new controls dialog; using gconf instead of hgw
[drnoksnes] / platform / hgw.cpp
1 #include <stdio.h>
2 #include <libgen.h>
3 #include <hgw/hgw.h>
4
5 #include "snes9x.h"
6
7 #include <glib.h>
8 #include <gconf/gconf.h>
9 #include <gconf/gconf-client.h>
10
11 #include "platform.h"
12 #include "hgw.h"
13 #include "../gui/gconf.h"
14
15 #define DIE(format, ...) do { \
16                 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
17                 fprintf(stderr, format "\n", ## __VA_ARGS__); \
18                 abort(); \
19         } while (0);
20
21 bool hgwLaunched;
22 static HgwContext *hgw;
23
24 static void createActionMappingsOnly();
25 static void parseGConfKeyMappings(GConfClient* gcc);
26
27 void HgwInit()
28 {
29         // hildon-games-wrapper sets this env variable for itself.
30         char* service = getenv("HGW_EXEC_SERVICE");
31
32         if (!service) {
33                 // Not launched from hildon-games-wrapper
34                 hgwLaunched = false;
35                 return;
36         }
37
38         g_type_init();
39         hgw = hgw_context_init();
40
41         if (!hgw) {
42                 fprintf(stderr, "Error opening hgw context\n");
43                 hgwLaunched = false;
44         }
45
46         hgwLaunched = true;
47         printf("Loading in HGW mode\n");
48 }
49
50 void HgwDeinit()
51 {
52         if (!hgwLaunched) return;
53
54         hgw_context_destroy(hgw,
55                 (Config.snapshotSave ? HGW_BYE_PAUSED : HGW_BYE_INACTIVE));
56
57         hgw = 0;
58 }
59
60 void HgwConfig()
61 {
62         if (!hgwLaunched) return;
63
64         GConfClient *gcc = gconf_client_get_default();
65
66         Config.fullscreen = true;
67
68         char romFile[PATH_MAX + 1];
69         if (hgw_conf_request_string(hgw, kGConfRomFile, romFile) == HGW_ERR_NONE
70                 && strlen(romFile) > 0) {
71                 S9xSetRomFile(romFile);
72         } else {
73                 printf("Exiting gracefully because there's no ROM in Gconf\n");
74                 HgwDeinit();
75                 exit(0);
76         }
77
78         char sound = FALSE;
79         if (hgw_conf_request_bool(hgw, kGConfSound, &sound) == HGW_ERR_NONE) {
80                 Config.enableAudio = sound ? true : false;
81         }
82
83         char turbo = FALSE;
84         if (hgw_conf_request_bool(hgw, kGConfTurboMode, &turbo) == HGW_ERR_NONE) {
85                 Settings.TurboMode = turbo ? TRUE : FALSE;
86         }
87
88         int frameskip = 0;
89         if (hgw_conf_request_int(hgw, kGConfFrameskip, &frameskip) == HGW_ERR_NONE) {
90                 Settings.SkipFrames = (frameskip > 0 ? frameskip : AUTO_FRAMERATE);
91         }
92
93         char transparency = FALSE;
94         if (hgw_conf_request_bool(hgw, kGConfTransparency, &transparency) == HGW_ERR_NONE) {
95                 Settings.Transparency = transparency ? TRUE : FALSE;
96         }
97
98         char scaler[NAME_MAX];
99         if (hgw_conf_request_string(hgw, kGConfScaler, scaler) == HGW_ERR_NONE
100                 && strlen(scaler) > 0) {
101                 free(Config.scaler);
102                 Config.scaler = strdup(scaler);
103         }
104
105         char displayFramerate = FALSE;
106         if (hgw_conf_request_bool(hgw, kGConfDisplayFramerate, &displayFramerate) == HGW_ERR_NONE) {
107                 Settings.DisplayFrameRate = displayFramerate ? TRUE : FALSE;
108         }
109
110 #if TODO
111         char displayControls = FALSE;
112         if (hgw_conf_request_bool(hgw, kGConfDisplayControls, &displayControls) == HGW_ERR_NONE) {
113                 Config.touchscreenShow = displayControls ? true : false;
114         }
115 #endif
116
117         int speedhacks = 0;
118         if (hgw_conf_request_int(hgw, kGConfSpeedhacks, &speedhacks) == HGW_ERR_NONE) {
119                 if (speedhacks <= 0) {
120                         Settings.HacksEnabled = FALSE;
121                         Settings.HacksFilter = FALSE;
122                 } else if (speedhacks == 1) {
123                         Settings.HacksEnabled = TRUE;
124                         Settings.HacksFilter = TRUE;
125                 } else {
126                         Settings.HacksEnabled = TRUE;
127                         Settings.HacksFilter = FALSE;
128                 }
129         }
130         if (Settings.HacksEnabled && !Config.hacksFile) {
131                 // Provide a default speedhacks file
132                 if (asprintf(&Config.hacksFile, "%s/snesadvance.dat", dirname(romFile))
133                                 < 0) {
134                         Config.hacksFile = 0; // malloc error.
135                 }
136                 // remember that dirname garbles romFile.
137         }
138
139         gchar key[kGConfPlayerPathBufferLen];
140         gchar *relKey = key + sprintf(key, kGConfPlayerPath, 1);
141
142         strcpy(relKey, kGConfPlayerKeyboardEnable);
143         if (gconf_client_get_bool(gcc, key, NULL)) {
144                 parseGConfKeyMappings(gcc);
145         } else {
146                 createActionMappingsOnly();
147         }
148
149         HgwStartCommand cmd = hgw_context_get_start_command(hgw);
150         switch (cmd) {
151                 default:
152                 case HGW_COMM_NONE:     // called from libosso
153                 case HGW_COMM_CONT:
154                         Config.snapshotLoad = true;
155                         Config.snapshotSave = true;
156                         break;
157                 case HGW_COMM_RESTART:
158                         Config.snapshotLoad = false;
159                         Config.snapshotSave = true;
160                         break;
161                 case HGW_COMM_QUIT:
162                         // hum, what?
163                         Config.snapshotLoad = false;
164                         Config.snapshotSave = false;
165                         Config.quitting = true;
166                         break;
167         }
168
169         g_object_unref(G_OBJECT(gcc));
170 }
171
172 void HgwPollEvents()
173 {
174         if (!hgwLaunched) return;
175         
176         HgwMessage msg;
177         HgwMessageFlags flags = HGW_MSG_FLAG_NONE;
178         
179         if ( hgw_msg_check_incoming(hgw, &msg, flags) == HGW_ERR_COMMUNICATION ) {
180                 // Message Incoming, process msg
181                 
182                 switch (msg.type) {
183                         case HGW_MSG_TYPE_CBREQ:
184                                 switch (msg.e_val) {
185                                         case HGW_CB_QUIT:
186                                         case HGW_CB_EXIT:
187                                                 Config.quitting = true;
188                                                 break;
189                                 }
190                                 break;
191                         case HGW_MSG_TYPE_DEVSTATE:
192                                 switch (msg.e_val) {
193                                         case HGW_DEVICE_STATE_SHUTDOWN:
194                                                 Config.quitting = true; // try to quit gracefully
195                                                 break;
196                                 }
197                                 break;
198                         default:
199                                 // do nothing
200                                 break;
201                 }
202                 
203                 hgw_msg_free_data(&msg);
204         }
205 }
206
207 // For now, please keep this in sync with ../gui/controls.c
208 typedef struct ButtonEntry {
209         const char * gconf_key;
210         unsigned long mask;
211         bool is_action;
212 } ButtonEntry;
213 #define BUTTON_INITIALIZER(button, name) \
214         { kGConfKeysPath "/" name, SNES_##button##_MASK, false }
215 #define ACTION_INITIALIZER(action, name) \
216         { kGConfKeysPath "/" name, kAction##action, true }
217 #define BUTTON_LAST     \
218         { 0 }
219
220 static const ButtonEntry buttons[] = {
221 #define HELP(...)
222 #define P(x) SNES_##x##_MASK
223 #define A(x) kAction##x
224 #define BUTTON(description, slug, actions, d, f) \
225         { G_STRINGIFY(slug), actions, false },
226 #define ACTION(description, slug, actions, d, f) \
227         { G_STRINGIFY(slug), actions, true },
228 #define LAST \
229         { 0 }
230 #include "../gui/buttons.inc"
231 #undef HELP
232 #undef P
233 #undef A
234 #undef BUTTON
235 #undef ACTION
236 #undef LAST
237 };
238
239 static void createActionMappingsOnly()
240 {
241         // Map quit to fullscreen, escape and task switch.
242         Config.action[72] = kActionQuit;
243         Config.action[9] = kActionQuit;
244         Config.action[71] = kActionQuit;
245 }
246
247 static void parseGConfKeyMappings(GConfClient* gcc)
248 {
249         // Build player 1 keyboard gconf key relative path
250         gchar key[kGConfPlayerPathBufferLen];
251         gchar *relKey = key + sprintf(key,
252                 kGConfPlayerPath kGConfPlayerKeyboardPath "/", 1);
253
254         // If the user does not map fullscreen or quit
255         bool quit_mapped = false;
256
257         printf("Hgw: Using gconf key mappings\n");
258         // Thus ignoring config file key mappings
259         ZeroMemory(Config.joypad1Mapping, sizeof(Config.joypad1Mapping));
260         ZeroMemory(Config.action, sizeof(Config.action));
261
262         int i, scancode;
263         for (i = 0; buttons[i].gconf_key; i++) {
264                 strcpy(relKey, buttons[i].gconf_key);
265                 scancode = gconf_client_get_int(gcc, key, NULL);
266
267                 if (scancode <= 0 || scancode > 255) continue;
268
269                 if (buttons[i].is_action) {
270                         Config.action[scancode] |= buttons[i].mask;
271                         if (buttons[i].mask & (kActionQuit | kActionToggleFullscreen)) {
272                                 quit_mapped = true;
273                         }
274                 } else {
275                         Config.joypad1Mapping[scancode] |= buttons[i].mask;
276                 }
277         }
278
279 #if MAEMO && !CONF_EXIT_BUTTON
280         // Safeguards
281         if (!quit_mapped) {
282                 // Newbie user won't know how to quit game.
283                 if (!Config.joypad1Mapping[72] && !Config.action[72]) {
284                         // Fullscreen key is not mapped, map
285                         Config.action[72] = kActionQuit;
286                         quit_mapped = true;
287                 }
288                 if (!quit_mapped && !Config.joypad1Mapping[9] && !Config.action[9]) {
289                         // Escape key is not mapped, map
290                         // But only if we couldn't map quit to fullscreen. Some people
291                         // actually want Quit not to be mapped.
292                         Config.action[9] = kActionQuit;
293                         quit_mapped = true;
294                 }
295                 if (!quit_mapped) {
296                         // Force mapping of fullscreen to Quit if can't map anywhere else.
297                         Config.joypad1Mapping[72] = 0;
298                         Config.action[72] = kActionQuit;
299                 }
300         }
301
302         // If task switch key is not mapped, map it to Quit by default.
303         if (!Config.action[71] && !Config.joypad1Mapping[71]) {
304                 Config.action[71] = kActionQuit;
305         }
306 #endif
307 }
308