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 /** Called from main(), initializes Glib & libosso stuff if needed. */
72 char *dbusLaunch = getenv("DRNOKSNES_DBUS");
74 if (!dbusLaunch || dbusLaunch[0] != 'y') {
75 // Not launched from GUI, so we don't assume GUI features.
81 mainContext = g_main_context_default();
82 mainLoop = g_main_loop_new(mainContext, FALSE);
83 ossoContext = osso_initialize("com.javispedro.drnoksnes", "1", 0, 0);
86 fprintf(stderr, "Error initializing libosso\n");
90 // At this point, we still don't know what the startup command is
91 startupCommand = STARTUP_COMMAND_UNKNOWN;
94 ret = osso_rpc_set_default_cb_f(ossoContext, ossoAppCallback, 0);
95 g_assert(ret == OSSO_OK);
97 printf("Osso: Initialized libosso\n");
100 static osso_return_t invokeLauncherMethod(const char *method, osso_rpc_t *retval)
102 // The launcher seems to assume there is at least one parameter,
103 // even if the method doesn't actually require one.
104 return osso_rpc_run(ossoContext, "com.javispedro.drnoksnes.startup",
105 "/com/javispedro/drnoksnes/startup", "com.javispedro.drnoksnes.startup",
106 method, retval, DBUS_TYPE_INVALID);
111 if (!OssoOk()) return;
113 // Send a goodbye message to the launcher
115 osso_rpc_t retval = { 0 };
116 if (Config.snapshotSave) {
117 // If we saved game state, notify launcher to enter "paused" status.
118 ret = invokeLauncherMethod("game_pause", &retval);
120 ret = invokeLauncherMethod("game_close", &retval);
122 if (ret != OSSO_OK) {
123 printf("Osso: failed to notify launcher\n");
125 osso_rpc_free_val(&retval);
127 osso_deinitialize(ossoContext);
128 g_main_loop_unref(mainLoop);
129 g_main_context_unref(mainContext);
134 /** Called after loading the config file, loads settings from gconf. */
137 if (!OssoOk()) return;
139 GConfClient *gcc = gconf_client_get_default();
141 // GUI only allows fullscreen
142 Config.fullscreen = true;
144 // Get ROM filename from Gconf
145 gchar *romFile = gconf_client_get_string(gcc, kGConfRomFile, 0);
146 if (romFile && strlen(romFile) > 0) {
147 S9xSetRomFile(romFile);
149 printf("Exiting gracefully because there's no ROM in Gconf\n");
154 // Read most of the non-player specific settings
155 Config.enableAudio = gconf_client_get_bool(gcc, kGConfSound, 0);
156 Settings.TurboMode = gconf_client_get_bool(gcc, kGConfTurboMode, 0);
157 Settings.Transparency = gconf_client_get_bool(gcc, kGConfTransparency, 0);
158 Settings.DisplayFrameRate = gconf_client_get_bool(gcc, kGConfDisplayFramerate, 0);
160 int frameskip = gconf_client_get_int(gcc, kGConfFrameskip, 0);
161 Settings.SkipFrames = (frameskip > 0 ? frameskip : AUTO_FRAMERATE);
163 gchar *scaler = gconf_client_get_string(gcc, kGConfScaler, 0);
164 if (scaler && strlen(scaler) > 0) {
166 Config.scaler = strdup(scaler);
170 int speedhacks = gconf_client_get_int(gcc, kGConfSpeedhacks, 0);
171 if (speedhacks <= 0) {
172 Settings.HacksEnabled = FALSE;
173 Settings.HacksFilter = FALSE;
174 } else if (speedhacks == 1) {
175 Settings.HacksEnabled = TRUE;
176 Settings.HacksFilter = TRUE;
178 Settings.HacksEnabled = TRUE;
179 Settings.HacksFilter = FALSE;
182 if (Settings.HacksEnabled && !Config.hacksFile) {
183 // Provide a default speedhacks file
184 gchar *romDir = g_path_get_dirname(romFile);
185 if (asprintf(&Config.hacksFile, "%s/snesadvance.dat", romDir)
187 Config.hacksFile = 0; // malloc error.
194 gchar key[kGConfPlayerPathBufferLen];
195 gchar *relKey = key + sprintf(key, kGConfPlayerPath, 1);
197 strcpy(relKey, kGConfPlayerKeyboardEnable);
198 if (gconf_client_get_bool(gcc, key, NULL)) {
199 parseGConfKeyMappings(gcc);
201 createActionMappingsOnly();
204 // Iterate the event loop since we want to catch the initial dbus messages
205 while (startupCommand == STARTUP_COMMAND_UNKNOWN) {
206 // This is not busylooping since we are blocking here
207 g_main_context_iteration(mainContext, TRUE);
210 switch (startupCommand) {
211 case STARTUP_COMMAND_RUN:
212 case STARTUP_COMMAND_RESTART:
213 Config.snapshotLoad = false;
214 Config.snapshotSave = true;
216 case STARTUP_COMMAND_CONTINUE:
217 Config.snapshotLoad = true;
218 Config.snapshotSave = true;
220 case STARTUP_COMMAND_QUIT:
221 Config.snapshotLoad = false;
222 Config.snapshotSave = false;
223 Config.quitting = true;
226 Config.snapshotLoad = false;
227 Config.snapshotSave = false;
231 g_object_unref(G_OBJECT(gcc));
234 void OssoPollEvents()
236 if (!OssoOk()) return;
238 //g_main_context_iteration(mainContext, FALSE);
241 typedef struct ButtonEntry {
242 const char * gconf_key;
247 /** This arrays contains generic info about each of the mappable buttons the
249 static const ButtonEntry buttons[] = {
251 #define P(x) SNES_##x##_MASK
252 #define A(x) kAction##x
253 #define BUTTON(description, slug, actions, d, f) \
254 { G_STRINGIFY(slug), actions, false },
255 #define ACTION(description, slug, actions, d, f) \
256 { G_STRINGIFY(slug), actions, true },
259 #include "../gui/buttons.inc"
268 static void createActionMappingsOnly()
270 // Map quit to fullscreen, escape and task switch.
271 Config.action[72] = kActionQuit;
272 Config.action[9] = kActionQuit;
273 Config.action[71] = kActionQuit;
276 static void parseGConfKeyMappings(GConfClient* gcc)
278 // Build player 1 keyboard gconf key relative path
279 gchar key[kGConfPlayerPathBufferLen];
280 gchar *relKey = key + sprintf(key,
281 kGConfPlayerPath kGConfPlayerKeyboardPath "/", 1);
283 // If the user does not map fullscreen or quit
284 bool quit_mapped = false;
286 printf("Hgw: Using gconf key mappings\n");
287 // Thus ignoring config file key mappings
288 ZeroMemory(Config.joypad1Mapping, sizeof(Config.joypad1Mapping));
289 ZeroMemory(Config.action, sizeof(Config.action));
292 for (i = 0; buttons[i].gconf_key; i++) {
293 strcpy(relKey, buttons[i].gconf_key);
294 scancode = gconf_client_get_int(gcc, key, NULL);
296 if (scancode <= 0 || scancode > 255) continue;
298 if (buttons[i].is_action) {
299 Config.action[scancode] |= buttons[i].mask;
300 if (buttons[i].mask & (kActionQuit | kActionToggleFullscreen)) {
304 Config.joypad1Mapping[scancode] |= buttons[i].mask;
308 #if MAEMO && !CONF_EXIT_BUTTON
311 // Newbie user won't know how to quit game.
312 if (!Config.joypad1Mapping[72] && !Config.action[72]) {
313 // Fullscreen key is not mapped, map
314 Config.action[72] = kActionQuit;
317 if (!quit_mapped && !Config.joypad1Mapping[9] && !Config.action[9]) {
318 // Escape key is not mapped, map
319 // But only if we couldn't map quit to fullscreen. Some people
320 // actually want Quit not to be mapped.
321 Config.action[9] = kActionQuit;
325 // Force mapping of fullscreen to Quit if can't map anywhere else.
326 Config.joypad1Mapping[72] = 0;
327 Config.action[72] = kActionQuit;
331 // If task switch key is not mapped, map it to Quit by default.
332 if (!Config.action[71] && !Config.joypad1Mapping[71]) {
333 Config.action[71] = kActionQuit;