1 /** \file uicommands.c
2 * \brief Simple commands triggered from the menu
3 *
4 * \author Bas Wassink <b.wassink@ziggo.nl>
5 *
6 */
7
8 /*
9 * $VICERES WarpMode all
10 * $VICERES JoyDevice1 -vsid
11 * $VICERES JoyDevice2 -vsid
12 * $VICERES JoyDevice3 -vsid
13 * $VICERES JoyDevice4 -vsid
14 */
15
16 /*
17 * This file is part of VICE, the Versatile Commodore Emulator.
18 * See README for copyright notice.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
33 * 02111-1307 USA.
34 *
35 */
36
37 #include "vice.h"
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <gtk/gtk.h>
42
43 #include "archdep.h"
44 #include "resources.h"
45 #include "debug_gtk3.h"
46 #include "basedialogs.h"
47 #include "drive.h"
48 #include "log.h"
49 #include "machine.h"
50 #include "util.h"
51 #include "vsync.h"
52
53 #if 0
54 #ifdef WIN32_COMPILE
55 # include <windows.h>
56 #endif
57 #endif
58
59 #include "ui.h"
60 #include "uicommands.h"
61 #include "uimachinewindow.h"
62
63
64 /** \brief Swap joysticks
65 *
66 * \param[in] widget widget triggering the event (invalid)
67 * \param[in] user_data extra data for event (unused)
68 *
69 * \return TRUE
70 */
ui_swap_joysticks_callback(GtkWidget * widget,gpointer user_data)71 gboolean ui_swap_joysticks_callback(GtkWidget *widget, gpointer user_data)
72 {
73 int joy1;
74 int joy2;
75
76 resources_get_int("JoyDevice1", &joy1);
77 resources_get_int("JoyDevice2", &joy2);
78 resources_set_int("JoyDevice1", joy2);
79 resources_set_int("JoyDevice2", joy1);
80
81 return TRUE;
82 }
83
84
85 /** \brief Swap userport joysticks
86 *
87 * \param[in] widget widget triggering the event (invalid)
88 * \param[in] user_data extra data for event (unused)
89 *
90 * \return TRUE
91 */
ui_swap_userport_joysticks_callback(GtkWidget * widget,gpointer user_data)92 gboolean ui_swap_userport_joysticks_callback(GtkWidget *widget,
93 gpointer user_data)
94 {
95 int joy3;
96 int joy4;
97
98 resources_get_int("JoyDevice3", &joy3);
99 resources_get_int("JoyDevice4", &joy4);
100 resources_set_int("JoyDevice3", joy4);
101 resources_set_int("JoyDevice4", joy3);
102
103 return TRUE;
104 }
105
106
107 /** \brief Callback for the soft/hard reset items
108 *
109 * \param[in] widget menu item triggering the event (unused)
110 * \param[in] user_data MACHINE_RESET_MODE_SOFT/MACHINE_RESET_MODE_HARD
111 */
ui_machine_reset_callback(GtkWidget * widget,gpointer user_data)112 void ui_machine_reset_callback(GtkWidget *widget, gpointer user_data)
113 {
114 vsync_suspend_speed_eval();
115 machine_trigger_reset(GPOINTER_TO_INT(user_data));
116 }
117
118
119 /** \brief Callback for the drive reset items
120 *
121 * \param[in] widget menu item triggering the event (unused)
122 * \param[in] user_data drive unit number (8-11) (int)
123 */
ui_drive_reset_callback(GtkWidget * widget,gpointer user_data)124 void ui_drive_reset_callback(GtkWidget *widget, gpointer user_data)
125 {
126 vsync_suspend_speed_eval();
127 drive_cpu_trigger_reset(GPOINTER_TO_INT(user_data) - 8);
128 }
129
130
131 /** \brief Ask the user to confirm to exit the emulator if ConfirmOnExit is set
132 *
133 * \return TRUE if the emulator should be exited, FALSE if not
134 */
confirm_exit(void)135 static gboolean confirm_exit(void)
136 {
137 int confirm;
138
139 resources_get_int("ConfirmOnExit", &confirm);
140 if (!confirm) {
141 return TRUE;
142 }
143
144 if (vice_gtk3_message_confirm("Exit VICE",
145 "Do you really wish to exit VICE?")) {
146 return TRUE;
147 }
148 ui_set_ignore_mouse_hide(FALSE);
149 return FALSE;
150 }
151
152
153 /** \brief Callback for the File->Exit menu item
154 *
155 * \param[in] widget menu item triggering the event (unused)
156 * \param[in] user_data unused
157 */
ui_close_callback(GtkWidget * widget,gpointer user_data)158 void ui_close_callback(GtkWidget *widget, gpointer user_data)
159 {
160 if (confirm_exit()) {
161 ui_exit();
162 }
163 }
164
165
166 /** \brief Handler for the "delete-event" of a main window
167 *
168 * \param[in] widget window triggering the event
169 * \param[in] event event details (unused)
170 * \param[in] user_data extra data for the event (unused)
171 *
172 * \return TRUE, if the function returns at all
173 */
ui_main_window_delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)174 gboolean ui_main_window_delete_event(GtkWidget *widget, GdkEvent *event,
175 gpointer user_data)
176 {
177 if (confirm_exit()) {
178 /* if we reach this point, the function doesn't return */
179 ui_exit();
180 }
181 return TRUE;
182 }
183
184
185 /** \brief Callback for the "destroy" event of a main window
186 *
187 * \param[in] widget widget triggering the event
188 * \param[in] user_data extra data for the callback (unused)
189 */
ui_main_window_destroy_callback(GtkWidget * widget,gpointer user_data)190 void ui_main_window_destroy_callback(GtkWidget *widget, gpointer user_data)
191 {
192 GtkWidget *grid;
193
194 debug_gtk3("WINDOW DESTROY called on %p.", widget);
195
196 /*
197 * This should not be needed, destroying a GtkWindow should trigger
198 * destruction of all widgets it contains.
199 */
200 debug_gtk3("Manually calling destroy() on the CRT widgets. This should not"
201 " be necesarry, but right now it is.");
202 grid = gtk_bin_get_child(GTK_BIN(widget));
203 if (grid != NULL) {
204 GtkWidget *crt = gtk_grid_get_child_at(GTK_GRID(grid), 0, 2);
205 if (crt != NULL) {
206 gtk_widget_destroy(crt);
207 }
208 }
209 }
210
211
212 /** \brief Toggle boolean resource from the menu
213 *
214 * Toggles \a resource when a valid.
215 *
216 * \param[in] widget menu item triggering the event
217 * \param[in] resource resource name
218 *
219 * \return TRUE if succesful, FALSE otherwise
220 */
ui_toggle_resource(GtkWidget * widget,gpointer resource)221 gboolean ui_toggle_resource(GtkWidget *widget, gpointer resource)
222 {
223 const char *res = (const char *)resource;
224
225 if (res != NULL) {
226 int new_state;
227
228 /* attempt to toggle resource */
229 if (resources_toggle(res, &new_state) < 0) {
230 debug_gtk3("toggling resource %s failed.", res);
231 return FALSE;
232 }
233 debug_gtk3("resource %s toggled to %s.",
234 res, new_state ? "True" : "False");
235 return TRUE;
236 }
237 return FALSE;
238 }
239
240
241 /** \brief Open the Manual
242 */
ui_open_manual_callback(GtkWidget * widget,gpointer user_data)243 void ui_open_manual_callback(GtkWidget *widget, gpointer user_data)
244 {
245 GError *error = NULL;
246 gboolean res;
247 char *uri;
248 const char *path;
249 gchar *final_uri;
250
251 /*
252 * Gget arch-dependent documentation dir (doesn't contain the HTML docs
253 * on Windows, but that's an other issue to fix.
254 */
255 path = archdep_get_vice_docsdir();
256
257 /* first try opening the pdf */
258 uri = archdep_join_paths(path, "vice.pdf", NULL);
259
260 debug_gtk3("URI before GTK3: %s", uri);
261
262 /*
263 * This should not be used, but rather a helper tool provided by Gtk:
264 * gspawn-winXX-helper-console.exe needs to be installed by the bindist
265 * script.
266 */
267 #if 0
268 #ifdef WIN32_COMPILE
269 /* Windows: the Gtk/GLib stuff fails whatever I do, so let's use actual
270 * Windows code. --compyx
271 */
272 ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOW);
273 /* that's right: no error checking and no fallback to HTML */
274 return;
275 #endif
276 #endif
277
278 final_uri = g_filename_to_uri(uri, NULL, &error);
279 debug_gtk3("final URI (pdf): %s", final_uri);
280 if (final_uri == NULL) {
281 /*
282 * This is a fatal error, if a proper URI can't be built something is
283 * wrong and should be looked at. This is different from failing to
284 * load the PDF or not having a program to show the PDF
285 */
286 log_error(LOG_ERR, "failed to construct a proper URI from '%s',"
287 " not trying the HTML fallback, this is an error that"
288 " should not happen.",
289 uri);
290 g_clear_error(&error);
291 lib_free(uri);
292 lib_free(path);
293 return;
294 }
295
296 debug_gtk3("pdf uri: '%s'.", final_uri);
297 res = gtk_show_uri_on_window(NULL, final_uri, GDK_CURRENT_TIME, &error);
298 if (!res) {
299 vice_gtk3_message_error(
300 "Failed to load PDF: %s.",
301 error != NULL ? error->message : "<no message>");
302 }
303 lib_free(uri);
304 g_free(final_uri);
305 g_clear_error(&error);
306 if (res) {
307 /* We succesfully managed to open the PDF application, but there's no
308 * way to determine if actually loading the PDF in that application
309 * worked. So we simply exit here to avoid also opening a HTML browser
310 * which on Windows at least seems to completely ignore the default and
311 * always starts fucking Internet Explorer.
312 *
313 * Also how do we close the PDF application if we could determine it
314 * failed to load the PDF? We don't get any reference to the application
315 * to be able to terminate it. Gtk3 is awesome!
316 *
317 * -- compyx
318 */
319 lib_free(path);
320 return;
321 }
322
323 /* try opening the html doc */
324 #if defined(WIN32_COMPILE)
325 /* HACK: on windows the html files are in a separate directory */
326 uri = archdep_join_paths(path, "..", "html", "vice_toc.html", NULL);
327 #else
328 uri = archdep_join_paths(path, "vice_toc.html", NULL);
329 #endif
330
331 final_uri = g_filename_to_uri(uri, NULL, &error);
332 if (final_uri == NULL) {
333 /*
334 * This is a fatal error, if a proper URI can't be built something is
335 * wrong and should be looked at. This is different from failing to
336 * load the PDF or not having a program to show the PDF
337 */
338 log_error(LOG_ERR,
339 "failed to construct a proper URI from '%s',"
340 " this is an error that should not happen.",
341 uri);
342 g_free(final_uri);
343 lib_free(uri);
344 lib_free(path);
345 return;
346 }
347
348 /*
349 * On Windows this does not respect the user's preferred browser. That is,
350 * it didn't respect my Firefox but decided to use Internet Explorer,
351 * which is an unspeakable act of cruelty.
352 */
353 debug_gtk3("html uri: '%s'.", final_uri);
354 res = gtk_show_uri_on_window(NULL, final_uri, GDK_CURRENT_TIME, &error);
355 if (!res && error != NULL) {
356 vice_gtk3_message_error("Failed to show URI", error->message);
357 }
358 lib_free(uri);
359 g_free(final_uri);
360 g_clear_error(&error);
361 lib_free(path);
362 }
363