1 /* $XConsortium: xmapdef.c /main/4 1995/07/15 20:47:41 drk $ */
2 /*
3  * Motif
4  *
5  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6  *
7  * These libraries and programs are free software; you can
8  * redistribute them and/or modify them under the terms of the GNU
9  * Lesser General Public License as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * These libraries and programs are distributed in the hope that
14  * they will be useful, but WITHOUT ANY WARRANTY; without even the
15  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16  * PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with these librararies and programs; if not, write
21  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22  * Floor, Boston, MA 02110-1301 USA
23  */
24 /*
25  * HISTORY
26  */
27 /*
28 **  This demo shows an APPLICATION_DEFINED scrolled window.
29 **
30 **  It's a file viewer that uses a FSB for filename input and
31 **  a viewport with a vertical scrollbar to see the file.
32 **  The file is shown using the per screen font resource.
33 **
34 */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <Xm/XmAll.h>
39 
40 /*-------------------------------------------------------------
41 **	Forwarded functions
42 */
43 void CreateApplication ();
44 void WarnUser ();
45 Widget CreateHelp ();
46 
47 /*      Xt callbacks
48 */
49 void DrawCB ();
50 void ValueCB ();
51 void OpenCB ();
52 void ReadCB ();
53 void QuitCB ();
54 void HelpCB ();
55 
56 /*-------------------------------------------------------------
57 **      File i/o and drawing stuff
58 */
59 void InitFile ();
60 Boolean BuildLineTable ();
61 void ReDraw ();
62 void ReSize ();
63 
64 typedef struct {
65     Widget work_area  ;
66     Widget v_scrb ;
67     String file_name ;
68     XFontStruct * font_struct ;
69     GC draw_gc ;
70     char ** lines ;
71     int num_lines ;
72 } FileData ;
73 
74 
75 /*-------------------------------------------------------------
76 **	    Main body
77 */
main(argc,argv)78 int main(argc, argv)
79 int argc; char **argv;
80 {
81     XtAppContext app_context;
82     Widget      toplevel ;
83     FileData    filedata ;
84 
85     toplevel = XtAppInitialize(&app_context, "XMdemos", NULL, 0,
86 			       &argc, argv, NULL, NULL, 0);
87 
88     InitFile(toplevel, &filedata, argc, argv);
89 
90     CreateApplication (toplevel, &filedata);
91 
92     XtRealizeWidget(toplevel);
93     XtAppMainLoop(app_context);
94 
95     return 0;    /* make compiler happy */
96 }
97 
98 
99 /*-------------------------------------------------------------
100 **	Create a app_defined Main Window with a Menubar to load a file
101 **      Add the vertical scrollbar and the workarea to filedata.
102 */
CreateApplication(parent,filedata)103 void CreateApplication (parent, filedata)
104 Widget		parent;
105 FileData *       filedata;
106 {
107     Widget main_window, menu_bar, menu_pane, cascade,
108            button ;
109     Arg args[5];
110     int	n ;
111 
112 
113     /*	Create app_defined MainWindow.
114      */
115     n = 0;
116     XtSetArg (args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED);  n++;
117     main_window = XmCreateMainWindow (parent, "main_window", args, n);
118     XtManageChild (main_window);
119 
120 
121     /*	Create MenuBar in MainWindow.
122      */
123     n = 0;
124     menu_bar = XmCreateMenuBar (main_window, "menu_bar", args, n);
125     XtManageChild (menu_bar);
126 
127 
128     /*	Create "File" PulldownMenu with Load and Quit buttons
129      */
130     n = 0;
131     menu_pane = XmCreatePulldownMenu (menu_bar, "menu_pane", args, n);
132 
133     n = 0;
134     button = XmCreatePushButton (menu_pane, "Open...", args, n);
135     XtManageChild (button);
136     /* pass the graphic id to the save function */
137     XtAddCallback (button, XmNactivateCallback, OpenCB, (XtPointer)filedata);
138     n = 0;
139     button = XmCreatePushButton (menu_pane, "Quit", args, n);
140     XtManageChild (button);
141     XtAddCallback (button, XmNactivateCallback, QuitCB, NULL);
142 
143     n = 0;
144     XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
145     cascade = XmCreateCascadeButton (menu_bar, "File", args, n);
146     XtManageChild (cascade);
147 
148 
149     /*	Create "Help" PulldownMenu with Help button.
150      */
151     n = 0;
152     menu_pane = XmCreatePulldownMenu (menu_bar, "menu_pane", args, n);
153 
154     n = 0;
155     button = XmCreatePushButton (menu_pane, "Help", args, n);
156     XtManageChild (button);
157     XtAddCallback (button, XmNactivateCallback, HelpCB, NULL);
158 
159     n = 0;
160     XtSetArg (args[n], XmNsubMenuId, menu_pane);  n++;
161     cascade = XmCreateCascadeButton (menu_bar, "Help", args, n);
162     XtManageChild (cascade);
163 
164     n = 0;
165     XtSetArg (args[n], XmNmenuHelpWidget, cascade);  n++;
166     XtSetValues (menu_bar, args, n);
167 
168 
169     /*	Create vertical scrollbar only
170      */
171      n = 0;
172     XtSetArg (args[n], XmNorientation, XmVERTICAL);  n++;
173     filedata->v_scrb = XmCreateScrollBar (main_window, "v_scrb", args, n);
174     XtAddCallback (filedata->v_scrb, XmNvalueChangedCallback, ValueCB,
175 		   (XtPointer)filedata);
176     XtManageChild (filedata->v_scrb);
177 
178 
179     /*	Create work_area in MainWindow
180      */
181     n = 0;
182     filedata->work_area = XmCreateDrawingArea(main_window, "work_area", args, n);
183     XtAddCallback (filedata->work_area, XmNexposeCallback, DrawCB,
184 		   (XtPointer)filedata);
185     XtAddCallback (filedata->work_area, XmNresizeCallback, DrawCB,
186 		   (XtPointer)filedata);
187     XtManageChild (filedata->work_area);
188 
189 
190     /*	Set MainWindow areas
191      */
192     XmMainWindowSetAreas (main_window, menu_bar, NULL, NULL,
193 			  filedata->v_scrb,
194 			  filedata->work_area);
195 
196 }
197 
198 /*-------------------------------------------------------------
199 **	OpenCB			- callback for Open button
200 */
OpenCB(w,client_data,call_data)201 void OpenCB (w, client_data, call_data)
202 Widget		w;		/*  widget id		*/
203 caddr_t		client_data;	/*  data from application   */
204 caddr_t		call_data;	/*  data from widget class  */
205 {
206 	static Widget fsb_box = NULL ;
207 
208 	if (!fsb_box) {
209 	    fsb_box = XmCreateFileSelectionDialog (w, "Load file",
210 						   NULL, 0);
211 	    /* just propagate the graphic information */
212 	    XtAddCallback (fsb_box, XmNokCallback, ReadCB, client_data);
213 	}
214 
215 	XtManageChild (fsb_box);
216 }
217 
218 
219 /*-------------------------------------------------------------
220 **	QuitCB			- callback for quit button
221 */
QuitCB(w,client_data,call_data)222 void QuitCB (w, client_data, call_data)
223 Widget		w;		/*  widget id		*/
224 caddr_t		client_data;	/*  data from applicaiton   */
225 caddr_t		call_data;	/*  data from widget class  */
226 {
227     exit (0);
228 }
229 
230 
231 /*-------------------------------------------------------------
232 **	HelpCB			- callback for help button
233 */
HelpCB(w,client_data,call_data)234 void HelpCB (w, client_data, call_data)
235 Widget		w;		/*  widget id		*/
236 caddr_t		client_data;	/*  data from application   */
237 caddr_t		call_data;	/*  data from widget class  */
238 {
239 	static Widget message_box = NULL ;
240 
241 	if (!message_box) message_box = CreateHelp (w);
242 
243 	XtManageChild (message_box);
244 }
245 
246 
247 
248 /*-------------------------------------------------------------
249 **	ReadCB	- callback for fsb activate
250 */
ReadCB(w,client_data,call_data)251 void ReadCB (w, client_data, call_data)
252 Widget		w;		/*  widget id		*/
253 caddr_t		client_data;	/*  data from application   */
254 caddr_t		call_data;	/*  data from widget class  */
255 {
256     FileData * filedata = (FileData *) client_data ;
257     String file_name ;
258     Arg args[5];
259     int	n, slider_size ;
260     Dimension height ;
261 
262     file_name = XmTextGetString(
263 		 XmFileSelectionBoxGetChild(w, XmDIALOG_TEXT)) ;
264 
265     if (!BuildLineTable(filedata, file_name)) {
266 	WarnUser (w, "Cannot open %s\n", file_name);
267     } else {
268 	filedata->file_name = file_name ;
269 
270 	/* ok, we have a new file, so reset some values */
271 	n = 0;
272 	XtSetArg (args[n], XmNheight, &height);  n++;
273 	XtGetValues (filedata->work_area, args, n);
274 
275 	slider_size = (height - 4) / (filedata->font_struct->ascent
276 				      + filedata->font_struct->descent) ;
277 	if (slider_size <= 0) slider_size = 1 ;
278 	if (slider_size > filedata->num_lines)
279 	    slider_size = filedata->num_lines ;
280 
281 	n = 0 ;
282 	XtSetArg (args[n], XmNsliderSize, slider_size);  n++;
283 	XtSetArg (args[n], XmNmaximum, filedata->num_lines);  n++;
284 	XtSetArg (args[n], XmNvalue, 0);  n++;
285 	XtSetValues (filedata->v_scrb, args, n);
286 
287 	/* clear and redraw */
288 	XClearWindow(XtDisplay(filedata->work_area),
289 		     XtWindow(filedata->work_area));
290 	ReDraw (filedata);
291     }
292 }
293 
294 /*-------------------------------------------------------------
295 **	ValueCB		- callback for scrollbar
296 */
ValueCB(w,client_data,call_data)297 void ValueCB (w, client_data, call_data)
298 Widget		w;		/*  widget id		*/
299 caddr_t		client_data;	/*  data from application   */
300 caddr_t		call_data;	/*  data from widget class  */
301 {
302     FileData * filedata = (FileData *) client_data ;
303 
304     /* clear and redraw, dumb dumb.. */
305     XClearWindow(XtDisplay(filedata->work_area),
306 		 XtWindow(filedata->work_area));
307     ReDraw(filedata);
308 }
309 
310 
311 
312 /*-------------------------------------------------------------
313 **	DrawCB			- callback for drawing area
314 */
DrawCB(w,client_data,call_data)315 void DrawCB (w, client_data, call_data)
316 Widget		w;		/*  widget id		*/
317 caddr_t		client_data;	/*  data from application   */
318 caddr_t		call_data;	/*  data from widget class  */
319 {
320 
321     XmDrawingAreaCallbackStruct * dacs =
322 	(XmDrawingAreaCallbackStruct *) call_data ;
323     FileData * filedata = (FileData *) client_data ;
324     XSetWindowAttributes xswa;
325 
326     static Boolean first_time = True ;
327 
328     switch (dacs->reason) {
329     case XmCR_EXPOSE:
330 	if (first_time) {
331 	    /* Change once the bit gravity of the Drawing Area; default
332 	       is north west and we want forget, so that resize
333 	       always generates exposure events */
334 	    first_time = False ;
335 	    xswa.bit_gravity = ForgetGravity ;
336 	    XChangeWindowAttributes(XtDisplay(w), XtWindow(w),
337 				    CWBitGravity, &xswa);
338 	}
339 
340 	ReDraw(filedata) ;
341 
342 	break ;
343     case XmCR_RESIZE:
344 	ReSize(filedata) ;
345 
346 	break ;
347     }
348 }
349 
350 /*-------------------------------------------------------------
351 **	CreateHelp		- create help window
352 */
CreateHelp(parent)353 Widget CreateHelp (parent)
354 	Widget		parent;		/*  parent widget	*/
355 {
356 	Widget		button;
357 	Widget		message_box;	/*  Message Dialog 	*/
358 	Arg		args[20];	/*  arg list		*/
359 	register int	n;		/*  arg count		*/
360 
361 	static char	message[1000];	/*  help text	*/
362 	XmString	title_string = NULL;
363 	XmString	message_string = NULL;
364 	XmString	button_string = NULL;
365 
366 	/*	Generate message to display.
367 	*/
368 	sprintf (message, "\
369 Use the Open button in the File menu to load a new file.\n\n\
370 Use the ScrollBar to scroll and the window manager to resize the main\n\
371 window and see the slider size change.\n\n\
372 You can specify which font to display the test using the\n\
373 XmNfont screen resource.");
374 
375 	message_string = XmStringCreateLtoR (message,
376 					     XmSTRING_DEFAULT_CHARSET);
377 	button_string = XmStringCreateLtoR ("Close",
378 					    XmSTRING_DEFAULT_CHARSET);
379 	title_string = XmStringCreateLtoR ("General Help",
380 					   XmSTRING_DEFAULT_CHARSET);
381 
382 
383 	/*	Create MessageBox dialog.
384 	*/
385 	n = 0;
386 	XtSetArg (args[n], XmNdialogTitle, title_string);  n++;
387 	XtSetArg (args[n], XmNokLabelString, button_string);  n++;
388 	XtSetArg (args[n], XmNmessageString, message_string);  n++;
389 	message_box = XmCreateMessageDialog (parent, "helpbox", args, n);
390 
391 	button = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
392 	XtUnmanageChild (button);
393 	button = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
394 	XtUnmanageChild (button);
395 
396 
397 	/*	Free strings and return MessageBox.
398 	*/
399 	if (title_string) XmStringFree (title_string);
400 	if (message_string) XmStringFree (message_string);
401 	if (button_string) XmStringFree (button_string);
402 
403 	return (message_box);
404 }
405 
WarnUser(widget,format,name)406 void WarnUser (widget, format, name)
407 Widget widget ;
408 String format ;
409 String name ;
410 {
411     /* better ui needed */
412     printf(format, name);
413 }
414 
415 
416 /*************************** FILE STUFF **********************************/
417 
InitFile(widget,filedata,argc,argv)418 void InitFile(widget, filedata, argc, argv)
419 Widget		widget;
420 FileData *       filedata;
421 int argc;     char **argv;
422 {
423     Arg args[5];
424     int	n ;
425     XGCValues val ;
426 
427     filedata->lines = NULL ;
428     filedata->num_lines = 0 ;
429 
430     /* get the X font from the screen object and make a gc */
431     n = 0;
432 
433 /* do not use the screen object routine in 1.1 or lesser */
434 #if XmREVISION < 2
435     filedata->font_struct = XLoadQueryFont(XtDisplay(widget), "fixed");
436 #else
437     XtSetArg (args[n], XmNfont, &(filedata->font_struct));  n++;
438     XtGetValues (XmGetXmScreen(XDefaultScreenOfDisplay(XtDisplay(widget))),
439 		 args, n);
440 #endif
441     val.font = filedata->font_struct->fid ;
442     filedata->draw_gc = XtGetGC(widget, GCFont, &val);
443 
444     if (argc == 2) {
445 	if (BuildLineTable(filedata, argv[1])) {
446 	    filedata->file_name = argv[1] ;
447 	} else {
448 	    filedata->file_name = "" ;
449 	    WarnUser(widget, "Cannot open %s\n", argv[1]);
450 	}
451     } else {
452 	filedata->file_name = "" ;
453     }
454 }
455 
456 
BuildLineTable(filedata,file_name)457 Boolean BuildLineTable(filedata, file_name)
458 FileData * filedata ;
459 String file_name ;
460 {
461     FILE  *in_file ;
462     char linebuff[256] ;
463 
464     if ((in_file = fopen(file_name, "r")) == NULL) {
465 	return False ;
466     } else {
467 	/* free the current data */
468 	if (filedata->num_lines) {
469 	    while (filedata->num_lines-- >= 0) {
470 		XtFree(filedata->lines[filedata->num_lines]) ;
471 	    }
472 	    XtFree ((char*)filedata->lines) ;
473 	    filedata->lines = NULL ;
474 	    filedata->num_lines = 0 ;
475 	}
476 	/* allocate and fill new data */
477 	while (fgets (linebuff, 256, in_file)) {
478 	    filedata->num_lines ++ ;
479 	    /* better fragmentation needed... */
480 	    filedata->lines = (char**) XtRealloc((char*)filedata->lines,
481 					filedata->num_lines * sizeof(char*)) ;
482 	    filedata->lines[filedata->num_lines-1] = XtNewString(linebuff);
483 	}
484 	return True ;
485     }
486 }
487 
ReDraw(filedata)488 void ReDraw(filedata)
489 FileData * filedata ;
490 {
491     /* Display as many line as slider_size actually shows, since
492        slider_size is computed relative to the work_area height */
493 
494     Cardinal i ;
495     int value, slider_size ;
496     Arg args[5];
497     int	n ;
498     Position y ;
499 
500     if (filedata->num_lines == 0) return ;
501 
502     n = 0;
503     XtSetArg (args[n], XmNvalue, &value);  n++;
504     XtSetArg (args[n], XmNsliderSize, &slider_size);  n++;
505     XtGetValues (filedata->v_scrb, args, n);
506 
507     for (i = value, y = 2 + filedata->font_struct->ascent;
508 	 i < value + slider_size ;
509 	 i++, y += (filedata->font_struct->ascent
510 		    + filedata->font_struct->descent)) {
511 	XDrawString(XtDisplay(filedata->work_area),
512 		    XtWindow(filedata->work_area),
513 		    filedata->draw_gc,
514 		    4, y,
515 		    filedata->lines[i], strlen(filedata->lines[i]));
516     }
517 }
518 
ReSize(filedata)519 void ReSize(filedata)
520 FileData * filedata ;
521 {
522     /* Just update the scrollbar internals here, don't bother to redisplay
523        since the gravity is none */
524 
525     Arg args[5];
526     int	n ;
527     int value, slider_size ;
528     Dimension height ;
529 
530     if (filedata->num_lines == 0) return ;
531 
532     n = 0;
533     XtSetArg (args[n], XmNheight, &height);  n++;
534     XtGetValues (filedata->work_area, args, n);
535 
536     /* sliderSize is the number of visible lines */
537     slider_size = (height - 4) / (filedata->font_struct->ascent
538 				  + filedata->font_struct->descent) ;
539     if (slider_size <= 0) slider_size = 1 ;
540     if (slider_size > filedata->num_lines)
541 	slider_size = filedata->num_lines ;
542 
543     n = 0;
544     XtSetArg (args[n], XmNvalue, &value);  n++;
545     XtGetValues (filedata->v_scrb, args, n);
546 
547     /* value shouldn't change that often but there are cases
548        where it matters */
549     if (value > filedata->num_lines - slider_size)
550 	value = filedata->num_lines - slider_size;
551 
552     n = 0;
553     XtSetArg (args[n], XmNsliderSize, slider_size);  n++;
554     XtSetArg (args[n], XmNvalue, value);  n++;
555     XtSetArg (args[n], XmNmaximum, filedata->num_lines);  n++;
556     XtSetValues (filedata->v_scrb, args, n);
557 }
558 
559