diff options
Diffstat (limited to 'nx-X11/lib/XprintUtil/xprintutil_printtofile.c')
-rw-r--r-- | nx-X11/lib/XprintUtil/xprintutil_printtofile.c | 498 |
1 files changed, 0 insertions, 498 deletions
diff --git a/nx-X11/lib/XprintUtil/xprintutil_printtofile.c b/nx-X11/lib/XprintUtil/xprintutil_printtofile.c deleted file mode 100644 index 331e7ad5b..000000000 --- a/nx-X11/lib/XprintUtil/xprintutil_printtofile.c +++ /dev/null @@ -1,498 +0,0 @@ -/****************************************************************************** - ****************************************************************************** - ** - ** (c) Copyright 2001-2004 Roland Mainz <roland.mainz@nrubsig.org> - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy - ** of this software and associated documentation files (the "Software"), to deal - ** in the Software without restriction, including without limitation the rights - ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - ** copies of the Software, and to permit persons to whom the Software is - ** furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in - ** all copies or substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - ** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - ** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ** Except as contained in this notice, the names of the copyright holders shall - ** not be used in advertising or otherwise to promote the sale, use or other - ** dealings in this Software without prior written authorization from said - ** copyright holders. - ** - ****************************************************************************** - *****************************************************************************/ - -#include "xprintutil.h" - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> -#include <errno.h> -#ifdef XPU_USE_THREADS -#include <time.h> -#ifdef XPU_USE_NSPR -#include <prthread.h> -#else -#include <pthread.h> -#endif /* XPU_USE_NSPR */ -#endif /* XPU_USE_THREADS */ -#include <unistd.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> - -/* local prototypes */ -#ifdef DEBUG -static void PrintXPGetDocStatus( XPGetDocStatus status ); -#endif -static Bool XNextEventTimeout( Display *display, XEvent *event_return, struct timeval *timeout ); -static void *XpuPrintToFile( Display *pdpy, XPContext pcontext, const char *filename ); -static void MyPrintToFileProc( Display *pdpy, XPContext pcontext, unsigned char *data, unsigned int data_len, XPointer client_data ); -static void MyFinishProc( Display *pdpy, XPContext pcontext, XPGetDocStatus status, XPointer client_data ); -#ifdef XPU_USE_NSPR -static void PrintToFile_Consumer( void *handle ); -#else -static void *PrintToFile_Consumer( void *handle ); -#endif - -void XpuStartJobToSpooler(Display *pdpy) -{ - XpStartJob(pdpy, XPSpool); -} - -void *XpuStartJobToFile( Display *pdpy, XPContext pcontext, const char *filename ) -{ - void *handle; - - XpStartJob(pdpy, XPGetData); - handle = XpuPrintToFile(pdpy, pcontext, filename); - - if (!handle) - { - /* Cancel the print job and discard all events... */ - XpCancelJob(pdpy, True); - } - - return(handle); -} - -#ifdef DEBUG -/* DEBUG: Print XPGetDocStatus */ -static -void PrintXPGetDocStatus( XPGetDocStatus status ) -{ - switch(status) - { - case XPGetDocFinished: puts("PrintXPGetDocStatus: XPGetDocFinished"); break; - case XPGetDocSecondConsumer: puts("PrintXPGetDocStatus: XPGetDocSecondConsumer"); break; - case XPGetDocError: puts("PrintXPGetDocStatus: XPGetDocError"); break; - default: puts("PrintXPGetDocStatus: <unknown value"); break; - } -} -#endif /* DEBUG */ - - -/* XNextEvent() with timeout */ -static -Bool XNextEventTimeout( Display *display, XEvent *event_return, struct timeval *timeout ) -{ - int res; - fd_set readfds; - int display_fd = XConnectionNumber(display); - - /* small shortcut... */ - if( timeout == NULL ) - { - XNextEvent(display, event_return); - return(True); - } - - FD_ZERO(&readfds); - FD_SET(display_fd, &readfds); - - /* Note/bug: In the case of internal X events (like used to trigger callbacks - * registered by XpGetDocumentData()&co.) select() will return with "new info" - * - but XNextEvent() below processes these _internal_ events silently - and - * will block if there are no other non-internal events. - * The workaround here is to check with XEventsQueued() if there are non-internal - * events queued - if not select() will be called again - unfortunately we use - * the old timeout here instead of the "remaining" time... (this only would hurt - * if the timeout would be really long - but for current use with values below - * 1/2 secs it does not hurt... =:-) - */ - while( XEventsQueued(display, QueuedAfterFlush) == 0 ) - { - res = select(display_fd+1, &readfds, NULL, NULL, timeout); - - switch(res) - { - case -1: /* select() error - should not happen */ - perror("XNextEventTimeout: select() failure"); - return(False); - case 0: /* timeout */ - return(False); - } - } - - XNextEvent(display, event_return); - return(True); -} - - -#ifdef XPU_USE_THREADS -/** - ** XpuPrintToFile() - threaded version - ** Create consumer thread which creates it's own display connection to print server - ** (a 2nd display connection/thread is required to avoid deadlocks within Xlib), - ** registers (Xlib-internal) consumer callback (via XpGetDocumentData(3Xp)) and - ** processes/eats all incoming events via MyPrintToFileProc(). A final call to - ** MyPrintToFileProc() cleans-up all stuff and sets the "done" flag. - ** Note that these callbacks are called directly by Xlib while waiting for events in - ** XNextEvent() because XpGetDocumentData() registeres them as "internal" callbacks, - ** e.g. XNextEvent() does _not_ return before/after processing these events !! - ** - ** Usage: - ** XpStartJob(pdpy, XPGetData); - ** handle = XpuPrintToFile(pdpy, pcontext, "myfile"); - ** // render something - ** XpEndJob(); // or XpCancelJob() - ** status = XpuWaitForPrintFileChild(handle); - ** - */ - -typedef struct -{ -#ifdef XPU_USE_NSPR - PRThread *prthread; -#else - pthread_t tid; -#endif - char *displayname; - Display *pdpy; - Display *parent_pdpy; - XPContext pcontext; - const char *file_name; - FILE *file; - XPGetDocStatus status; - Bool done; -} MyPrintFileData; - - -static -void *XpuPrintToFile( Display *pdpy, XPContext pcontext, const char *filename ) -{ - MyPrintFileData *mpfd; /* warning: shared between threads !! */ - - if( (mpfd = malloc(sizeof(MyPrintFileData))) == NULL ) - return(NULL); - - mpfd->parent_pdpy = pdpy; - mpfd->displayname = XDisplayString(pdpy); - mpfd->pdpy = NULL; - mpfd->pcontext = pcontext; - mpfd->file_name = filename; - mpfd->file = NULL; - mpfd->status = XPGetDocError; - - /* make sure we can open the file for writing */ - if( (mpfd->file = fopen(mpfd->file_name, "w")) == NULL ) - { - /* fopen() error */ - free(mpfd); - return(NULL); - } - - /* its important to flush before we start the consumer thread, - * to make sure that the XpStartJob gets through first in the parent - */ - XFlush(pdpy); -#ifdef XPU_USE_NSPR - if( (mpfd->prthread = PR_CreateThread(PR_SYSTEM_THREAD, PrintToFile_Consumer, mpfd, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0)) == NULL ) -#else - if( pthread_create(&(mpfd->tid), NULL, PrintToFile_Consumer, mpfd) != 0 ) -#endif - { - /* pthread_create() error */ - fclose(mpfd->file); - free(mpfd); - return(NULL); - } - - /* we're still in the parent */ - XPU_DEBUG_ONLY(printf("### parent started consumer thread.\n" )); - return(mpfd); -} - - -XPGetDocStatus XpuWaitForPrintFileChild( void *handle ) -{ - MyPrintFileData *mpfd = (MyPrintFileData *)handle; - void *res; - XPGetDocStatus status; - - /* Flush data a last time to make sure we send all data to Xprt and that - * the Xlib internal hooks have called a last time */ - XFlush(mpfd->parent_pdpy); - -#ifdef XPU_USE_NSPR - if( PR_JoinThread(mpfd->prthread) != PR_SUCCESS ) - perror("XpuWaitForPrintFileChild: PR_JoinThread() failure"); /* fixme(later): use NSPR error handling calls... */ -#else - if( XPU_TRACE(pthread_join(mpfd->tid, &res)) != 0 ) - perror("XpuWaitForPrintFileChild: pthread_join() failure"); -#endif - - status = mpfd->status; - free(handle); - - XPU_DEBUG_ONLY(PrintXPGetDocStatus(status)); - return(status); -} - -#else /* XPU_USE_THREADS */ -/** - ** XpuPrintToFile() - fork() version - ** Create consumer thread which creates it's own display connection to print server - ** (a 2nd display connection/process is required to avoid deadlocks within Xlib), - ** registers (Xlib-internal) consumer callback (via XpGetDocumentData(3Xp)) and - ** processes/eats all incoming events via MyPrintToFileProc(). A final call to - ** MyPrintToFileProc() cleans-up all stuff and sets the "done" flag. - ** Note that these callbacks are called directly by Xlib while waiting for events in - ** XNextEvent() because XpGetDocumentData() registeres them as "internal" callbacks, - ** e.g. XNextEvent() does _not_ return before/after processing these events !! - ** - ** Usage: - ** XpStartJob(pdpy, XPGetData); - ** handle = XpuPrintToFile(pdpy, pcontext, "myfile"); - ** // render something - ** XpEndJob(); // or XpCancelJob() - ** status = XpuWaitForPrintFileChild(handle); - ** - */ -typedef struct -{ - pid_t pid; - int pipe[2]; /* child-->parent communication pipe */ - const char *displayname; - Display *pdpy; - Display *parent_pdpy; - XPContext pcontext; - const char *file_name; - FILE *file; - XPGetDocStatus status; - Bool done; -} MyPrintFileData; - - -static -void *XpuPrintToFile( Display *pdpy, XPContext pcontext, const char *filename ) -{ - MyPrintFileData *mpfd; - - if( (mpfd = (MyPrintFileData *)malloc(sizeof(MyPrintFileData))) == NULL ) - return(NULL); - - /* create pipe */ - if( pipe(mpfd->pipe) == -1 ) - { - /* this should never happen, but... */ - perror("XpuPrintToFile: cannot create pipe"); - free(mpfd); - return(NULL); - } - - mpfd->parent_pdpy = pdpy; - mpfd->displayname = XDisplayString(pdpy); - mpfd->pcontext = pcontext; - mpfd->file_name = filename; - mpfd->file = NULL; - mpfd->status = XPGetDocError; - - /* make sure we can open the file for writing */ - if( (mpfd->file = fopen(mpfd->file_name, "w")) == NULL ) - { - /* fopen() error */ - close(mpfd->pipe[1]); - close(mpfd->pipe[0]); - free(mpfd); - return(NULL); - } - - /* its important to flush before we fork, to make sure that the - * XpStartJob gets through first in the parent - */ - XFlush(pdpy); - - mpfd->pid = fork(); - - if( mpfd->pid == 0 ) - { - /* we're now in the fork()'ed child */ - PrintToFile_Consumer(mpfd); - } - else if( mpfd->pid < 0 ) - { - /* fork() error */ - close(mpfd->pipe[1]); - close(mpfd->pipe[0]); - fclose(mpfd->file); - free(mpfd); - return(NULL); - } - - /* we're still in the parent */ - XPU_DEBUG_ONLY(printf("### parent fork()'ed consumer child.\n")); - - /* child will write into file - we don't need it anymore here... :-) */ - fclose(mpfd->file); - close(mpfd->pipe[1]); - return(mpfd); -} - - -XPGetDocStatus XpuWaitForPrintFileChild( void *handle ) -{ - MyPrintFileData *mpfd = (MyPrintFileData *)handle; - int res; - XPGetDocStatus status = XPGetDocError; /* used when read() from pipe fails */ - - /* Flush data a last time to make sure we send all data to Xprt and that - * the Xlib internal hooks have called a last time */ - XFlush(mpfd->parent_pdpy); - - if( XPU_TRACE(waitpid(mpfd->pid, &res, 0)) == -1 ) - perror("XpuWaitForPrintFileChild: waitpid failure"); - - /* read the status from the child */ - if( read(mpfd->pipe[0], &status, sizeof(XPGetDocStatus)) != sizeof(XPGetDocStatus) ) - { - perror("XpuWaitForPrintFileChild: can't read XPGetDocStatus"); - } - close(mpfd->pipe[0]); - - free(handle); - - XPU_DEBUG_ONLY(PrintXPGetDocStatus(status)); - return(status); -} -#endif /* XPU_USE_THREADS */ - - -static -void MyPrintToFileProc( Display *pdpy, - XPContext pcontext, - unsigned char *data, - unsigned int data_len, - XPointer client_data ) -{ - MyPrintFileData *mpfd = (MyPrintFileData *)client_data; - - /* write to the file */ - XPU_TRACE_CHILD((void)fwrite(data, data_len, 1, mpfd->file)); /* what about error handling ? */ -} - - -static -void MyFinishProc( Display *pdpy, - XPContext pcontext, - XPGetDocStatus status, - XPointer client_data ) -{ - MyPrintFileData *mpfd = (MyPrintFileData *)client_data; - - /* remove the file if unsuccessful */ - if( status != XPGetDocFinished ) - { - XPU_DEBUG_ONLY(printf("MyFinishProc: error %d\n", (int)status)); - XPU_TRACE_CHILD(remove(mpfd->file_name)); - } - - XPU_TRACE_CHILD((void)fclose(mpfd->file)); /* what about error handling ? */ - - mpfd->status = status; - mpfd->done = True; -} - - -static -#ifdef XPU_USE_NSPR -void PrintToFile_Consumer( void *handle ) -#else -void *PrintToFile_Consumer( void *handle ) -#endif -{ - MyPrintFileData *mpfd = (MyPrintFileData *)handle; - XEvent dummy; - struct timeval timeout; - - timeout.tv_sec = 0; - timeout.tv_usec = 100000; /* 1/10 s */ - - XPU_DEBUG_ONLY(printf("### child running, getting data from '%s'.\n", mpfd->displayname)); - - /* we cannot reuse fork()'ed display handles - our child needs his own one */ - if( (mpfd->pdpy = XPU_TRACE_CHILD(XOpenDisplay(mpfd->displayname))) == NULL ) - { - perror("child cannot open display"); -#ifdef XPU_USE_NSPR - return; -#else - return(NULL); -#endif - } - - mpfd->done = False; - - /* register "consumer" callbacks */ - if( XPU_TRACE_CHILD(XpGetDocumentData(mpfd->pdpy, mpfd->pcontext, - MyPrintToFileProc, MyFinishProc, - (XPointer)mpfd)) == 0 ) - { - XPU_DEBUG_ONLY(printf("XpGetDocumentData cannot register callbacks\n")); -#ifdef XPU_USE_NSPR - return; -#else - return(NULL); -#endif - } - - /* loop forever - libXp has registered hidden event callbacks for the consumer - * callbacks - the finishCB will call set the "done" boolean after all... - */ - while( mpfd->done != True ) - { - XNextEventTimeout(mpfd->pdpy, &dummy, &timeout); - } - - XCloseDisplay(mpfd->pdpy); - -#ifdef XPU_USE_THREADS -#ifdef XPU_USE_NSPR - return; -#else - return(NULL); -#endif -#else - /* write the status to the parent */ - if( XPU_TRACE_CHILD(write(mpfd->pipe[1], &mpfd->status, sizeof(XPGetDocStatus))) != sizeof(XPGetDocStatus) ) - { - perror("PrintToFile_Consumer: can't write XPGetDocStatus"); - } - - /* we don't do any free's or close's, as we are just - * going to exit, in fact, get out without calling any C++ - * destructors, etc., as we don't want anything funny to happen - * to the parent - */ - XPU_TRACE_CHILD(_exit(EXIT_SUCCESS)); -#endif /* XPU_USE_THREADS */ -} - -/* EOF. */ |