Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
gui_gtk.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  ~/xemu/gui/gui_gtk.c: UI implementation for GTK+3 of Xemu's UI abstraction layer
3  Copyright (C)2016-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 
20 /* ------------------ LINUX/UNIX STUFFS based on GTK --------------- */
21 
22 
23 /* Note: this whole stuff is very confusing. This is because GTK makes it very
24  hard to be used as some 'aux lib' and not the main heart of the project.
25  so many dirty things must be played, and even this way you'll get stupid
26  GTK messages even during run-time, like dialog boxes without parent, sure
27  I have NO parent, why it is so important to tell (as parent window is SDL
28  not GTK ..) */
29 
30 #include <gtk/gtk.h>
31 
32 #define USE_OLD_GTK_POPUP
33 
34 static int _gtkgui_active = 0;
35 static int _gtkgui_popup_is_open = 0;
36 
37 static struct {
40  int problem;
41 } xemugtkmenu;
42 
43 
44 #ifndef GUI_HAS_POPUP
45 #define GUI_HAS_POPUP
46 #endif
47 
48 static int xemugtkgui_iteration ( void )
49 {
50  if (XEMU_UNLIKELY(_gtkgui_active && is_xemugui_ok)) {
51  int n = 0;
52  while (gtk_events_pending()) {
53  gtk_main_iteration();
54  n++;
55  }
56  if (n > 0)
57  DEBUGGUI("GUI: GTK used %d iterations." NL, n);
58  if (n == 0 && _gtkgui_active == 2) {
59  _gtkgui_active = 0;
60  DEBUGGUI("GUI: stopping GTK3 iterator" NL);
61  }
62  return n;
63  } else
64  return 0;
65 }
66 
67 
68 static void xemugtkgui_shutdown ( void );
69 
70 #ifndef XEMU_NO_SDL_DIALOG_OVERRIDE
71 static int SDL_ShowSimpleMessageBox_xemuguigtk ( Uint32 flags, const char *title, const char *message, SDL_Window *window );
72 static int SDL_ShowMessageBox_xemuguigtk ( const SDL_MessageBoxData* messageboxdata, int *buttonid );
73 #endif
74 
75 static int xemugtkgui_init ( void )
76 {
77 #ifdef XEMU_ARCH_UNIX
78  if (sdl_on_x11) {
79  // Workaround: on Wayland, it's possible that SDL uses x11, but the GUI (with GTK) would use Wayland, mixing x11 and wayland within the same app, isn't a good idea
80  // thus we try to force x11 for GTK (better say GDK as its backend) via an environment variable set here, if we detect SDL uses x11
81  static const char gdk_backend_var_name[] = "GDK_BACKEND";
82  static const char gdk_backend_var_value[] = "x11";
83  DEBUGPRINT("GTK: setting environment variable %s=%s to avoid possible GTK backend mismatch with SDL" NL, gdk_backend_var_name, gdk_backend_var_value);
84  setenv(gdk_backend_var_name, gdk_backend_var_value, 1);
85  }
86 #endif
87  is_xemugui_ok = 0;
88  _gtkgui_popup_is_open = 0;
89  _gtkgui_active = 0;
90  if (!gtk_init_check(NULL, NULL)) {
91  DEBUGGUI("GUI: GTK3 cannot be initialized, no GUI is available ..." NL);
92  ERROR_WINDOW("Cannot initialize GTK");
93  return 1;
94  }
95  is_xemugui_ok = 1;
96  xemugtkmenu.num_of_menus = 0;
97  _gtkgui_active = 2;
98  int n = xemugtkgui_iteration();
99  DEBUGPRINT("GUI: GTK3 initialized, %d iterations." NL, n); // consume possible pending (if any?) GTK stuffs after initialization - maybe not needed at all?
100  atexit(xemugtkgui_shutdown);
101 #ifndef XEMU_NO_SDL_DIALOG_OVERRIDE
102  // override callback for SDL_ShowSimpleMessageBox_custom to be implemented by GTK, from this point
103  SDL_ShowSimpleMessageBox_custom = SDL_ShowSimpleMessageBox_xemuguigtk;
104  SDL_ShowMessageBox_custom = SDL_ShowMessageBox_xemuguigtk;
105 #endif
106  return 0;
107 }
108 
109 
110 static void xemugtkgui_shutdown ( void )
111 {
112  if (!is_xemugui_ok)
113  return;
114  xemugtkgui_iteration();
115  // gtk_main_quit();
116  is_xemugui_ok = 0;
117  DEBUGGUI("GUI: GTK3 end" NL);
118 }
119 
120 
121 static int _gtkgui_bgtask_running_want = 0;
122 static int _gtkgui_bgtask_running_status = 0;
123 static int _gtkgui_bgtask_callback ( void *unused ) {
124  // This is the whole point of this g_timeout_add callback:
125  // to have something receives SDL (!!) events while GTK is blocking,
126  // thus like X11 Window System would not yell about our main SDL app being dead ...
127  //xemu_drop_events();
128  SDL_Event event;
129  while (SDL_PollEvent(&event))
130  ;
131  if (_gtkgui_bgtask_running_want) {
132  _gtkgui_bgtask_running_status = 1;
133  DEBUGGUI("GUI: bgtask is active" NL);
134  return TRUE;
135  } else {
136  _gtkgui_bgtask_running_status = 0;
137  DEBUGGUI("GUI: bgtask is inactive" NL);
138  return FALSE; // returning FALSE will cause GTK/GLIB to remove the callback of g_timeout_add()
139  }
140 }
141 static void _gtkgui_bgtask_set ( void ) {
142  if (_gtkgui_bgtask_running_want)
143  return;
144  _gtkgui_bgtask_running_want = 1;
145  _gtkgui_bgtask_running_status = 1;
146  g_timeout_add(100, _gtkgui_bgtask_callback, NULL); // set callback, first arg: 1/1000th of seconds
147 }
148 static void _gtkgui_bgtask_clear ( void ) {
149  if (!_gtkgui_bgtask_running_want)
150  return;
151  _gtkgui_bgtask_running_want = 0;
152  while (_gtkgui_bgtask_running_status || gtk_events_pending()) {
153  gtk_main_iteration();
154  usleep(10000);
155  }
156  //xemu_drop_events();
157 }
158 
159 
160 
161 static GtkFileChooserConfirmation xemugtkgui_confirm_overwrite ( GtkFileChooser *chooser, gpointer data ) {
162  return GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM; // use the default dialog
163 }
164 
165 // Currently it's a "blocking" implemtation, unlike to pop-up menu
166 static int xemugtkgui_file_selector ( int dialog_mode, const char *dialog_title, char *default_dir, char *selected, int path_max_size )
167 {
168  if (!is_xemugui_ok)
169  return 1;
170  _gtkgui_active = 1;
171  const char *button_text;
172  GtkFileChooserAction action;
173  switch (dialog_mode & 3) {
174  case XEMUGUI_FSEL_OPEN:
175  action = GTK_FILE_CHOOSER_ACTION_OPEN;
176  button_text = "_Open";
177  break;
178  case XEMUGUI_FSEL_SAVE:
179  action = GTK_FILE_CHOOSER_ACTION_SAVE;
180  button_text = "_Save";
181  break;
182  default:
183  FATAL("Invalid mode for UI selector: %d", dialog_mode & 3);
184  }
185  GtkWidget *dialog = gtk_file_chooser_dialog_new(
186  dialog_title,
187  NULL, // parent window! We have NO GTK parent window, and it seems GTK is lame, that dumps warning, but we can't avoid this ...
188  action,
189  "_Cancel",
190  GTK_RESPONSE_CANCEL,
191  button_text,
192  GTK_RESPONSE_ACCEPT,
193  NULL
194  );
195  if (default_dir)
196  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), default_dir);
197  *selected = '\0';
198  if ((dialog_mode & 3) == XEMUGUI_FSEL_SAVE) {
199  gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
200  g_signal_connect(dialog, "confirm-overwrite", G_CALLBACK(xemugtkgui_confirm_overwrite), NULL);
201  }
202  _gtkgui_bgtask_set();
203  gint res = gtk_dialog_run(GTK_DIALOG(dialog));
204  _gtkgui_bgtask_clear();
205  if (res == GTK_RESPONSE_ACCEPT) {
206  char *filename;
207  filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
208  if (strlen(filename) < path_max_size) {
209  strcpy(selected, filename);
210  store_dir_from_file_selection(default_dir, filename, dialog_mode);
211  } else
212  res = GTK_RESPONSE_CANCEL;
213  g_free(filename);
214  }
215  gtk_widget_destroy(dialog);
216  while (gtk_events_pending())
217  gtk_main_iteration();
219  _gtkgui_active = 2;
220  return res != GTK_RESPONSE_ACCEPT;
221 }
222 
223 
224 
225 
226 static void _gtkgui_destroy_menu ( void )
227 {
228  // FIXME: I'm still not sure, GTK would destroy all the children menu etc, or I need to play this game here.
229  // If this is not needed, in fact, the whole xemugtkmenu is unneeded, and all operations on it throughout this file!!
230  while (xemugtkmenu.num_of_menus > 0) {
231  gtk_widget_destroy(xemugtkmenu.menus[--xemugtkmenu.num_of_menus]);
232  DEBUGGUI("GUI: destroyed menu #%d at %p" NL, xemugtkmenu.num_of_menus, xemugtkmenu.menus[xemugtkmenu.num_of_menus]);
233  }
234  xemugtkmenu.num_of_menus = 0;
235 }
236 
237 
238 
239 static void _gtkgui_callback ( const struct menu_st *item )
240 {
241  _gtkgui_destroy_menu();
242  //gtk_widget_destroy(_gtkgui_popup);
243  //_gtkgui_popup = NULL;
244  DEBUGGUI("GUI: menu point \"%s\" has been activated." NL, item->name);
245  ((xemugui_callback_t)(item->handler))(item, NULL);
246 }
247 
248 
249 static GtkWidget *_gtkgui_recursive_menu_builder ( const struct menu_st desc[], const char *parent_name)
250 {
251  if (xemugtkmenu.num_of_menus >= XEMUGUI_MAX_SUBMENUS) {
252  DEBUGPRINT("GUI: Too many submenus (max=%d)" NL, XEMUGUI_MAX_SUBMENUS);
253  goto PROBLEM;
254  }
255  GtkWidget *menu = gtk_menu_new();
256  xemugtkmenu.menus[xemugtkmenu.num_of_menus++] = menu;
257  for (int a = 0; desc[a].name; a++) {
258  int type = desc[a].type;
259  // Some sanity checks:
260  if (
261  ((type & 0xFF) != XEMUGUI_MENUID_SUBMENU && !desc[a].handler) ||
262  ((type & 0xFF) == XEMUGUI_MENUID_SUBMENU && (desc[a].handler || !desc[a].user_data)) ||
263  !desc[a].name
264  ) {
265  DEBUGPRINT("GUI: invalid menu entry found, skipping it (item #%d of menu \"%s\")" NL, a, parent_name);
266  continue;
267  }
268  GtkWidget *item = NULL;
269  switch (type & 0xFF) {
271  item = gtk_menu_item_new_with_label(desc[a].name);
272  if (!item)
273  goto PROBLEM;
274  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
275  // submenus use the user_data as the submenu menu_st struct pointer!
276  GtkWidget *submenu = _gtkgui_recursive_menu_builder(desc[a].user_data, desc[a].name); // who does not like recursion, seriously? :-)
277  if (!submenu)
278  goto PROBLEM;
279  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
280  break;
282  if ((type & XEMUGUI_MENUFLAG_QUERYBACK)) {
283  DEBUGGUI("GUI: query-back for \"%s\"" NL, desc[a].name);
284  ((xemugui_callback_t)(desc[a].handler))(&desc[a], &type);
285  }
286  if ((type & XEMUGUI_MENUFLAG_HIDDEN))
287  continue;
289  item = gtk_check_menu_item_new_with_label(desc[a].name);
290  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), (type & XEMUGUI_MENUFLAG_CHECKED));
291  } else
292  item = gtk_menu_item_new_with_label(desc[a].name);
293  if (!item)
294  goto PROBLEM;
295  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
296  g_signal_connect_swapped(
297  item,
298  "activate",
299  G_CALLBACK(_gtkgui_callback),
300  (gpointer)&desc[a]
301  );
302  break;
303  default:
304  DEBUGPRINT("GUI: invalid menu item type: %d" NL, type & 0xFF);
305  break;
306  }
307  if (item) {
308  gtk_widget_show(item);
309  if ((type & XEMUGUI_MENUFLAG_SEPARATOR)) {
310  // if a menu item is flagged with separator, then a separator must be added to, after the given item
311  item = gtk_separator_menu_item_new();
312  if (!item)
313  goto PROBLEM;
314  gtk_widget_show(item);
315  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
316  }
317  }
318  }
319  gtk_widget_show(menu);
320  return menu;
321 PROBLEM:
322  xemugtkmenu.problem = 1;
323  return NULL;
324 }
325 
326 
327 static GtkWidget *_gtkgui_create_menu ( const struct menu_st desc[] )
328 {
329  _gtkgui_destroy_menu();
330  xemugtkmenu.problem = 0;
331  GtkWidget *menu = _gtkgui_recursive_menu_builder(desc, XEMUGUI_MAINMENU_NAME);
332  if (!menu || xemugtkmenu.problem) {
333  _gtkgui_destroy_menu();
334  return NULL;
335  } else
336  return menu;
337 }
338 
339 
340 static void _gtkgui_disappear ( const char *signal_name )
341 {
342  // Basically we don't want to waste CPU time in GTK for the iterator (ie event loop) if you
343  // don't need it. So when pop-up menu deactivated, this callback is called, which sets _gtkgui_active to 2.
344  // this is a signal for the iterator to stop itself if there was no events processed once at its run
345  DEBUGGUI("GUI: requesting iterator stop on g-signal \"%s\"" NL, signal_name);
346  // Unfortunately, we can't destroy widget here, since it makes callback never executed :( Oh main, GTK is hard :-O
347  _gtkgui_active = 2;
348  _gtkgui_popup_is_open = 0;
349 }
350 
351 
352 #ifndef USE_OLD_GTK_POPUP
353 #include <gdk/gdkx.h>
354 #include <SDL_syswm.h>
355 static GdkWindow *super_ugly_gtk_hack ( void )
356 {
357  if (!sdl_win)
358  return NULL;
359  SDL_SysWMinfo info;
360  SDL_VERSION(&info.version);
361  SDL_GetWindowWMInfo(sdl_win, &info);
362  if (info.subsystem != SDL_SYSWM_X11)
363  ERROR_WINDOW("Sorry, it won't work, GTK GUI is supported only on top of X11, because of GTK3 makes it no possible to get uniform window-ID from non-GTK window.");
364  //return gdk_x11_window_lookup_for_display(info.info.x11.display, info.info.x11.window);
365  //GdkWindow *gwin = gdk_x11_window_lookup_for_display(gdk_display_get_default(), info.info.x11.window);
366  GdkDisplay *gdisp = gdk_x11_lookup_xdisplay(info.info.x11.display);
367  if (!gdisp) {
368  DEBUGGUI("GUI: gdk_x11_lookup_xdisplay() failed :( reverting to gdk_display_get_default() ..." NL);
369  gdisp = gdk_display_get_default();
370  }
371  GdkWindow *gwin = gdk_x11_window_foreign_new_for_display(
372  //gdk_display_get_default(),
373  //gdk_x11_lookup_xdisplay(info.info.x11.display),
374  gdisp,
375  info.info.x11.window
376  );
377  DEBUGPRINT("GUI: gwin = %p" NL, gwin);
378  return gwin;
379 }
380 #endif
381 
382 
383 static int xemugtkgui_popup ( const struct menu_st desc[] )
384 {
385  static const char disappear_signal[] = "deactivate";
386  if (_gtkgui_popup_is_open) {
387  DEBUGGUI("GUI: trying to enter popup mode, while we're already there" NL);
388  return 0;
389  }
390  if (!is_xemugui_ok /*|| gtk_menu_problem*/) {
391  DEBUGGUI("GUI: MENU: GUI was not successfully initialized yet, or GTK menu creation problem occured back to the first attempt" NL);
392  return 1;
393  }
394  _gtkgui_active = 1;
395  GtkWidget *menu = _gtkgui_create_menu(desc);
396  if (!menu) {
397  _gtkgui_active = 0;
398  ERROR_WINDOW("Could not build GTK pop-up menu :(");
399  return 1;
400  }
401  // this signal will be fired, to request iterator there, since the menu should be run "in the background" unlike the file selector window ...
402  g_signal_connect_swapped(menu, disappear_signal, G_CALLBACK(_gtkgui_disappear), (gpointer)disappear_signal);
403  // FIXME: yes, I should use gtk_menu_popup_at_pointer() as this function is deprecated already!
404  // however that function does not work since the event parameter being NULL causes not to display anything
405  // I guess it's because there is no "parent" for the pop-up menu, as this is not a GTK app, just using the pop-up ...
406 #ifdef USE_OLD_GTK_POPUP
407  gtk_menu_popup(
408  GTK_MENU(menu),
409  NULL, NULL, NULL,
410  NULL, 0, 0
411  );
412 #else
413  GdkEventButton fake_event = {
414  .type = GDK_BUTTON_PRESS,
415  //.window = gdk_x11_window_foreign_new_for_display(
416  //.window = gdk_x11_window_lookup_for_display(
417  // gdk_display_get_default(),
418  // NULL
419  //)
420  .window = super_ugly_gtk_hack()
421  };
422  gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent*)&fake_event);
423 #endif
424  _gtkgui_popup_is_open = 1;
425  xemugtkgui_iteration();
426  return 0;
427 }
428 
429 
430 #if 0
431 static int _xemugtkgui_info_window_response;
432 static void _xemugtkgui_info_window_response_cb (GtkDialog *dialog, gint response, gpointer user_data) {
433  _xemugtkgui_info_window_response = response;
434 }
435 #endif
436 static int xemugtkgui_info_window ( GtkMessageType msg_class, const char *msg, const char *msg2 )
437 {
438  GtkWidget* dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, msg_class, GTK_BUTTONS_OK, "%s", msg);
439  if (!dialog)
440  return 1;
441  if (msg2 && *msg2)
442  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", msg2);
443  _gtkgui_bgtask_set();
444  gtk_dialog_run(GTK_DIALOG(dialog));
445  _gtkgui_bgtask_clear();
446 #if 0
447  g_signal_connect_swapped(dialog, "response", G_CALLBACK(_xemugtkgui_info_window_response_cb), NULL);
448  _xemugtkgui_info_window_response = 0;
449  gtk_widget_show(dialog);
450  while (!_xemugtkgui_info_window_response) {
451  while (gtk_events_pending())
452  gtk_main_iteration();
453  usleep(10000);
455  }
456 #endif
457  gtk_widget_destroy(dialog);
458  while (gtk_events_pending())
459  gtk_main_iteration();
460  return 0;
461 }
462 static int xemugtkgui_info ( int sdl_class, const char *msg )
463 {
464  GtkMessageType msg_class;
465  const char *title;
466  switch (sdl_class) {
467  case SDL_MESSAGEBOX_INFORMATION:
468  title = "Xemu";
469  msg_class = GTK_MESSAGE_INFO;
470  break;
471  case SDL_MESSAGEBOX_WARNING:
472  title = "Xemu warning";
473  msg_class = GTK_MESSAGE_WARNING;
474  break;
475  case SDL_MESSAGEBOX_ERROR:
476  title = "Xemu error";
477  msg_class = GTK_MESSAGE_ERROR;
478  break;
479  default:
480  title = "Xemu ???";
481  msg_class = GTK_MESSAGE_OTHER;
482  break;
483  }
484  return xemugtkgui_info_window(msg_class, title, msg);
485 }
486 
487 #ifndef XEMU_NO_SDL_DIALOG_OVERRIDE
488 static int SDL_ShowSimpleMessageBox_xemuguigtk ( Uint32 flags, const char *title, const char *message, SDL_Window *window )
489 {
490  if (is_xemugui_ok) {
491  if (!xemugtkgui_info(flags, message))
492  return 0;
493  else
494  DEBUGPRINT("GUI: SDL_ShowSimpleMessageBox_xemuguigtk() has problems, reverting to SDL_ShowSimpleMessageBox()" NL);
495  } else
496  DEBUGPRINT("GUI: not initialized yet, SDL_ShowSimpleMessageBox_xemuguigtk() reverts to SDL_ShowSimpleMessageBox()" NL);
497  if (!SDL_ShowSimpleMessageBox(flags, title, message, window))
498  return 0;
499  DEBUGPRINT("GUI: SDL_ShowSimpleMessageBox() error: %s" NL, SDL_GetError());
500  return -1;
501 }
502 static int SDL_ShowMessageBox_xemuguigtk ( const SDL_MessageBoxData *box, int *buttonid )
503 {
504  if (!is_xemugui_ok) {
505  DEBUGPRINT("GUI: not initialized yet, SDL_ShowMessageBox_xemuguigtk() reverts to SDL_ShowMessageBox()" NL);
506  goto sdl;
507  }
508  if (XEMU_UNLIKELY(box->numbuttons < 1))
509  FATAL("Less than one button for %s?!", __func__);
510  GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", "Xemu question");
511  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", box->message);
512  gtk_window_set_focus(GTK_WINDOW(dialog), NULL);
513  int escape_default_value = -1;
514  GtkWidget *return_default_button = NULL;
515  for (int a = 0; a < box->numbuttons; a++) {
516  GtkWidget *button = gtk_dialog_add_button(GTK_DIALOG(dialog), box->buttons[a].text, a);
517  if ((box->buttons[a].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) || escape_default_value < 0)
518  escape_default_value = a;
519  if ((box->buttons[a].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) || !return_default_button)
520  return_default_button = button;
521  }
522 #if 0
523  for (int a = 0; a < 10; a++) {
524  char name[10];
525  sprintf(name, "Element-%d", a);
526  gtk_dialog_add_button(GTK_DIALOG(dialog), name, box->numbuttons + a);
527  }
528 #endif
529  gtk_widget_set_can_default(return_default_button, TRUE);
530  gtk_window_set_default(GTK_WINDOW(dialog), return_default_button);
531  _gtkgui_bgtask_set();
532  gint res = gtk_dialog_run(GTK_DIALOG(dialog));
533  _gtkgui_bgtask_clear();
534  gtk_widget_destroy(dialog);
535  //DEBUGPRINT("GUI: GTK RES = %d" NL, res);
536  if (res < 0) {
537  // FIXME: not all negative error codes mean escape the dialog box, maybe only -4? what about the others??
538  res = escape_default_value;
539  }
540  while (gtk_events_pending())
541  gtk_main_iteration();
542  //xemu_drop_events();
543  *buttonid = res;
544  return 0;
545 sdl:
546  return SDL_ShowMessageBox(box, buttonid);
547 }
548 #endif
549 
550 static const struct xemugui_descriptor_st xemugtkgui_descriptor = {
551  .name = "gtk",
552  .description = "GTK3 based Xemu UI implementation",
553  .init = xemugtkgui_init,
554  .shutdown = xemugtkgui_shutdown,
555  .iteration = xemugtkgui_iteration,
556  .file_selector = xemugtkgui_file_selector,
557  .popup = xemugtkgui_popup,
558  .info = xemugtkgui_info
559 };
num_of_menus
int num_of_menus
Definition: gui_gtk.c:38
menu_st
Definition: emutools_gui.h:65
XEMUGUI_MENUFLAG_UNCHECKED
#define XEMUGUI_MENUFLAG_UNCHECKED
Definition: emutools_gui.h:41
sdl_win
SDL_Window * sdl_win
Definition: screen.c:43
flags
Uint8 flags
Definition: z8k1.c:126
XEMUGUI_MAX_SUBMENUS
#define XEMUGUI_MAX_SUBMENUS
Definition: emutools_gui.h:45
menu_st::type
int type
Definition: emutools_gui.h:67
menu_st::handler
const xemugui_callback_t handler
Definition: emutools_gui.h:68
SDL_ShowSimpleMessageBox_custom
int(* SDL_ShowSimpleMessageBox_custom)(Uint32, const char *, const char *, SDL_Window *)
Definition: emutools.c:62
xemu_drop_events
#define xemu_drop_events
Definition: gui.c:19
XEMUGUI_MENUID_CALLABLE
#define XEMUGUI_MENUID_CALLABLE
Definition: emutools_gui.h:30
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
sdl_on_x11
int sdl_on_x11
Definition: emutools.c:81
xemugui_callback_t
void(* xemugui_callback_t)(const struct menu_st *desc, int *query)
Definition: emutools_gui.h:63
xemugui_descriptor_st::name
const char * name
Definition: emutools_gui.c:45
XEMUGUI_MENUFLAG_QUERYBACK
#define XEMUGUI_MENUFLAG_QUERYBACK
Definition: emutools_gui.h:40
XEMUGUI_FSEL_SAVE
#define XEMUGUI_FSEL_SAVE
Definition: emutools_gui.h:27
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
NL
#define NL
Definition: fat32.c:37
XEMUGUI_FSEL_OPEN
#define XEMUGUI_FSEL_OPEN
Definition: emutools_gui.h:26
xemugui_descriptor_st
Definition: emutools_gui.c:44
menu_st::name
const char * name
Definition: emutools_gui.h:66
XEMUGUI_MENUID_SUBMENU
#define XEMUGUI_MENUID_SUBMENU
Definition: emutools_gui.h:31
SDL_ShowMessageBox_custom
int(* SDL_ShowMessageBox_custom)(const SDL_MessageBoxData *, int *)
Definition: emutools.c:63
XEMUGUI_MENUFLAG_HIDDEN
#define XEMUGUI_MENUFLAG_HIDDEN
Definition: emutools_gui.h:42
name
const char * name
Definition: joystick.c:46
problem
int problem
Definition: gui_gtk.c:40
is_xemugui_ok
int is_xemugui_ok
Definition: emutools_gui.c:22
XEMUGUI_MENUFLAG_CHECKED
#define XEMUGUI_MENUFLAG_CHECKED
Definition: emutools_gui.h:39
FATAL
#define FATAL(...)
Definition: xep128.h:117
XEMUGUI_MAINMENU_NAME
#define XEMUGUI_MAINMENU_NAME
Definition: emutools_gui.h:52
button
Uint32 button
Definition: joystick.c:43
menus
GtkWidget * menus[XEMUGUI_MAX_SUBMENUS]
Definition: gui_gtk.c:39
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
DEBUGGUI
#define DEBUGGUI
Definition: emutools_gui.h:22
XEMUGUI_MENUFLAG_SEPARATOR
#define XEMUGUI_MENUFLAG_SEPARATOR
Definition: emutools_gui.h:38