1 /*
2  * ui_x.c
3  *
4  * user interface for the X Window System.
5  */
6 
7 /* $Id: ui_x.c,v 1.31 2000/08/22 01:28:59 nyef Exp $ */
8 
9 #include <X11/Intrinsic.h>
10 #include <X11/Shell.h>
11 #include <X11/StringDefs.h>
12 #include <X11/Xaw/Box.h>
13 #include <X11/Xaw/MenuButton.h>
14 #include <X11/Xaw/SimpleMenu.h>
15 #include <X11/Xaw/SmeBSB.h>
16 
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include "ui.h"
20 #include "system.h"
21 #include "video.h"
22 #include "tool.h"
23 #include "menu.h"
24 
25 #define APPLICATION_NAME "darcnes"
26 #define APPLICATION_CLASS "DarcNES"
27 
28 /* Overhead for Xt and main window */
29 XtAppContext context;
30 Widget toplevel;
31 Widget manager;
32 
33 /* Menus */
34 Widget menubar;
35 Widget menubutton_file;
36 Widget menu_file;
37 Widget menu_file_exit;
38 
39 /* the drawing area */
40 Widget drawbox;
41 
42 /* the shutdown callback */
43 shutdown_t dn_shutdown;
44 
45 /* miscellany */
46 void do_file_exit(Widget, XtPointer, XtPointer);
47 Boolean emulation_timeslice(XtPointer);
48 
menu_callback(Widget widget,XtPointer menu,XtPointer call_data)49 void menu_callback(Widget widget, XtPointer menu, XtPointer call_data)
50 {
51     struct ui_menu *item;
52 
53     item = (struct ui_menu *) menu;
54     item->callback(item->callback_data);
55 }
56 
menu_init(struct ui_menu * menu)57 void menu_init(struct ui_menu *menu)
58 {
59     Widget menubutton;
60     Widget themenu;
61     Widget menuitem;
62     int i;
63 
64     menubutton = XtCreateManagedWidget(menu[0].name, menuButtonWidgetClass, menubar, NULL, 0);
65     themenu = XtCreatePopupShell("drivermenu", simpleMenuWidgetClass, menubutton, NULL, 0);
66     XtVaSetValues(menubutton, XtNmenuName, "drivermenu", NULL);
67 
68     for (i = 1; menu[i].name; i++) {
69 	if (menu[i].flags & MF_CHILD) {
70 	    /* don't create child menus */
71 	    continue;
72 	}
73 	menuitem = XtCreateManagedWidget(menu[i].name, smeBSBObjectClass, themenu, NULL, 0);
74 	XtAddCallback(menuitem, XtNcallback, menu_callback, &menu[i]);
75 	menu[i].ui_data = menuitem;
76     }
77 }
78 
menu_rename_item(struct ui_menu * item)79 void menu_rename_item(struct ui_menu *item)
80 {
81     Widget item_widget;
82 
83     item_widget = item->ui_data;
84     XtVaSetValues(item_widget, XtNlabel, item->name, NULL);
85 }
86 
menu_disable_item(struct ui_menu * item)87 void menu_disable_item(struct ui_menu *item)
88 {
89     /* dummy implementation */
90 }
91 
menu_enable_item(struct ui_menu * item)92 void menu_enable_item(struct ui_menu *item)
93 {
94     /* dummy implementation */
95 }
96 
init_menus(void)97 void init_menus(void)
98 {
99     /* the menubar */
100     menubar = XtVaCreateManagedWidget("menubar", boxWidgetClass, manager, XtNorientation, XtorientHorizontal, XtNborderWidth, 0, NULL);
101 
102     /* the file menu */
103     menubutton_file = XtCreateManagedWidget("File", menuButtonWidgetClass, menubar, NULL, 0);
104     menu_file = XtCreatePopupShell("fileMenu", simpleMenuWidgetClass, menubutton_file, NULL, 0);
105     XtVaSetValues(menubutton_file, XtNmenuName, "fileMenu", NULL);
106     menu_file_exit = XtCreateManagedWidget("Exit", smeBSBObjectClass, menu_file, NULL, 0);
107     XtAddCallback(menu_file_exit, XtNcallback, do_file_exit, NULL);
108 }
109 
menu_file_open_box(ui_open_callback callback,void * data,char * filter)110 void menu_file_open_box(ui_open_callback callback, void *data, char *filter)
111 {
112     /* dummy implementation */
113 }
114 
initialize_window(Display * display)115 void initialize_window(Display *display)
116 {
117     toplevel = XtVaAppCreateShell(APPLICATION_NAME, APPLICATION_CLASS, applicationShellWidgetClass, display, XtNallowShellResize, TRUE, NULL);
118 
119     manager = XtVaCreateManagedWidget("manager", boxWidgetClass, toplevel, XtNhSpace, 0, XtNvSpace, 0, NULL);
120 
121     init_menus();
122 
123     drawbox = XtVaCreateManagedWidget("drawbox", boxWidgetClass, manager, XtNwidth, 512, XtNheight, 256, NULL);
124 
125     XtRealizeWidget(toplevel);
126 
127     video_init();
128 }
129 
usage(char * progname)130 void usage(char *progname)
131 {
132     printf("usage: %s [--system=<system>] [--nosound] [filename]\n", progname);
133 }
134 
main(int argc,char * argv[])135 int main(int argc, char *argv[])
136 {
137     extern int nes_psg_quality; /* FIXME: cheap hack, copied from nes_psg.h */
138     rom_file romfile;
139     int system_type;
140     int i;
141     Display *display; /* so as not to conflict with the one in video_x.c */
142 
143     XtToolkitInitialize();
144 
145     context = XtCreateApplicationContext();
146 
147     display = XtOpenDisplay(context, NULL, APPLICATION_NAME, APPLICATION_CLASS, NULL, 0, &argc, argv);
148 
149     if (argc == 1) {
150 	usage(argv[0]);
151 	return 1;
152     }
153 
154     system_type = ST_NONE;
155     romfile = NULL;
156 
157     nes_psg_quality = 2;
158 
159     for (i = 1; i < argc; i++) {
160 	if (!strncasecmp(argv[i], "--system=", 9)) {
161 	    system_type = parse_system_name(argv[i] + 9);
162 	} else if (!strcasecmp(argv[i], "--nosound")) {
163 	    nes_psg_quality = 0;
164 	} else if (romfile) {
165 	    printf("rom file \"%s\" already loaded, ignoring \"%s\"\n", romfile->filename, argv[i]);
166 	} else if ((romfile = read_romimage(argv[i]))) {
167 	    if (system_type == ST_NONE) {
168 		system_type = guess_system(romfile);
169 	    }
170 	} else {
171 	    printf("error loading rom file \"%s\"\n", argv[i]);
172 	}
173     }
174 
175     if (system_type == ST_NONE) {
176 	printf("no system specified or unable to guess system.\n");
177 	return 1;
178     }
179 
180     if (romfile == NULL) {
181 	printf("rom not specified.\n");
182 	usage(argv[0]);
183 	return 1;
184     }
185 
186     initialize_window(display);
187 
188     activate_system(system_type, romfile);
189 
190     XtAppMainLoop(context);
191 
192     return 0;
193 }
194 
195 
196 /* debug console handling */
197 
deb_printf(const char * fmt,...)198 void deb_printf(const char *fmt, ...)
199 {
200     va_list args;
201 
202     va_start(args, fmt);
203     vprintf(fmt, args);
204     va_end(args);
205 }
206 
207 
208 /* emulation timeslicing */
209 
210 void (*timeslice)(void *) = NULL;
211 void *timeslice_data;
212 
set_timeslice(void (* proc)(void *),void * data)213 void set_timeslice(void (*proc)(void *), void *data)
214 {
215     if (!timeslice) {
216 	XtAppAddWorkProc(context, emulation_timeslice, NULL);
217     }
218 
219     timeslice = proc;
220     timeslice_data = data;
221 }
222 
unset_timeslice(void)223 void unset_timeslice(void)
224 {
225     timeslice = NULL;
226     timeslice_data = NULL;
227 }
228 
emulation_timeslice(XtPointer client_data)229 Boolean emulation_timeslice(XtPointer client_data)
230 {
231     if (timeslice) {
232 	timeslice(timeslice_data);
233     }
234 
235     if ((system_flags == F_NONE) && timeslice) {
236 	return False;
237     } else {
238 	return True;
239     }
240 }
241 
242 
243 /* menu callbacks */
244 
do_file_exit(Widget w,XtPointer client_data,XtPointer call_data)245 void do_file_exit(Widget w, XtPointer client_data, XtPointer call_data)
246 {
247     if (dn_shutdown) {
248 	dn_shutdown();
249     }
250     exit(0);
251 }
252 
253 
254 /* video interface */
255 
ui_set_drawbox_size(int width,int height)256 void ui_set_drawbox_size(int width, int height)
257 {
258     XtVaSetValues(drawbox, XtNwidth, width, XtNheight, height, NULL);
259 }
260 
261 /*
262  * $Log: ui_x.c,v $
263  * Revision 1.31  2000/08/22 01:28:59  nyef
264  * added dummy implementation of menu_file_open_box()
265  *
266  * Revision 1.30  2000/07/01 15:43:14  nyef
267  * fixed to not dump core when encountering a child menu
268  *
269  * Revision 1.29  2000/06/29 01:24:56  nyef
270  * renamed the menu functions more appropriately
271  *
272  * Revision 1.28  2000/06/29 01:05:39  nyef
273  * moved menu interface out from ui.h to menu.h
274  *
275  * Revision 1.27  2000/06/25 19:22:11  nyef
276  * added dummy implementations of ui_{en,dis}able_item()
277  *
278  * Revision 1.26  2000/06/25 18:57:09  nyef
279  * added support for parameters with menu callbacks
280  * added support for changing the label on a menu
281  *
282  * Revision 1.25  2000/06/25 17:20:09  nyef
283  * added per-driver menu interface
284  *
285  * Revision 1.24  2000/06/10 02:20:49  nyef
286  * fixed --nosound option (silly bug in args parser)
287  *
288  * Revision 1.23  2000/06/09 00:11:31  nyef
289  * added --nosound option
290  *
291  * Revision 1.22  2000/03/25 18:23:02  nyef
292  * broke up toolkit initialization
293  * moved toplevel window creation to initialize_window()
294  *
295  * Revision 1.21  2000/03/06 01:29:59  nyef
296  * extracted most of the X initialization code from main()
297  * rebuilt the command argument parser (added "--system=" option)
298  *
299  * Revision 1.20  2000/02/21 23:16:09  nyef
300  * fixed toplevel window to resize when the drawbox is resized
301  *
302  * Revision 1.19  2000/01/01 04:15:14  nyef
303  * added disabled code to activate apple2 emulation
304  *
305  * Revision 1.18  1999/12/04 06:43:22  nyef
306  * stripped out a lot of dead code
307  *
308  * Revision 1.17  1999/11/26 20:08:24  nyef
309  * moved sound quality control in from the game system layer
310  *
311  * Revision 1.16  1999/11/20 05:27:19  nyef
312  * fixed to work with new rom loading interface
313  *
314  * Revision 1.15  1999/04/17 20:12:46  nyef
315  * changed shutdown() to dn_shutdown().
316  *
317  * Revision 1.14  1999/03/03 02:53:05  nyef
318  * changed the initial size of the drawbox to "really big"
319  * as a workaround for the resize problem
320  *
321  * Revision 1.13  1999/02/13 17:25:34  nyef
322  * disabled file->nes.
323  * added code to accept a filename on the command line.
324  * changed to start running game immediately after starting.
325  *
326  * Revision 1.12  1999/01/08 02:45:25  nyef
327  * disabled file->zarzon.
328  *
329  * Revision 1.11  1998/12/24 04:56:51  nyef
330  * moved for loop from emulation_timeslice() to nes.c.
331  *
332  * Revision 1.10  1998/12/24 01:23:18  nyef
333  * removed debug menu (it was at best useless, and at worst dangerous).
334  * added two file menu items ("Nes", and "Zarzon") to start the system.
335  * fixed file->quit to call exit(3).
336  * fixed background task to only run when we need an emulation timeslice.
337  *
338  * Revision 1.9  1998/12/21 02:58:03  nyef
339  * added a shutdown callback.
340  *
341  * Revision 1.8  1998/12/18 04:22:25  nyef
342  * changed application class to "DarcNES".
343  *
344  * Revision 1.7  1998/10/28 01:50:00  nyef
345  * changed emulation_timeslice() to return aproximately once per screen
346  * refresh. this sped up the emulation appreciably but does not appear
347  * to have degraded the key response.
348  *
349  * Revision 1.6  1998/10/02 01:22:07  nyef
350  * changed timeslice function to remove itself when emulation halts.
351  *
352  * Revision 1.5  1998/08/24 01:25:41  nyef
353  * started working on new interface.
354  *
355  * Revision 1.4  1998/08/02 04:01:56  nyef
356  * added function deb_printf() for debug console support.
357  * added ui.h to the list of includes.
358  *
359  * Revision 1.3  1998/08/02 03:56:28  nyef
360  * added comments grouping functions into related sections.
361  *
362  * Revision 1.2  1998/08/02 02:31:47  nyef
363  * added a separate menubar widget.
364  * added a "Debug" menu with one item. ("Show console", which calls a stub.)
365  *
366  * Revision 1.1  1998/08/02 02:04:26  nyef
367  * Initial revision
368  *
369  */
370