7 #include <gconf/gconf.h>
8 #include <gconf/gconf-client.h>
12 #include "../gui/gconf.h"
14 static GMainContext *mainContext;
15 static GMainLoop *mainLoop;
16 osso_context_t *ossoContext;
18 static volatile enum {
19 STARTUP_COMMAND_INVALID = -1,
20 STARTUP_COMMAND_UNKNOWN = 0,
22 STARTUP_COMMAND_CONTINUE,
23 STARTUP_COMMAND_RESTART,
27 static void createActionMappingsOnly();
28 static void parseGConfKeyMappings(GConfClient* gcc);
30 static gint ossoAppCallback(const gchar *interface, const gchar *method,
31 GArray *arguments, gpointer data, osso_rpc_t *retval)
33 retval->type = DBUS_TYPE_BOOLEAN;
35 if (startupCommand == STARTUP_COMMAND_UNKNOWN) {
36 // Only if we haven't received the startup command yet.
37 printf("Osso: Startup method is: %s\n", method);
39 if (strcmp(method, "game_run") == 0) {
40 startupCommand = STARTUP_COMMAND_RUN;
41 retval->value.b = TRUE;
42 } else if (strcmp(method, "game_continue") == 0) {
43 startupCommand = STARTUP_COMMAND_CONTINUE;
44 retval->value.b = TRUE;
45 } else if (strcmp(method, "game_restart") == 0) {
46 startupCommand = STARTUP_COMMAND_RESTART;
47 retval->value.b = TRUE;
48 } else if (strcmp(method, "game_close") == 0) {
49 // A bit weird, but could happen
50 startupCommand = STARTUP_COMMAND_QUIT;
51 retval->value.b = TRUE;
53 startupCommand = STARTUP_COMMAND_INVALID;
54 retval->value.b = FALSE;
57 if (strcmp(method, "game_close") == 0) {
58 printf("Osso: quitting because of D-Bus close message\n");
59 S9xDoAction(kActionQuit);
60 retval->value.b = TRUE;
62 retval->value.b = FALSE;
69 static void ossoHwCallback(osso_hw_state_t *state, gpointer data)
71 if (state->shutdown_ind) {
72 // Shutting down. Try to quit gracefully.
73 S9xDoAction(kActionQuit);
75 if (Config.saver && state->system_inactivity_ind) {
76 // Screen went off, and power saving is active.
77 S9xDoAction(kActionQuit);
81 /** Called from main(), initializes Glib & libosso stuff if needed. */
84 char *dbusLaunch = getenv("DRNOKSNES_DBUS");
86 if (!dbusLaunch || dbusLaunch[0] != 'y') {
87 // Not launched from GUI, so we don't assume GUI features.
93 g_set_prgname("drnoksnes");
94 g_set_application_name("DrNokSnes");
95 mainContext = g_main_context_default();
96 mainLoop = g_main_loop_new(mainContext, FALSE);
97 ossoContext = osso_initialize("com.javispedro.drnoksnes", "1", 0, 0);
100 fprintf(stderr, "Error initializing libosso\n");
104 // At this point, we still don't know what the startup command is
105 startupCommand = STARTUP_COMMAND_UNKNOWN;
108 ret = osso_rpc_set_default_cb_f(ossoContext, ossoAppCallback, 0);
109 g_warn_if_fail(ret == OSSO_OK);
111 osso_hw_state_t hwStateFlags = { FALSE };
112 hwStateFlags.shutdown_ind = TRUE;
113 hwStateFlags.system_inactivity_ind = TRUE;
114 ret = osso_hw_set_event_cb(ossoContext, &hwStateFlags, ossoHwCallback, 0);
115 g_warn_if_fail(ret == OSSO_OK);
117 printf("Osso: Initialized libosso\n");
120 static osso_return_t invokeLauncherMethod(const char *method, osso_rpc_t *retval)
122 // The launcher seems to assume there is at least one parameter,
123 // even if the method doesn't actually require one.
124 return osso_rpc_run(ossoContext, "com.javispedro.drnoksnes.startup",
125 "/com/javispedro/drnoksnes/startup", "com.javispedro.drnoksnes.startup",
126 method, retval, DBUS_TYPE_INVALID);
131 if (!OssoOk()) return;
133 // Send a goodbye message to the launcher
135 osso_rpc_t retval = { 0 };
136 if (Config.snapshotSave) {
137 // If we saved game state, notify launcher to enter "paused" status.
138 ret = invokeLauncherMethod("game_pause", &retval);
140 ret = invokeLauncherMethod("game_close", &retval);
142 if (ret != OSSO_OK) {
143 printf("Osso: failed to notify launcher\n");
145 osso_rpc_free_val(&retval);
147 osso_deinitialize(ossoContext);
148 g_main_loop_unref(mainLoop);
149 g_main_context_unref(mainContext);
154 /** Called after loading the config file, loads settings from gconf. */
157 if (!OssoOk()) return;
159 GConfClient *gcc = gconf_client_get_default();
161 // GUI only allows fullscreen
162 Config.fullscreen = true;
164 // Get ROM filename from Gconf
165 gchar *romFile = gconf_client_get_string(gcc, kGConfRomFile, 0);
166 if (romFile && strlen(romFile) > 0) {
167 S9xSetRomFile(romFile);
169 printf("Exiting gracefully because there's no ROM in Gconf\n");
174 // Read most of the non-player specific settings
175 Config.saver = gconf_client_get_bool(gcc, kGConfSaver, 0);
176 Config.enableAudio = gconf_client_get_bool(gcc, kGConfSound, 0);
177 Settings.TurboMode = gconf_client_get_bool(gcc, kGConfTurboMode, 0);
178 Settings.Transparency = gconf_client_get_bool(gcc, kGConfTransparency, 0);
179 Settings.DisplayFrameRate = gconf_client_get_bool(gcc, kGConfDisplayFramerate, 0);
181 int frameskip = gconf_client_get_int(gcc, kGConfFrameskip, 0);
182 Settings.SkipFrames = (frameskip > 0 ? frameskip : AUTO_FRAMERATE);
184 gchar *scaler = gconf_client_get_string(gcc, kGConfScaler, 0);
185 if (scaler && strlen(scaler) > 0) {
187 Config.scaler = strdup(scaler);
191 int speedhacks = gconf_client_get_int(gcc, kGConfSpeedhacks, 0);
192 if (speedhacks <= 0) {
193 Settings.HacksEnabled = FALSE;
194 Settings.HacksFilter = FALSE;
195 } else if (speedhacks == 1) {
196 Settings.HacksEnabled = TRUE;
197 Settings.HacksFilter = TRUE;
199 Settings.HacksEnabled = TRUE;
200 Settings.HacksFilter = FALSE;
203 if (Settings.HacksEnabled && !Config.hacksFile) {
204 // Provide a default speedhacks file
205 gchar *romDir = g_path_get_dirname(romFile);
206 if (asprintf(&Config.hacksFile, "%s/snesadvance.dat", romDir)
208 Config.hacksFile = 0; // malloc error.
215 // Read player 1 controls
216 gchar key[kGConfPlayerPathBufferLen];
217 gchar *relKey = key + sprintf(key, kGConfPlayerPath, 1);
219 strcpy(relKey, kGConfPlayerKeyboardEnable);
220 if (gconf_client_get_bool(gcc, key, NULL)) {
221 parseGConfKeyMappings(gcc);
223 createActionMappingsOnly();
226 // Iterate the event loop since we want to catch the initial dbus messages
227 while (startupCommand == STARTUP_COMMAND_UNKNOWN) {
228 // This is not busylooping since we are blocking here
229 g_main_context_iteration(mainContext, TRUE);
232 // The command we received from the launcher will tell us if we have to
233 // load a snapshot file.
234 switch (startupCommand) {
235 case STARTUP_COMMAND_RUN:
236 case STARTUP_COMMAND_RESTART:
237 Config.snapshotLoad = false;
238 Config.snapshotSave = true;
240 case STARTUP_COMMAND_CONTINUE:
241 Config.snapshotLoad = true;
242 Config.snapshotSave = true;
244 case STARTUP_COMMAND_QUIT:
245 Config.snapshotLoad = false;
246 Config.snapshotSave = false;
247 Config.quitting = true;
250 Config.snapshotLoad = false;
251 Config.snapshotSave = false;
255 g_object_unref(G_OBJECT(gcc));
258 /** This is called periodically from the main loop.
259 Iterates the GLib loop to get D-Bus events.
261 void OssoPollEvents()
263 if (!OssoOk()) return;
265 g_main_context_iteration(mainContext, FALSE);
268 typedef struct ButtonEntry {
269 const char * gconf_key;
274 /** This arrays contains generic info about each of the mappable buttons the
276 static const ButtonEntry buttons[] = {
278 #define P(x) SNES_##x##_MASK
279 #define A(x) kAction##x
280 #define BUTTON(description, slug, actions, d, f) \
281 { G_STRINGIFY(slug), actions, false },
282 #define ACTION(description, slug, actions, d, f) \
283 { G_STRINGIFY(slug), actions, true },
286 #include "../gui/buttons.inc"
295 static void createActionMappingsOnly()
297 // Map quit to fullscreen, escape and task switch.
298 Config.action[72] = kActionQuit;
299 Config.action[9] = kActionQuit;
300 Config.action[71] = kActionQuit;
303 static void parseGConfKeyMappings(GConfClient* gcc)
305 // Build player 1 keyboard gconf key relative path
306 gchar key[kGConfPlayerPathBufferLen];
307 gchar *relKey = key + sprintf(key,
308 kGConfPlayerPath kGConfPlayerKeyboardPath "/", 1);
310 // If the user does not map fullscreen or quit
311 bool quit_mapped = false;
313 printf("Hgw: Using gconf key mappings\n");
314 // Thus ignoring config file key mappings
315 ZeroMemory(Config.joypad1Mapping, sizeof(Config.joypad1Mapping));
316 ZeroMemory(Config.action, sizeof(Config.action));
319 for (i = 0; buttons[i].gconf_key; i++) {
320 strcpy(relKey, buttons[i].gconf_key);
321 scancode = gconf_client_get_int(gcc, key, NULL);
323 if (scancode <= 0 || scancode > 255) continue;
325 if (buttons[i].is_action) {
326 Config.action[scancode] |= buttons[i].mask;
327 if (buttons[i].mask & (kActionQuit | kActionToggleFullscreen)) {
331 Config.joypad1Mapping[scancode] |= buttons[i].mask;
335 #if MAEMO && !CONF_EXIT_BUTTON
338 // Newbie user won't know how to quit game.
339 if (!Config.joypad1Mapping[72] && !Config.action[72]) {
340 // Fullscreen key is not mapped, map
341 Config.action[72] = kActionQuit;
344 if (!quit_mapped && !Config.joypad1Mapping[9] && !Config.action[9]) {
345 // Escape key is not mapped, map
346 // But only if we couldn't map quit to fullscreen. Some people
347 // actually want Quit not to be mapped.
348 Config.action[9] = kActionQuit;
352 // Force mapping of fullscreen to Quit if can't map anywhere else.
353 Config.joypad1Mapping[72] = 0;
354 Config.action[72] = kActionQuit;
358 // If task switch key is not mapped, map it to Quit by default.
359 if (!Config.action[71] && !Config.joypad1Mapping[71]) {
360 Config.action[71] = kActionQuit;