1 /*
2  * Copyright (c) 2001-2004 Marcin Dalecki and others
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 
24 /*
25  * Implementation of the File selection dialogue for the Motif GUI.
26  */
27 
28 #include "xdvi-config.h"
29 #include "xdvi.h"
30 #include "sfSelFile.h"
31 
32 #include "dvi.h"
33 #include "string-utils.h"
34 #include "util.h"
35 #include "events.h"
36 #include "message-window.h"
37 #include "dvi-init.h" /* for dviErrFlagT */
38 #include "x_util.h"
39 
40 #if defined(MOTIF) /* entire file */
41 
42 #include <Xm/FileSB.h>
43 #include <Xm/Form.h>
44 #include <Xm/ToggleBG.h>
45 
46 #if HAVE_XKB_BELL_EXT
47 # include <X11/XKBlib.h>
48 # define XdviBell(display, window, percent)	\
49 	 XkbBell(display, window, percent, (Atom) None)
50 #else
51 # define XdviBell(display, window, percent)	XBell(display, percent)
52 #endif
53 
54 /* static Widget dialog = NULL; */
55 /* static char *browse_fname = NULL; */
56 
57 /*
58  * Process callback from Dialog cancel actions.
59  */
60 static void
cancel_callback(Widget w,XtPointer client_data,XtPointer call_data)61 cancel_callback(Widget w,
62 		XtPointer client_data,
63 		XtPointer call_data)
64 {
65     struct filesel_callback *callback = (struct filesel_callback *)client_data;
66 
67     UNUSED(w);
68     UNUSED(call_data);
69 #if 0
70     /* DON'T reset browse_fname, so that user gets the current
71        value as default next time when he cancels now */
72     if (callback->browse_fname != NULL)
73     {
74 	XtFree(callback->browse_fname);
75 	callback->browse_fname = NULL;
76     }
77 #endif
78 
79     XtUnmanageChild(callback->shell);
80     if (callback->exit_on_cancel) {
81 	exit(0);
82     }
83 }
84 
85 /*
86  * Process callback from Dialog actions.
87  */
88 
89 static void
accept_callback(Widget w,XtPointer client_data,XtPointer call_data)90 accept_callback(Widget w,
91 		XtPointer client_data,
92 		XtPointer call_data)
93 {
94     XmFileSelectionBoxCallbackStruct *fcb;
95     struct filesel_callback *callback;
96 
97     UNUSED(w);
98 
99     ASSERT(client_data != NULL, "struct filesel_callback pointer expected in client data");
100     callback = (struct filesel_callback *)client_data;
101 
102     /* get the filename from the file selection box */
103     fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
104     if (callback->browse_fname != NULL) {
105 	XtFree(callback->browse_fname);
106 	callback->browse_fname = NULL;
107     }
108     XmStringGetLtoR(fcb->value, G_charset, &callback->browse_fname);
109 
110     if (0 && callback->must_exist) {
111 	FILE *tmp_fp = XFOPEN(callback->browse_fname, "r");
112 	dviErrFlagT errflag = NO_ERROR;
113 	if (tmp_fp == NULL) {
114 	    popup_message(XtParent(callback->shell),
115 			  MSG_ERR, NULL, "Could not open %s: %s.\n",
116 			  callback->browse_fname, strerror(errno));
117 	    /* leave file selection box open */
118 	    return;
119 	}
120 	else if (!process_preamble(tmp_fp, &errflag)
121 		 || !find_postamble(tmp_fp, &errflag)
122 		 || !read_postamble(tmp_fp, &errflag, True
123 #if DELAYED_MKTEXPK
124 				    , False
125 #endif
126 				    )) {
127 	    popup_message(XtParent(callback->shell),
128 			  MSG_ERR, NULL, "Error opening %s:\n%s.",
129 			  callback->browse_fname, get_dvi_error(errflag));
130 	    fclose(tmp_fp);
131 	    /* leave file selection box open */
132 	    return;
133 	}
134 	else { /* file is OK */
135 	    fclose(tmp_fp);
136 	}
137     }
138 
139     /* success; close dialog, and call our callback */
140     XtUnmanageChild(callback->shell);
141     callback->func_ptr(callback->browse_fname, callback->data);
142 }
143 
144 static void
cb_open_new_window(Widget w,XtPointer client_data,XtPointer call_data)145 cb_open_new_window(Widget w, XtPointer client_data, XtPointer call_data)
146 {
147     UNUSED(client_data);
148     UNUSED(call_data);
149 
150     if (XmToggleButtonGadgetGetState(w))
151 	resource.filesel_open_new_window = True;
152     else
153 	resource.filesel_open_new_window = False;
154     store_preference(NULL, "fileselOpenNewWindow", "%d", resource.filesel_open_new_window);
155 }
156 
raise_file_selector(void)157 void raise_file_selector(void)
158 {
159     /* dummy */
160     return;
161 }
162 
163 void
XsraSelFilePopup(struct filesel_callback * callback)164 XsraSelFilePopup(struct filesel_callback *callback)
165 {
166     if (XtIsManaged(callback->shell)) {
167 	XdviBell(DISP, XtWindow(callback->shell), 10);
168 	XRaiseWindow(DISP, XtWindow(callback->shell));
169 	return;
170     }
171     else {
172 #define ARG_CNT 4
173 	XmString filemask = NULL;
174 	XmString directory = NULL;
175 	Arg args[ARG_CNT];
176 	int i = 0;
177 	char *path, *ptr;
178 
179 	/* only show files matching our mask */
180 	filemask = XmStringCreateLtoR((char *)callback->filemask, G_charset);
181 	XtSetArg(args[i], XmNpattern, filemask); i++;
182 
183 	/* set directory to last directory used */
184 	if (callback->browse_fname == NULL) {
185 	    ASSERT(callback->init_path != NULL, "callback->init_path mustn't be NULL!");
186 	    callback->browse_fname = xt_strdup(callback->init_path);
187 	}
188 	path = xstrdup(callback->browse_fname);
189 	ptr = strrchr(path, '/');
190 	if (ptr != NULL)
191 	    *ptr = '\0';
192 	directory = XmStringCreateLtoR(path, G_charset);
193 	XtSetArg(args[i], XmNdirectory, directory); i++;
194 	free(path);
195 
196 
197 	ASSERT(i < ARG_CNT, "args list too short");
198 	XtSetValues(callback->shell, args, (Cardinal)i);
199 
200 	free(filemask);
201 	free(directory);
202 
203 	XtManageChild(callback->shell);
204 #undef ARG_CNT
205     }
206 }
207 
208 Widget
XsraSelFile(Widget parent,struct filesel_callback * callback)209 XsraSelFile(Widget parent, struct filesel_callback *callback)
210 {
211     Widget dialog = XmCreateFileSelectionDialog(parent, "file", NULL, 0);
212 
213     XtVaSetValues(XtParent(dialog), XmNtitle, callback->title, NULL);
214 
215     XtAddCallback(dialog, XmNokCallback, accept_callback, (XtPointer)callback);
216     XtAddCallback(dialog, XmNcancelCallback, cancel_callback, (XtPointer)callback);
217 
218     /* When opening a DVI file, offer to open in new window */
219     if (callback->must_exist) {
220 	Widget form, button;
221 	XmString test;
222 	form = XtVaCreateManagedWidget("new_window_form", xmFormWidgetClass, dialog, NULL);
223 	test = XmStringCreateLocalized("Open file in new window");
224 	button = XtVaCreateManagedWidget(Xdvi_NEW_WINDOW_RADIO_NAME, xmToggleButtonGadgetClass, form,
225 					 XmNlabelString, test,
226 					 XmNindicatorType, XmN_OF_MANY,
227 					 XmNset, resource.filesel_open_new_window,
228 					 NULL);
229 	XmStringFree(test);
230 	XtAddCallback(button, XmNvalueChangedCallback, cb_open_new_window, (XtPointer)NULL);
231     }
232 
233 
234     /* We have no help in this window, so hide help button */
235     XtUnmanageChild(XmFileSelectionBoxGetChild(dialog, (unsigned char)XmDIALOG_HELP_BUTTON));
236 
237     return dialog;
238 }
239 
240 #else
241 /* silence `empty compilation unit' warnings */
bar(void)242 static void bar(void); static void foo(void) { bar(); } static void bar(void) { foo(); }
243 #endif /* defined(MOTIF) */
244