1 /*
2 * Copyright (c) 2009-2015 Hypertriton, Inc. <http://hypertriton.com/>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 /*
27 * Main Agar-GUI initialization.
28 */
29
30 #include <agar/core/core.h>
31 #include <agar/core/config.h>
32
33 #include <agar/config/have_opengl.h>
34 #include <agar/config/ag_debug_gui.h>
35
36 #include <agar/gui/gui.h>
37 #include <agar/gui/box.h>
38 #include <agar/gui/button.h>
39 #include <agar/gui/checkbox.h>
40 #include <agar/gui/combo.h>
41 #include <agar/gui/console.h>
42 #include <agar/gui/dir_dlg.h>
43 #include <agar/gui/editable.h>
44 #include <agar/gui/file_dlg.h>
45 #include <agar/gui/file_selector.h>
46 #include <agar/gui/fixed.h>
47 #include <agar/gui/fspinbutton.h>
48 #include <agar/gui/fixed_plotter.h>
49 #include <agar/gui/font_selector.h>
50 #include <agar/gui/glview.h>
51 #include <agar/gui/graph.h>
52 #include <agar/gui/hsvpal.h>
53 #include <agar/gui/icon.h>
54 #include <agar/gui/label.h>
55 #include <agar/gui/menu.h>
56 #include <agar/gui/mfspinbutton.h>
57 #include <agar/gui/mpane.h>
58 #include <agar/gui/mspinbutton.h>
59 #include <agar/gui/notebook.h>
60 #include <agar/gui/numerical.h>
61 #include <agar/gui/objsel.h>
62 #include <agar/gui/pane.h>
63 #include <agar/gui/pixmap.h>
64 #include <agar/gui/progress_bar.h>
65 #include <agar/gui/radio.h>
66 #include <agar/gui/scrollbar.h>
67 #include <agar/gui/scrollview.h>
68 #include <agar/gui/separator.h>
69 #include <agar/gui/slider.h>
70 #include <agar/gui/socket.h>
71 #include <agar/gui/spinbutton.h>
72 #include <agar/gui/statusbar.h>
73 #include <agar/gui/table.h>
74 #include <agar/gui/treetbl.h>
75 #include <agar/gui/textbox.h>
76 #include <agar/gui/titlebar.h>
77 #include <agar/gui/tlist.h>
78 #include <agar/gui/toolbar.h>
79 #include <agar/gui/ucombo.h>
80
81 #include <agar/gui/colors.h>
82 #include <agar/gui/cursors.h>
83 #include <agar/gui/primitive.h>
84 #include <agar/gui/icons.h>
85 #include <agar/gui/icons_data.h>
86 #include <agar/gui/text.h>
87
88 static struct {
89 const char *key;
90 int *p;
91 } agGUIOptions[] = {
92 { "ag_kbd_delay", &agKbdDelay },
93 { "ag_kbd_repeat", &agKbdRepeat },
94 { "ag_mouse_dblclick_delay", &agMouseDblclickDelay },
95 { "ag_mouse_spin_delay", &agMouseSpinDelay },
96 { "ag_mouse_spin_interval", &agMouseSpinIval },
97 { "ag_text_composition", &agTextComposition },
98 { "ag_text_bidi", &agTextBidi },
99 { "ag_text_cache", &agTextCache },
100 { "ag_text_tab_width", &agTextTabWidth },
101 { "ag_text_blink_rate", &agTextBlinkRate },
102 { "ag_text_symbols", &agTextSymbols },
103 { "ag_page_increment", &agPageIncrement },
104 { "ag_idle_threshold", &agIdleThresh },
105 { "ag_screenshot_quality", &agScreenshotQuality },
106 { "ag_msg_delay", &agMsgDelay }
107 };
108 const Uint agGUIOptionCount = sizeof(agGUIOptions) / sizeof(agGUIOptions[0]);
109
110 void *agStdClasses[] = {
111 &agDriverClass,
112 &agDriverSwClass,
113 &agDriverMwClass,
114 &agInputDeviceClass,
115 &agMouseClass,
116 &agKeyboardClass,
117 NULL
118 };
119 void *agStdWidgets[] = {
120 &agWidgetClass,
121 &agWindowClass,
122 &agFontClass,
123 &agBoxClass,
124 &agButtonClass,
125 &agCheckboxClass,
126 &agComboClass,
127 &agConsoleClass,
128 &agDirDlgClass,
129 &agEditableClass,
130 &agFontSelectorClass,
131 &agFileDlgClass,
132 &agFileSelectorClass,
133 &agFixedClass,
134 &agFSpinbuttonClass,
135 &agFixedPlotterClass,
136 &agGraphClass,
137 #ifdef HAVE_OPENGL
138 &agGLViewClass,
139 #endif
140 &agHSVPalClass,
141 &agIconClass,
142 &agLabelClass,
143 &agMenuClass,
144 &agMenuViewClass,
145 &agMFSpinbuttonClass,
146 &agMPaneClass,
147 &agMSpinbuttonClass,
148 &agNotebookClass,
149 &agNotebookTabClass,
150 &agNumericalClass,
151 &agObjectSelectorClass,
152 &agPaneClass,
153 &agPixmapClass,
154 &agProgressBarClass,
155 &agRadioClass,
156 &agScrollbarClass,
157 &agScrollviewClass,
158 &agSeparatorClass,
159 &agSliderClass,
160 &agSocketClass,
161 &agSpinbuttonClass,
162 &agStatusbarClass,
163 &agTitlebarClass,
164 &agTableClass,
165 &agTreetblClass,
166 &agTextboxClass,
167 &agTlistClass,
168 &agToolbarClass,
169 &agUComboClass,
170 NULL
171 };
172
173 static int initedGlobals = 0; /* GUI globals are initialized */
174
175 int agGUI = 0; /* GUI is initialized */
176 int agRenderingContext = 0; /* In rendering context */
177 int agStereo = 0; /* Stereoscopic display */
178 int agKbdDelay = 250; /* Key repeat delay */
179 int agKbdRepeat = 35; /* Key repeat interval */
180 int agMouseDblclickDelay = 250; /* Mouse double-click delay */
181 int agMouseSpinDelay = 250; /* Spinbutton repeat delay */
182 int agMouseSpinIval = 50; /* Spinbutton repeat interval */
183 int agMouseScrollDelay = 100; /* Scrollbar increment delay */
184 int agMouseScrollIval = 50; /* Scrollbar increment interval */
185 int agTextComposition = 1; /* Built-in input composition */
186 int agTextBidi = 0; /* Bidirectionnal text display */
187 int agTextCache = 1; /* Dynamic text caching */
188 int agTextTabWidth = 40; /* Tab width (px) */
189 int agTextBlinkRate = 500; /* Cursor blink rate (ms) */
190 int agTextSymbols = 1; /* Process special symbols in text */
191 int agPageIncrement = 4; /* Pgup/Pgdn scrolling increment */
192 int agIdleThresh = 20; /* Idling threshold */
193 int agScreenshotQuality = 100; /* JPEG quality in % */
194 int agMsgDelay = 500; /* Display duration of infoboxes (ms) */
195 double agZoomValues[AG_ZOOM_RANGE] = { /* Scale values for zoom */
196 30.00, 50.00, 67.00, 80.00, 90.00,
197 100.00,
198 110.00, 120.00, 133.00, 150.00, 170.00, 200.00, 240.00, 300.00
199 };
200
201 /*
202 * Initialize the Agar-GUI globals and built-in classes. This function
203 * is invoked internally prior to graphics initialization.
204 */
205 int
AG_InitGUIGlobals(void)206 AG_InitGUIGlobals(void)
207 {
208 AG_Config *cfg;
209 void **cl;
210 Uint i;
211
212 if (initedGlobals++ > 0) {
213 return (0);
214 }
215 agGUI = 1;
216
217 for (cl = &agStdClasses[0]; *cl != NULL; cl++)
218 AG_RegisterClass(*cl);
219 for (i = 0; i < agDriverListSize; i++)
220 AG_RegisterClass(agDriverList[i]);
221
222 AG_InitGlobalKeys();
223 AG_EditableInitClipboards();
224
225 agSurfaceFmt = AG_PixelFormatRGBA(32,
226 #if AG_BYTEORDER == AG_BIG_ENDIAN
227 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
228 #else
229 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
230 #endif
231 );
232
233 agRenderingContext = 0;
234 AG_ObjectInitStatic(&agDrivers, &agObjectClass);
235 AG_ObjectSetName(&agDrivers, "agDrivers");
236 AG_ObjectInitStatic(&agInputDevices, &agObjectClass);
237 AG_ObjectSetName(&agInputDevices, "agInputDevices");
238
239 cfg = AG_ConfigObject();
240 for (i = 0; i < agGUIOptionCount; i++)
241 AG_BindInt(cfg, agGUIOptions[i].key, agGUIOptions[i].p);
242
243 AG_LoadStyleSheet(NULL, "_agStyleDefault");
244 return (0);
245 }
246
247 /*
248 * Destroy the Agar-GUI globals and built-in classes. This function
249 * is invoked internally after the graphics subsystem is destroyed.
250 */
251 void
AG_DestroyGUIGlobals(void)252 AG_DestroyGUIGlobals(void)
253 {
254 AG_Config *cfg;
255 void **cl;
256 Uint i;
257
258 if (--initedGlobals > 0)
259 return;
260
261 AG_DestroyStyleSheet(&agDefaultCSS);
262
263 cfg = AG_ConfigObject();
264 for (i = 0; i < agGUIOptionCount; i++)
265 AG_Unset(cfg, agGUIOptions[i].key);
266
267 AG_ObjectDestroy(&agInputDevices);
268 #ifndef __APPLE__ /* XXX mutex issue */
269 AG_ObjectDestroy(&agDrivers);
270 #endif
271
272 AG_PixelFormatFree(agSurfaceFmt); agSurfaceFmt = NULL;
273 AG_EditableDestroyClipboards();
274 AG_DestroyGlobalKeys();
275
276 for (i = 0; i < agDriverListSize; i++)
277 AG_UnregisterClass(agDriverList[i]);
278 for (cl = &agStdClasses[0]; *cl != NULL; cl++)
279 AG_UnregisterClass(*cl);
280
281 agRenderingContext = 0;
282 agGUI = 0;
283 }
284
285 /*
286 * Initialize the Agar-GUI library. This is called internally by
287 * AG_InitGraphics().
288 *
289 * As an alternative to AG_InitGraphics(), applications may also invoke
290 * AG_InitGUI() directly (following one or more AG_DriverOpen() calls).
291 */
292 int
AG_InitGUI(Uint flags)293 AG_InitGUI(Uint flags)
294 {
295 void **ops;
296
297 for (ops = &agStdWidgets[0]; *ops != NULL; ops++) {
298 AG_RegisterClass(*ops);
299 }
300 agIcon_Init();
301
302 if (AG_InitTextSubsystem() == -1) {
303 return (-1);
304 }
305 AG_InitWindowSystem();
306 AG_InitAppMenu();
307 return (0);
308 }
309
310 /*
311 * Release all resources allocated by the Agar-GUI library. This is called
312 * directly from the application, or from AG_Destroy().
313 */
314 void
AG_DestroyGUI(void)315 AG_DestroyGUI(void)
316 {
317 void **ops;
318 AG_Object *drv, *drvNext;
319 AG_Window *win;
320
321 AG_LockVFS(&agDrivers);
322
323 /* Destroy all windows */
324 #ifdef AG_DEBUG_GUI
325 Debug(NULL, "AG_DestroyGUI()\n");
326 #endif
327 OBJECT_FOREACH_CHILD(drv, &agDrivers, ag_object) {
328 OBJECT_FOREACH_CHILD(win, drv, ag_window) {
329 #ifdef AG_DEBUG_GUI
330 Debug(drv, "Freeing Window %s (\"%s\")\n", OBJECT(win)->name, win->caption);
331 #endif
332 AG_ObjectDetach(win);
333 }
334 }
335 while (!TAILQ_EMPTY(&agWindowDetachQ)) {
336 AG_WindowProcessDetachQueue();
337 }
338
339 for (drv = TAILQ_FIRST(&agDrivers.children);
340 drv != TAILQ_END(&agDrivers.children);
341 drv = drvNext) {
342 drvNext = TAILQ_NEXT(drv, cobjs);
343 #ifdef AG_DEBUG_GUI
344 Debug(drv, "Freeing Driver %s\n", OBJECT(drv)->name);
345 #endif
346 TAILQ_INIT(&drv->children);
347 AG_DriverClose((AG_Driver *)drv);
348 }
349
350 agDriverSw = NULL;
351 agDriverMw = NULL;
352 agDriverOps = NULL;
353 AG_UnlockVFS(&agDrivers);
354
355 AG_DestroyAppMenu();
356 AG_DestroyWindowSystem();
357 AG_DestroyTextSubsystem();
358 agIcon_Destroy();
359
360 for (ops = &agStdWidgets[0]; *ops != NULL; ops++)
361 AG_UnregisterClass(*ops);
362
363 AG_DestroyGUIGlobals();
364 }
365
366 /* Break out of the event loop. */
367 void
AG_QuitGUI(void)368 AG_QuitGUI(void)
369 {
370 AG_Terminate(0);
371 }
372
373 /*
374 * Initialize the Agar-GUI library. If spec is non-NULL, select the driver
375 * by priority from a comma-separated list. If spec is NULL, try to match
376 * the "best" driver for the current platform.
377 *
378 * Note: Instead of using AG_InitGraphics(), applications may also use the
379 * low-level AG_DriverOpen(), AG_InitGUI() and AG_DestroyGUI() interface
380 * (as is needed when creating multiple driver instances).
381 */
382 int
AG_InitGraphics(const char * spec)383 AG_InitGraphics(const char *spec)
384 {
385 char specBuf[128], *s, *sOpts = "", *tok;
386 AG_Driver *drv = NULL;
387 AG_DriverClass *dc = NULL;
388 int i;
389 size_t len;
390
391 if (AG_InitGUIGlobals() == -1)
392 return (-1);
393
394 if (agDriverMw != NULL || agDriverSw != NULL) {
395 AG_SetError(_("Root driver already initialized"));
396 goto fail;
397 }
398 if (spec != NULL && spec[0] != '\0') {
399 Strlcpy(specBuf, spec, sizeof(specBuf));
400 s = &specBuf[0];
401
402 if (strncmp(s, "<OpenGL>", 8) == 0) {
403 /*
404 * Select preferred OpenGL-compatible driver.
405 */
406 sOpts = &s[8];
407 for (i = 0; i < agDriverListSize; i++) {
408 dc = agDriverList[i];
409 if (dc->flags & AG_DRIVER_OPENGL &&
410 (drv = AG_DriverOpen(dc)) != NULL)
411 break;
412 }
413 if (i == agDriverListSize) {
414 AG_SetError(_("No OpenGL drivers are available"));
415 goto fail;
416 }
417 } else if (strncmp(s, "<SDL>", 5) == 0) {
418 /*
419 * Select preferred SDL-compatible driver.
420 */
421 sOpts = &s[5];
422 for (i = 0; i < agDriverListSize; i++) {
423 dc = agDriverList[i];
424 if (dc->flags & AG_DRIVER_SDL &&
425 (drv = AG_DriverOpen(dc)) != NULL)
426 break;
427 }
428 if (i == agDriverListSize) {
429 AG_SetError(_("No SDL drivers are available"));
430 goto fail;
431 }
432 } else {
433 /*
434 * Try explicit list of preferred drivers.
435 */
436 while ((tok = AG_Strsep(&s, ",;")) != NULL) {
437 for (i = 0; i < agDriverListSize; i++) {
438 dc = agDriverList[i];
439 len = strlen(dc->name);
440 if (strncmp(dc->name, tok, len) == 0 &&
441 (tok[len] == '\0' || tok[len] == '(') &&
442 (drv = AG_DriverOpen(dc)) != NULL) {
443 sOpts = &tok[len];
444 break;
445 }
446 }
447 if (i < agDriverListSize)
448 break;
449 }
450 if (tok == NULL) {
451 char availDrvs[256];
452
453 for (availDrvs[0] = '\0', i = 0;
454 i < agDriverListSize; i++) {
455 dc = agDriverList[i];
456 Strlcat(availDrvs, " ", sizeof(availDrvs));
457 Strlcat(availDrvs, dc->name, sizeof(availDrvs));
458 }
459 AG_SetError(_("Agar driver is not available: \"%s\"\n"
460 "(compiled-in drivers: <%s >)"),
461 specBuf, availDrvs);
462 goto fail;
463 }
464 }
465 } else {
466 /*
467 * Auto-select best available driver.
468 */
469 for (i = 0; i < agDriverListSize; i++) {
470 dc = agDriverList[i];
471 if ((drv = AG_DriverOpen(dc)) != NULL)
472 break;
473 }
474 if (i == agDriverListSize) {
475 AG_SetError(_("No graphics drivers are available"));
476 goto fail;
477 }
478 }
479
480 /* Process driver options */
481 if (sOpts[0] == '(' && sOpts[1] != '\0') {
482 char *key, *val, *ep;
483
484 sOpts++;
485 if ((ep = strrchr(sOpts, ')')) != NULL) {
486 *ep = '\0';
487 } else {
488 Verbose(_("Syntax error in driver options: %s\n"), sOpts);
489 }
490 while ((tok = AG_Strsep(&sOpts, ":")) != NULL) {
491 if ((key = AG_Strsep(&tok, "=")) != NULL) {
492 if (Strcasecmp(key, "stereo") == 0) {
493 agStereo = 1;
494 continue;
495 }
496 if ((val = AG_Strsep(&tok, "=")) != NULL) {
497 AG_SetString(drv, key, val);
498 } else {
499 AG_SetString(drv, key, "");
500 }
501 }
502 }
503 }
504
505 switch (dc->wm) {
506 case AG_WM_MULTIPLE:
507 agDriverMw = AGDRIVER_MW(drv);
508 break;
509 case AG_WM_SINGLE:
510 if (AGDRIVER_SW_CLASS(drv)->openVideo(drv, 0,0,0,
511 AG_VIDEO_RESIZABLE) == -1) {
512 AG_SetError("%s: %s", OBJECT(drv)->name,
513 AG_GetError());
514 goto fail_close;
515 }
516 agDriverSw = AGDRIVER_SW(drv);
517 break;
518 }
519 agDriverOps = dc;
520
521 if (AG_InitGUI(0) == -1) {
522 goto fail_close;
523 }
524 return (0);
525 fail_close:
526 if (drv != NULL) { AG_DriverClose(drv); }
527 agDriverOps = NULL;
528 agDriverSw = NULL;
529 agDriverMw = NULL;
530 fail:
531 AG_DestroyGUIGlobals();
532 return (-1);
533 }
534
535 /* Provided for symmetry. */
536 void
AG_DestroyGraphics(void)537 AG_DestroyGraphics(void)
538 {
539 AG_DestroyGUI();
540 }
541
542 /*
543 * Zoom in/out the GUI elements of the active window, changing
544 * the default font size accordingly. Depending on style settings,
545 * the default font size of a window may affect that of its logical
546 * child windows as well.
547 *
548 * It is customary to assign AG_GlobalKeys(3) shortcuts to those
549 * routines. Most users will expect Ctrl+{Plus,Minus,0} to work.
550 */
551 void
AG_ZoomIn(void)552 AG_ZoomIn(void)
553 {
554 AG_Window *win;
555
556 AG_LockVFS(&agDrivers);
557 if ((win = agWindowFocused) != NULL) {
558 AG_WindowSetZoom(win, win->zoom+1);
559 } else {
560 Verbose("No window is focused for zoom\n");
561 }
562 AG_UnlockVFS(&agDrivers);
563 }
564 void
AG_ZoomOut(void)565 AG_ZoomOut(void)
566 {
567 AG_Window *win;
568
569 AG_LockVFS(&agDrivers);
570 if ((win = agWindowFocused) != NULL) {
571 AG_WindowSetZoom(win, win->zoom-1);
572 } else {
573 Verbose("No window is focused for zoom-out\n");
574 }
575 AG_UnlockVFS(&agDrivers);
576 }
577 void
AG_ZoomReset(void)578 AG_ZoomReset(void)
579 {
580 AG_Window *win;
581
582 AG_LockVFS(&agDrivers);
583 if ((win = agWindowFocused) != NULL) {
584 AG_WindowSetZoom(win, AG_ZOOM_DEFAULT);
585 } else {
586 Verbose("No window is focused for zoom-in\n");
587 }
588 AG_UnlockVFS(&agDrivers);
589 }
590
591 #ifdef AG_LEGACY
592 /*
593 * Initialize Agar with a single-window driver of specified resolution.
594 * As of Agar-1.4, this interface obsolete but kept for backward compat.
595 */
596 int
AG_InitVideo(int w,int h,int depth,Uint flags)597 AG_InitVideo(int w, int h, int depth, Uint flags)
598 {
599 AG_Driver *drv = NULL;
600 AG_DriverClass *dc = NULL;
601 int i;
602
603 if (AG_InitGUIGlobals() == -1) {
604 return (-1);
605 }
606 if (agDriverMw != NULL || agDriverSw != NULL) {
607 AG_SetError("Root driver already initialized");
608 goto fail;
609 }
610 if (depth < 1 || w < 16 || h < 16) {
611 AG_SetError("Resolution too small");
612 goto fail;
613 }
614 if (flags & (AG_VIDEO_OPENGL|AG_VIDEO_OPENGL_OR_SDL)) {
615 for (i = 0; i < agDriverListSize; i++) {
616 dc = agDriverList[i];
617 if (dc->wm == AG_WM_SINGLE &&
618 (dc->flags & AG_DRIVER_OPENGL) &&
619 (drv = AG_DriverOpen(dc)) != NULL)
620 break;
621 }
622 if (i == agDriverListSize) {
623 if (flags & AG_VIDEO_OPENGL_OR_SDL) {
624 for (i = 0; i < agDriverListSize; i++) {
625 dc = agDriverList[i];
626 if (dc->wm == AG_WM_SINGLE &&
627 (dc->flags & AG_DRIVER_SDL) &&
628 (drv = AG_DriverOpen(dc)) != NULL)
629 break;
630 }
631 if (i == agDriverListSize) {
632 AG_SetError("SDL/GL not available");
633 goto fail;
634 }
635 } else {
636 AG_SetError("GL not available");
637 goto fail;
638 }
639 }
640 } else if (flags & AG_VIDEO_SDL) {
641 for (i = 0; i < agDriverListSize; i++) {
642 dc = agDriverList[i];
643 if (dc->wm == AG_WM_SINGLE &&
644 (dc->flags & AG_DRIVER_SDL) &&
645 (drv = AG_DriverOpen(dc)) != NULL)
646 break;
647 }
648 if (i == agDriverListSize) {
649 AG_SetError("SDL not available");
650 goto fail;
651 }
652 } else {
653 for (i = 0; i < agDriverListSize; i++) {
654 dc = agDriverList[i];
655 if (dc->wm == AG_WM_SINGLE &&
656 (drv = AG_DriverOpen(dc)) != NULL)
657 break;
658 }
659 if (i == agDriverListSize) {
660 AG_SetError("No graphics drivers are available");
661 goto fail;
662 }
663 }
664 if (AGDRIVER_SW_CLASS(drv)->openVideo(drv, w,h, depth, flags) == -1) {
665 AG_DriverClose(drv);
666 goto fail;
667 }
668 if (AG_InitGUI(0) == -1) {
669 AG_DriverClose(drv);
670 goto fail;
671 }
672 agDriverOps = dc;
673 agDriverSw = AGDRIVER_SW(drv);
674 return (0);
675 fail:
676 AG_DestroyGUIGlobals();
677 return (-1);
678 }
679 void
AG_DestroyVideo(void)680 AG_DestroyVideo(void)
681 {
682 AG_DestroyGUI();
683 }
684 #endif /* AG_LEGACY */
685