/* $TOG: PrintS.c /main/38 1997/06/18 17:48:54 samborn $ */ /* * (c) Copyright 1996 Digital Equipment Corporation. * (c) Copyright 1996 Hewlett-Packard Company. * (c) Copyright 1996 International Business Machines Corp. * (c) Copyright 1996 Sun Microsystems, Inc. * (c) Copyright 1996 Novell, Inc. * (c) Copyright 1996 FUJITSU LIMITED. * (c) Copyright 1996 Hitachi. */ #include "XmI.h" #include #include "ImageCachI.h" #include "SyntheticI.h" /******** Static Function Declarations ********/ static void ClassPartInitialize( WidgetClass wc) ; static void ClassInitialize( void ) ; static void Initialize( Widget requested_widget, Widget new_widget, ArgList args, Cardinal *num_args) ; static Boolean SetValues( Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args) ; static void Destroy( Widget w) ; static void PrintNotifyHandler( Widget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch); static void ResourcesUpdate( Widget w, XPContext pcontext, Dimension * pwidth, Dimension * pheight); static void AttributesNotifyHandler( Widget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch); static void SelectXpEvents ( Widget widget, int *event_types, XtPointer *select_data, int count, XtPointer client_data); static void PrintToFileProc(Display * dpy, XPContext context, unsigned char *data, unsigned int data_len, XPointer client_data); static void FinishProc(Display *display, XPContext context, XPGetDocStatus status, XPointer client_data); static void PDMPhase2Handler(Widget w, XtPointer data, XEvent *event, Boolean *cont); static void PDMSelectionProc (Widget w, XtPointer client_data, Atom *selection, Atom *type, XtPointer value, unsigned long *length, int *format); static Boolean PrintDispatchEvent (XEvent *event); static void GetFromTable (Display* pdpy, XPContext context, Widget * widget); static void DeleteFromTable (XPContext context, Widget widget); static void AddToTable (XPContext context, Widget widget); #define Offset(x) (XtOffsetOf(XmPrintShellRec, print.x)) static XtResource resources[] = { { XmNallowShellResize, XmCAllowShellResize, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmPrintShellRec, shell.allow_shell_resize), XtRImmediate, (XtPointer)False, }, { XmNminX, XmCMinX, XmRHorizontalDimension, sizeof (Dimension), Offset(min_x), XmRImmediate, (XtPointer) 0, }, { XmNminY, XmCMinY, XmRVerticalDimension, sizeof (Dimension), Offset(min_y), XmRImmediate, (XtPointer) 0, }, { XmNmaxX, XmCMaxX, XmRHorizontalDimension, sizeof (Dimension), Offset(max_x), XmRImmediate, (XtPointer) 0, }, { XmNmaxY, XmCMaxY, XmRVerticalDimension, sizeof (Dimension), Offset(max_y), XmRImmediate, (XtPointer) 0, }, { XmNdefaultPixmapResolution, XmCDefaultPixmapResolution, XmRShort, sizeof(unsigned short), Offset(default_pixmap_resolution), XmRImmediate, (XtPointer)100, }, { XmNstartJobCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(start_job_callback), XmRImmediate, (XtPointer)NULL, }, { XmNendJobCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(end_job_callback), XmRImmediate, (XtPointer)NULL, }, { XmNpageSetupCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(page_setup_callback), XmRImmediate, (XtPointer)NULL, }, { XmNpdmNotificationCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), Offset(pdm_notification_callback), XmRImmediate, (XtPointer)NULL, }, }; /** only getvalues is supported on these, not setvalues hook therefore */ static XmSyntheticResource syn_resources[] = { { XmNminX, sizeof(Dimension), Offset(min_x), XmeFromHorizontalPixels,NULL, }, { XmNminY, sizeof(Dimension), Offset(min_y), XmeFromVerticalPixels,NULL, }, { XmNmaxX, sizeof(Dimension), Offset(max_x), XmeFromHorizontalPixels,NULL, }, { XmNmaxY, sizeof(Dimension), Offset(max_y), XmeFromVerticalPixels,NULL, }, }; #undef Offset externaldef(xmprintshellclassrec) XmPrintShellClassRec xmPrintShellClassRec = { { (WidgetClass) &applicationShellClassRec, /* superclass */ "XmPrintShell", /* class_name */ sizeof(XmPrintShellRec), /* size */ ClassInitialize, /* Class Initializer */ ClassPartInitialize, /* class_part_init */ FALSE, /* Class init'ed ? */ Initialize, /* initialize */ NULL, /* initialize_notify */ XtInheritRealize, /* realize */ NULL, /* actions */ 0, /* num_actions */ resources, /* resources */ XtNumber(resources), /* resource_count */ NULLQUARK, /* xrm_class */ FALSE, /* compress_motion */ XtExposeCompressSeries, /* compress_exposure */ FALSE, /* compress_enterleave */ FALSE, /* visible_interest */ Destroy, /* destroy */ XtInheritResize, /* resize */ (XtExposeProc)NULL, /* expose */ SetValues, /* set_values */ (XtArgsFunc)NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ _XmPrintShellGetValuesHook, /* get_values_hook */ (XtAcceptFocusProc)NULL, /* accept_focus */ XtVersion, /* intrinsics version */ NULL, /* callback offsets */ XtInheritTranslations, /* tm_table */ XtInheritQueryGeometry, /* query_geometry */ (XtStringProc)NULL, /* display_accelerator */ (XtPointer)NULL, /* extension */ }, { /* composite class record */ XtInheritGeometryManager, /* geometry_manager */ XtInheritChangeManaged, /* change_managed */ XtInheritInsertChild, /* insert_child */ XtInheritDeleteChild, /* from the shell */ NULL, /* extension record */ }, { /* shell class record */ NULL, /* extension record */ }, { /* wm shell class record */ NULL, /* extension record */ }, { /* vendor shell class record */ NULL, /* extension record */ }, { /* toplevelclass record */ NULL, /* extension record */ }, { /* appShell record */ NULL, /* extension record */ }, { /* PrintShell class */ syn_resources, /* syn_resources */ XtNumber(syn_resources), /* num_syn_resources */ NULL, /* extension */ }, }; externaldef(xmprintshellclass) WidgetClass xmPrintShellWidgetClass = (WidgetClass) (&xmPrintShellClassRec); static XContext PrintContextToWidget = 0; /* global because used in ResInd.c to find out about resolution */ XContext _XmPrintScreenToShellContext = 0; Cardinal _XmPrintShellCounter = 0 ; /************************************************************************ * * ClassInitialize * ************************************************************************/ static void ClassInitialize( void ) { if (PrintContextToWidget == 0) PrintContextToWidget = XUniqueContext(); if (_XmPrintScreenToShellContext == 0) _XmPrintScreenToShellContext = XUniqueContext(); } /************************************************************************ * * ClassPartInitialize * ************************************************************************/ static void ClassPartInitialize( WidgetClass wc ) { _XmFastSubclassInit(wc, XmPRINT_SHELL_BIT); } static void PrintNotifyHandler( Widget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch) { XPPrintEvent * xpev = (XPPrintEvent *) event ; XmPrintShellWidget print_shell = (XmPrintShellWidget) w ; XmPrintShellCallbackStruct pr_cbs ; /* don't interfere with the app if it hasn't set any callback. (since we set the handler all the time) It is probably using it's own handler doing start page, etc */ if (!print_shell->print.start_job_callback && !print_shell->print.page_setup_callback && !print_shell->print.end_job_callback) return ; pr_cbs.event = event; pr_cbs.context = xpev->context ; switch (xpev->detail) { case XPStartJobNotify : print_shell->print.last_page = False ; pr_cbs.reason = XmCR_START_JOB ; pr_cbs.last_page = False ; XtCallCallbackList (w, print_shell->print.start_job_callback, &pr_cbs); /* fall thru : call both callbacks if present */ case XPEndPageNotify : /* if last end page, no need to call pagesetup again */ if (!print_shell->print.last_page) { pr_cbs.reason = XmCR_PAGE_SETUP; pr_cbs.last_page = False ; XtCallCallbackList (w, print_shell->print.page_setup_callback, &pr_cbs); /* on return from pageSetup, save whether or not that was the last page set up by the app */ print_shell->print.last_page = pr_cbs.last_page; /* only start a page if a callback is there */ if (print_shell->print.page_setup_callback) { XpStartPage(XtDisplay(w), XtWindow(w)); } } break ; case XPStartPageNotify : if (print_shell->print.page_setup_callback) { XpEndPage(XtDisplay(w)); if (print_shell->print.last_page) XpEndJob(XtDisplay(w)); } break ; case XPEndJobNotify : pr_cbs.reason = XmCR_PAGE_SETUP; pr_cbs.last_page = True ; XtCallCallbackList (w, print_shell->print.page_setup_callback, &pr_cbs); pr_cbs.reason = XmCR_END_JOB ; XtCallCallbackList (w, print_shell->print.end_job_callback, &pr_cbs); break ; } } static void ResourcesUpdate(Widget w, XPContext pcontext, Dimension * pwidth, Dimension * pheight) { XmPrintShellWidget print_shell = (XmPrintShellWidget) w ; String string_resolution ; XRectangle imageable_area ; /*** Get the resolution so that unit Type conversion works */ string_resolution = XpGetOneAttribute(XtDisplay(w), pcontext, XPDocAttr, "default-printer-resolution") ; print_shell->print.print_resolution = atoi(string_resolution); XFree(string_resolution); if (!print_shell->print.print_resolution) /* compute from the X screen resolution */ print_shell->print.print_resolution = (254 * WidthOfScreen(XtScreen(w)) + 5 * WidthMMOfScreen(XtScreen(w))) / (10 * WidthMMOfScreen(XtScreen(w))) ; /* get our size from the print server now */ XpGetPageDimensions(XtDisplay(w), pcontext, pwidth, pheight, &imageable_area); print_shell->print.min_x = imageable_area.x ; print_shell->print.min_y = imageable_area.y ; print_shell->print.max_x = imageable_area.x + imageable_area.width ; print_shell->print.max_y = imageable_area.y + imageable_area.height ; } static void AttributesNotifyHandler( Widget w, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch) { XPAttributeEvent * xatrev = (XPAttributeEvent *) event ; XmPrintShellWidget print_shell = (XmPrintShellWidget) w ; Dimension width = w->core.width, height = w->core.height; /* For now, blindly update resolution and sizes */ ResourcesUpdate(w, xatrev->context, &width, &height); XtResizeWidget(w, width, height, w->core.border_width); } static void SelectXpEvents ( Widget widget, int *event_types, XtPointer *select_data, int count, XtPointer client_data) { XpSelectInput(XtDisplay(widget), XpGetContext(XtDisplay(widget)), XPPrintMask|XPAttributeMask); } /***************************** Maintain a XPContext to widget binding for use in event dispatch to print shell logic. Limitation is only one shell per XPContext in this implementation. Could improve to dispatch to all widget in this context later, but not sure if supported by Xp itself. ******************************/ static void GetFromTable (Display* pdpy, XPContext context, Widget * widget) { XFindContext(pdpy, (XID)context, PrintContextToWidget, (XPointer *) widget); } static void DeleteFromTable (XPContext context, Widget widget) { XDeleteContext(XtDisplay(widget), (XID)context, PrintContextToWidget); } static void AddToTable (XPContext context, Widget widget) { XSaveContext(XtDisplay(widget), (XID)context, PrintContextToWidget, (XPointer) widget); } /*****************************/ static Boolean PrintDispatchEvent (XEvent *event) { XPPrintEvent * xpev = (XPPrintEvent *) event ; Widget widget = NULL ; /* I only have a context, not a window, so I can't use XtWindowToWidget.. I have to maintain my own table widget/context. Limitation: one context to one widget for now */ GetFromTable(xpev->display, xpev->context, &widget); /* If ever supported, need to loop thru a list, if several print_shell have been created under the same XPContext, and dispatch the event to all of them */ if (!widget) return False ; /* spec says to call filter first, even though in my case, I shouldn't have any IM around... */ if (XFilterEvent(event, XtWindow(widget))) return True ; return XtDispatchEventToWidget(widget, event); } /************************************************************************ * * Initialize * ************************************************************************/ static void Initialize( Widget req_widget, Widget new_widget, ArgList args, Cardinal *num_args ) { int event_base_return, error_base_return ; XmPrintShellWidget print_shell = (XmPrintShellWidget) new_widget ; XPContext pcontext ; Screen * pscreen ; _XmProcessLock(); /* mark the screen of this print shell in this context */ XSaveContext(XtDisplay(new_widget), (XID)XtScreen(new_widget), _XmPrintScreenToShellContext, (XPointer) new_widget); /* also maintain a counter of all shell */ _XmPrintShellCounter ++ ; _XmProcessUnlock(); print_shell->print.xp_connected = False ; print_shell->print.print_resolution = 100 ; /*** first check if the Print extension is present at all */ if (!XpQueryExtension (XtDisplay(new_widget), &event_base_return, &error_base_return)) { return ; } /* need to check that the print context is set for the screen of this print shell (i.e. it's a print screen, not just a screen on a display that support printing and for which a context was establish on a different screen - which can be common in preview case */ pcontext = XpGetContext(XtDisplay(new_widget)); if (!pcontext || XpGetScreenOfContext(XtDisplay(new_widget),pcontext) != XtScreen(new_widget)) { return ; } print_shell->print.xp_connected = True ; /*** add an element to a widget/XPContext table, used in the event dispatch mechanism */ AddToTable(pcontext, new_widget); /*** add extension event Handler for Start/End Job/Page Notify */ XtInsertEventTypeHandler(new_widget, event_base_return + XPPrintNotify, (XtPointer)XPPrintMask, PrintNotifyHandler, NULL, XtListTail); /*** also add extension event Handler for tracking attributes change */ XtInsertEventTypeHandler(new_widget, event_base_return + XPAttributeNotify, (XtPointer)XPAttributeMask, AttributesNotifyHandler, NULL, XtListTail); /* always register the extension selector, and the event dispatcher, it will override itself accordingly and works ok for different display connection */ XtRegisterExtensionSelector(XtDisplay(new_widget), event_base_return + XPPrintNotify, event_base_return + XPAttributeNotify, SelectXpEvents, NULL); (void) XtSetEventDispatcher(XtDisplay(new_widget), event_base_return + XPPrintNotify, PrintDispatchEvent); (void) XtSetEventDispatcher(XtDisplay(new_widget), event_base_return + XPAttributeNotify, PrintDispatchEvent); /* go and get resolution and initial sizes */ ResourcesUpdate(new_widget, pcontext, &(new_widget->core.width), &(new_widget->core.height)); } /************************************************************************ * * SetValues * ************************************************************************/ /*ARGSUSED*/ static Boolean SetValues( Widget current, Widget request, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num_args ) /* unused */ { XmPrintShellWidget cur_print_shell = (XmPrintShellWidget) current ; XmPrintShellWidget new_print_shell = (XmPrintShellWidget) new_w ; if (!new_print_shell->print.xp_connected) return False ; /* need to check for changes in getvalues only resources . need to put out a warning */ if (cur_print_shell->print.min_x != new_print_shell->print.min_x) new_print_shell->print.min_x = cur_print_shell->print.min_x ; if (cur_print_shell->print.min_y != new_print_shell->print.min_y) new_print_shell->print.min_y = cur_print_shell->print.min_y ; if (cur_print_shell->print.max_x != new_print_shell->print.max_x) new_print_shell->print.max_x = cur_print_shell->print.max_x ; if (cur_print_shell->print.max_y != new_print_shell->print.max_y) new_print_shell->print.max_y = cur_print_shell->print.max_y ; return False ; } /************************************************************************ * * Destroy * ************************************************************************/ /* ARGSUSED */ static void Destroy( Widget w ) { XmPrintShellWidget print_shell = (XmPrintShellWidget) w ; /* need to remove the pixmap from this shell: no sharing between diff shell and the same shell pointer id can come up next time */ _XmCleanPixmapCache (XtScreen(w), w); if (!print_shell->print.xp_connected) return ; /*** remove entry in the widget/XPContext table, used in the event dispatch mechanism */ DeleteFromTable(XpGetContext(XtDisplay(w)), w); _XmProcessLock(); /* unmark the screen of this print shell in this context */ XDeleteContext(XtDisplay(w), (XID)XtScreen(w), _XmPrintScreenToShellContext); /* also maintain a counter of all shells alive */ _XmPrintShellCounter -- ; _XmProcessUnlock(); } /************************************************************************ * * Public API * ************************************************************************/ /************************************************************************ * * XmPrintSetup * * add print display in app context and create the print shell * ************************************************************************/ Widget XmPrintSetup( Widget video_widget, Screen *print_screen, String print_shell_name, ArgList args, Cardinal num_args) { String video_name, video_class ; Widget pappshell ; Widget print_shell; Display *print_display = DisplayOfScreen(print_screen); /* get to the video app root shell */ while(!XtIsApplicationShell(video_widget)) video_widget = XtParent(video_widget); if (!video_widget) return NULL; XtGetApplicationNameAndClass(XtDisplay(video_widget), &video_name, &video_class); /* we want to be able to specify things like: dtpad.print*textFontList: somefont dtpad.print*background:white so we create a first shell unrealized and them a popup named "print". */ pappshell = XtVaAppCreateShell(video_name, video_class, applicationShellWidgetClass, print_display, XmNscreen, print_screen, NULL); /* then create the XmPrintShell */ print_shell = XtCreatePopupShell(print_shell_name, xmPrintShellWidgetClass, pappshell, args, num_args); /* Add callback to destroy application Shell parent. */ XtAddCallback(print_shell, XmNdestroyCallback, _XmDestroyParentCallback, (XtPointer) NULL) ; /* we're mapping/unmapping at start/end page time */ XtSetMappedWhenManaged(print_shell, False); /* realize the shell now, so that XmPrintPopupPDM works dy default */ XtRealizeWidget(print_shell); return print_shell ; } /************************************************************************ * * XmPrintToFile * ************************************************************************/ /* need to be able to remove the filename or write/close the file */ typedef struct { String file_name; FILE * file; int pipe; } FileDescRec ; typedef struct { Display *display; XPFinishProc finish_proc; XPointer client_data; int pipe; XtInputId input_id; } FileCallbackRec; static void PrintToFileProc(Display * dpy, XPContext context, unsigned char *data, unsigned int data_len, XPointer client_data) { FileDescRec * file_desc = (FileDescRec *) client_data ; /* write to the file */ fwrite(data, data_len, 1, file_desc->file); } static void FinishProc(Display *display, XPContext context, XPGetDocStatus status, XPointer client_data) { FileDescRec * file_desc = (FileDescRec *) client_data ; /* remove the file if not successfull */ if (status != XPGetDocFinished) remove(file_desc->file_name); else fclose(file_desc->file); /* write the status to the parent */ (void) write(file_desc->pipe, &status, sizeof(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 */ _exit(0); } static void FilePipeCB(XtPointer client_data, int *source, XtInputId *id) { FileCallbackRec *cb = (FileCallbackRec *) client_data; XPGetDocStatus status; /* read the status from the child */ (void) read(cb->pipe, &status, sizeof(XPGetDocStatus)); XtRemoveInput(cb->input_id); close(cb->pipe); if (cb->finish_proc) { (*cb->finish_proc)(cb->display, XpGetContext(cb->display), status, cb->client_data); } XtFree((char*)cb); } static void ChildPrintToFile(String display_name, XPContext pcontext, FILE *file, char *file_name, int pipe, String application_name, String application_class) { FileDescRec *file_desc; XtAppContext app_context; int argc = 0; String argv[] = { NULL }; Display *display; file_desc = (FileDescRec *) XtMalloc(sizeof(FileDescRec)); file_desc->file_name = XtNewString(file_name); file_desc->file = file; file_desc->pipe = pipe; app_context = XtCreateApplicationContext(); if ((display = XtOpenDisplay(app_context, display_name, application_name, application_class, NULL, 0, &argc, argv)) == NULL) { _exit(1); } XpGetDocumentData(display, pcontext, PrintToFileProc, FinishProc, (XPointer) file_desc); XtAppMainLoop(app_context); _exit(0); } XtEnum XmPrintToFile(Display *pdpy, char *file_name, XPFinishProc finish_proc, XPointer client_data) { FileCallbackRec *callback; int pid; XPContext pcontext ; String application_name, application_class, display_name; FILE *file; int filedes[2]; /* make sure we can open the file for writing */ if ((file = fopen(file_name, "w")) == NULL) { return False; } if ((pipe(filedes)) == -1) { return False; } /* its important to flush before we fork, to make sure that the XpStartJob gets through first in the parent */ XFlush(pdpy); XtGetApplicationNameAndClass(pdpy, &application_name, &application_class); display_name = XDisplayString(pdpy) ; pcontext = XpGetContext(pdpy) ; pid = fork(); if (pid == 0) { ChildPrintToFile(display_name, pcontext, file, file_name, filedes[1], application_name, application_class); } else if (pid < 0) { return False; } /* we are in the parent */ fclose(file); close(filedes[1]); /* allocate the space for a callback */ callback = (FileCallbackRec *) XtMalloc(sizeof(FileCallbackRec)); callback->display = pdpy; callback->pipe = filedes[0]; callback->finish_proc = finish_proc; callback->client_data = client_data; /* notification that the child has completed */ callback->input_id = XtAppAddInput(XtDisplayToApplicationContext(pdpy), callback->pipe, (XtPointer)XtInputReadMask, FilePipeCB, callback); return True; } /************************************************************* ** XmPrintPopupPDM code *************************************************************/ static void PDMPhase2Handler(Widget w, XtPointer data, XEvent *event, Boolean *cont) { enum { XmAPDM_REPLY, XmAPDM_EXIT_OK, XmAPDM_EXIT_ERROR, XmAPDM_EXIT_CANCEL, NUM_ATOMS }; static char *atom_names[] = { XmIPDM_REPLY, XmIPDM_EXIT_OK, XmIPDM_EXIT_ERROR, XmIPDM_EXIT_CANCEL }; XmPrintShellWidget print_shell = (XmPrintShellWidget) w ; XmPrintShellCallbackStruct pr_cbs ; XClientMessageEvent * xevent = (XClientMessageEvent *) event; Atom atoms[XtNumber(atom_names)]; assert(XtNumber(atom_names) == NUM_ATOMS); XInternAtoms(XtDisplay(print_shell), atom_names, XtNumber(atom_names), False, atoms); if (xevent->type == ClientMessage && xevent->message_type == atoms[XmAPDM_REPLY]) { /* check for the exit status of the PDM */ if (xevent->data.l[0] == atoms[XmAPDM_EXIT_OK]) pr_cbs.reason = XmCR_PDM_OK ; else if (xevent->data.l[0] == atoms[XmAPDM_EXIT_CANCEL]) pr_cbs.reason = XmCR_PDM_CANCEL ; else if (xevent->data.l[0] == atoms[XmAPDM_EXIT_ERROR]) pr_cbs.reason = XmCR_PDM_EXIT_ERROR ; /* some error message might have been logged */ XtCallCallbackList (w, print_shell->print.pdm_notification_callback, &pr_cbs); } /* remove me */ XtAddEventHandler(w, (EventMask) 0, True, PDMPhase2Handler, NULL); } typedef struct { Atom pdm_selection ; XmPrintShellWidget print_shell ; Widget transient_for_video_shell ; Window transient_for_input_only_window; } PDMSelectData ; static void PDMSelectionProc (Widget w, XtPointer client_data, Atom *selection, Atom *type, XtPointer value, unsigned long *length, int *format) { enum { XmAPDM_START_OK, XmAPDM_START_ERROR, XmAPDM_START_VXAUTH, XmAPDM_START_PXAUTH, NUM_ATOMS }; static char *atom_names[] = { XmIPDM_START_OK, XmIPDM_START_ERROR, XmIPDM_START_VXAUTH, XmIPDM_START_PXAUTH }; XmPrintShellCallbackStruct pr_cbs ; PDMSelectData * pdm_select_data = (PDMSelectData *) client_data ; Atom atoms[XtNumber(atom_names)]; assert(XtNumber(atom_names) == NUM_ATOMS); XInternAtoms(XtDisplay(pdm_select_data->print_shell), atom_names, XtNumber(atom_names), False, atoms); /* set back the video shell widget usable */ XDestroyWindow(XtDisplay(pdm_select_data->transient_for_video_shell), pdm_select_data->transient_for_input_only_window); /* look at value and decide if success or failure */ if (!value) { pr_cbs.reason = XmCR_PDM_NONE ; pr_cbs.detail = (XtPointer) pdm_select_data->pdm_selection ; } else { /* look if value is PDM_START_OK, or PDM_START_VXAUTH, etc */ if (*(Atom *)value == atoms[XmAPDM_START_OK]) pr_cbs.reason = XmCR_PDM_UP ; else if (*(Atom *)value == atoms[XmAPDM_START_ERROR]) pr_cbs.reason = XmCR_PDM_START_ERROR ; else if (*(Atom *)value == atoms[XmAPDM_START_VXAUTH]) pr_cbs.reason = XmCR_PDM_START_VXAUTH ; else if (*(Atom *)value == atoms[XmAPDM_START_PXAUTH]) pr_cbs.reason = XmCR_PDM_START_PXAUTH ; /* if PDM is up, install a handler for phase 2 */ if (pr_cbs.reason == XmCR_PDM_UP) { XtAddEventHandler((Widget)pdm_select_data->print_shell, (EventMask) 0, True, /* ClientMessage are non maskable */ PDMPhase2Handler, NULL); } } XtCallCallbackList ((Widget)pdm_select_data->print_shell, pdm_select_data->print_shell ->print.pdm_notification_callback, &pr_cbs); XtFree((char*)pdm_select_data); } XtEnum XmPrintPopupPDM(Widget print_shell, Widget transient_for_video_shell) { Atom pdm_selection; Atom type; unsigned char * value; int length; int format; Atom PDM_START ; Display * display_used ; PDMSelectData * pdm_select_data ; Widget widget_for_selection ; XtAppContext app; unsigned long old_timeout; /* get parameter for PDM_START from libXp ask conversion using XtSetSelectionParameters, and then call XtGetSelectionValue, which registers a XtSelectionCallbackProc that will wait for failure (no pdm owner, or timeout) or success. Phase 2 of the pdm (clientmessage) will be handled by a event handler set up from the selection callback on success */ if (!XpGetPdmStartParams (XtDisplay(print_shell), XtWindow(print_shell), XpGetContext(XtDisplay(print_shell)), XtDisplay(transient_for_video_shell), XtWindow(transient_for_video_shell), &display_used, &pdm_selection, &type, &format, &value, &length)) return XmPDM_NOTIFY_FAIL; /* only support XPDMDISPLAY = "print" or "video" */ if (display_used == XtDisplay(print_shell)) widget_for_selection = print_shell ; else if (display_used == XtDisplay(transient_for_video_shell)) widget_for_selection = transient_for_video_shell ; else return XmPDM_NOTIFY_FAIL ; XtSetSelectionParameters(widget_for_selection, pdm_selection, type, (XtPointer)value, length, format); XFree(value); pdm_select_data = (PDMSelectData *) XtMalloc(sizeof(PDMSelectData)); pdm_select_data->pdm_selection = pdm_selection ; pdm_select_data->transient_for_video_shell = transient_for_video_shell ; pdm_select_data->print_shell = (XmPrintShellWidget) print_shell ; /* need this one in all cases */ PDM_START = XInternAtom(XtDisplay(widget_for_selection), XmIPDM_START, False); app = XtWidgetToApplicationContext(widget_for_selection); /* twenty minutes */ #define REALLY_LONG_TIMEOUT (2 * 60 * 1000) _XmAppLock(app); old_timeout = XtAppGetSelectionTimeout(app); XtAppSetSelectionTimeout(app, REALLY_LONG_TIMEOUT); XtGetSelectionValue(widget_for_selection, pdm_selection, PDM_START, PDMSelectionProc, (XtPointer)pdm_select_data, XtLastTimestampProcessed( XtDisplay(widget_for_selection))); XtAppSetSelectionTimeout(app, old_timeout); _XmAppUnlock(app); /* put up a InputOnly window on top of the dialog, so that the end-user cannot muck around with the print setup dialog hile the PDM is trying to come up. This is removed in PDMSelectionProc */ pdm_select_data->transient_for_input_only_window = XCreateWindow(XtDisplay(transient_for_video_shell), XtWindow(transient_for_video_shell), 0, 0, XtWidth(transient_for_video_shell), XtHeight(transient_for_video_shell), 0, CopyFromParent, InputOnly, CopyFromParent, 0, NULL); XMapRaised(XtDisplay(transient_for_video_shell), pdm_select_data->transient_for_input_only_window); return XmPDM_NOTIFY_SUCCESS ; } /************************************************************************ * * XmRedisplayWidget * * Call the expose method of the passed widget with a fake * event corresponding to its entire area. * ************************************************************************/ void XmRedisplayWidget(Widget widget) { XExposeEvent xev ; Region region ; xev.type = Expose ; /* is this better than 0 ? shouldn't make much difference unless the expose method is very tricky... */ xev.serial = LastKnownRequestProcessed(XtDisplay(widget)) ; xev.send_event = False ; xev.display = XtDisplay(widget); xev.window = XtWindowOfObject(widget); /* work with gadget too */ xev.x = 0 ; xev.y = 0 ; xev.width = widget->core.width ; xev.height = widget->core.height ; xev.count = 0 ; region = XCreateRegion(); XtAddExposureToRegion((XEvent*)&xev, region); if (widget->core.widget_class->core_class.expose) (*(widget->core.widget_class->core_class.expose)) (widget, (XEvent*)&xev, region); XDestroyRegion(region); }