[GTK3] Add UI skeleton

This commit is contained in:
Maximilian Mader 2020-04-11 18:24:55 +02:00
parent 695c6ee943
commit 6913c47076
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
18 changed files with 2469 additions and 9 deletions

10
.gitignore vendored
View File

@ -1 +1,9 @@
build build
# intermediate source files generated at build time
gtk3/sameboy-gtk3-resources.c
gtk3/resources/gtk3/
# temporary backup file
*.*~

View File

@ -1,5 +1,5 @@
# Make hacks # Make hacks
.INTERMEDIATE: .INTERMEDIATE: gtk3/sameboy-gtk3-resources.c
# Set target, configuration, version and destination folders # Set target, configuration, version and destination folders
@ -87,8 +87,8 @@ ifeq ($(PLATFORM),Darwin)
OPEN_DIALOG = OpenDialog/cocoa.m OPEN_DIALOG = OpenDialog/cocoa.m
endif endif
CFLAGS += -Werror -Wall -Wpartial-availability -Wno-nonnull -Wno-unused-result -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES CFLAGS += -Werror -Wall -Wpartial-availability -Wno-nonnull -Wno-unused-result -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
ifeq (,$(PKG_CONFIG)) ifeq (,$(PKG_CONFIG))
SDL_CFLAGS := $(shell sdl2-config --cflags) SDL_CFLAGS := $(shell sdl2-config --cflags)
SDL_LDFLAGS := $(shell sdl2-config --libs) SDL_LDFLAGS := $(shell sdl2-config --libs)
@ -102,6 +102,16 @@ else
GL_CFLAGS := $(shell $(PKG_CONFIG) --cflags gl) GL_CFLAGS := $(shell $(PKG_CONFIG) --cflags gl)
GL_LDFLAGS := $(shell $(PKG_CONFIG) --libs gl || echo -lGL) GL_LDFLAGS := $(shell $(PKG_CONFIG) --libs gl || echo -lGL)
endif endif
ifeq (,$(PKG_CONFIG))
ifneq ($(findstring gtk3,$(MAKECMDGOALS)),)
$(error The gtk3 target requires pkg-config)
endif
else
GTK3_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk+-3.0) -DGTK_DISABLE_DEPRECATED=1 -DG_DISABLE_DEPRECATED=1
GTK3_LDFLAGS := $(shell $(PKG_CONFIG) --libs gtk+-3.0)
endif
ifeq ($(PLATFORM),windows32) ifeq ($(PLATFORM),windows32)
CFLAGS += -IWindows -Drandom=rand CFLAGS += -IWindows -Drandom=rand
LDFLAGS += -lmsvcrt -lcomdlg32 -luser32 -lSDL2main -Wl,/MANIFESTFILE:NUL LDFLAGS += -lmsvcrt -lcomdlg32 -luser32 -lSDL2main -Wl,/MANIFESTFILE:NUL
@ -109,6 +119,7 @@ SDL_LDFLAGS := -lSDL2
GL_LDFLAGS := -lopengl32 GL_LDFLAGS := -lopengl32
else else
LDFLAGS += -lc -lm -ldl LDFLAGS += -lc -lm -ldl
GTK3_LDFLAGS += -Wl -rdynamic
endif endif
ifeq ($(PLATFORM),Darwin) ifeq ($(PLATFORM),Darwin)
@ -156,6 +167,7 @@ endif
cocoa: $(BIN)/SameBoy.app cocoa: $(BIN)/SameBoy.app
quicklook: $(BIN)/SameBoy.qlgenerator quicklook: $(BIN)/SameBoy.qlgenerator
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/sgb2_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
gtk3: $(BIN)/gtk3/sameboy
bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/sgb_boot.bin $(BIN)/BootROMs/sgb2_boot.bin
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin $(BIN)/tester/sgb2_boot.bin
all: cocoa sdl tester libretro all: cocoa sdl tester libretro
@ -164,6 +176,7 @@ all: cocoa sdl tester libretro
CORE_SOURCES := $(shell ls Core/*.c) CORE_SOURCES := $(shell ls Core/*.c)
SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG)
GTK3_SOURCES := $(shell ls gtk3/*.c) gtk3/sameboy-gtk3-resources.c
TESTER_SOURCES := $(shell ls Tester/*.c) TESTER_SOURCES := $(shell ls Tester/*.c)
ifeq ($(PLATFORM),Darwin) ifeq ($(PLATFORM),Darwin)
@ -179,6 +192,7 @@ CORE_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(CORE_SOURCES))
COCOA_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(COCOA_SOURCES)) COCOA_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(COCOA_SOURCES))
QUICKLOOK_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(QUICKLOOK_SOURCES)) QUICKLOOK_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(QUICKLOOK_SOURCES))
SDL_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(SDL_SOURCES)) SDL_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(SDL_SOURCES))
GTK3_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(GTK3_SOURCES))
TESTER_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(TESTER_SOURCES)) TESTER_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(TESTER_SOURCES))
# Automatic dependency generation # Automatic dependency generation
@ -188,6 +202,9 @@ ifneq ($(filter-out clean bootroms libretro %.bin, $(MAKECMDGOALS)),)
ifneq ($(filter $(MAKECMDGOALS),sdl),) ifneq ($(filter $(MAKECMDGOALS),sdl),)
-include $(SDL_OBJECTS:.o=.dep) -include $(SDL_OBJECTS:.o=.dep)
endif endif
ifneq ($(filter $(MAKECMDGOALS),gtk3),)
-include $(GTK3_OBJECTS:.o=.gtk3dep)
endif
ifneq ($(filter $(MAKECMDGOALS),tester),) ifneq ($(filter $(MAKECMDGOALS),tester),)
-include $(TESTER_OBJECTS:.o=.dep) -include $(TESTER_OBJECTS:.o=.dep)
endif endif
@ -200,6 +217,16 @@ $(OBJ)/SDL/%.dep: SDL/%
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@
gtk3/sameboy-gtk3-resources.c: gtk3/sameboy.gresource.xml $(shell glib-compile-resources --sourcedir=gtk3/resources --generate-dependencies gtk3/sameboy.gresource.xml)
glib-compile-resources --sourcedir=gtk3/resources --target=$@ --generate-source $<
# Resource hack cleanup
rm -rf gtk3/resources/gtk3
# GTK3 requires special CFLAGS
$(OBJ)/gtk3/%.gtk3dep: %
-@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(GTK3_CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@
$(OBJ)/%.dep: % $(OBJ)/%.dep: %
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ $(CC) $(CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@
@ -214,15 +241,20 @@ $(OBJ)/SDL/%.c.o: SDL/%.c
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@
# GTK3 requires special CFLAGS
$(OBJ)/gtk3/%.c.o: gtk3/%.c
-@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(GTK3_CFLAGS) -c $< -o $@
$(OBJ)/%.c.o: %.c $(OBJ)/%.c.o: %.c
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
# HexFiend requires more flags # HexFiend requires more flags
$(OBJ)/HexFiend/%.m.o: HexFiend/%.m $(OBJ)/HexFiend/%.m.o: HexFiend/%.m
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@ -fno-objc-arc -include HexFiend/HexFiend_2_Framework_Prefix.pch $(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@ -fno-objc-arc -include HexFiend/HexFiend_2_Framework_Prefix.pch
$(OBJ)/%.m.o: %.m $(OBJ)/%.m.o: %.m
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(OCFLAGS) -c $< -o $@
@ -260,7 +292,7 @@ endif
$(BIN)/SameBoy.app/Contents/Resources/Base.lproj/%.nib: Cocoa/%.xib $(BIN)/SameBoy.app/Contents/Resources/Base.lproj/%.nib: Cocoa/%.xib
ibtool --compile $@ $^ ibtool --compile $@ $^
# Quick Look generator # Quick Look generator
$(BIN)/SameBoy.qlgenerator: $(BIN)/SameBoy.qlgenerator/Contents/MacOS/SameBoyQL \ $(BIN)/SameBoy.qlgenerator: $(BIN)/SameBoy.qlgenerator/Contents/MacOS/SameBoyQL \
@ -282,7 +314,7 @@ $(BIN)/SameBoy.qlgenerator/Contents/MacOS/SameBoyQL: $(CORE_OBJECTS) $(QUICKLOOK
$(BIN)/SameBoy.qlgenerator/Contents/Resources/cgb_boot_fast.bin: $(BIN)/BootROMs/cgb_boot_fast.bin $(BIN)/SameBoy.qlgenerator/Contents/Resources/cgb_boot_fast.bin: $(BIN)/BootROMs/cgb_boot_fast.bin
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
cp -f $^ $@ cp -f $^ $@
# SDL Port # SDL Port
# Unix versions build only one binary # Unix versions build only one binary
@ -293,7 +325,7 @@ ifeq ($(CONF), release)
$(STRIP) $@ $(STRIP) $@
endif endif
# Windows version builds two, one with a conole and one without it # Windows version builds two, one with a console and one without it
$(BIN)/SDL/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o $(BIN)/SDL/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) $(GL_LDFLAGS) -Wl,/subsystem:windows $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) $(GL_LDFLAGS) -Wl,/subsystem:windows
@ -309,7 +341,7 @@ $(OBJ)/%.o: %.rc
else else
$(OBJ)/%.res: %.rc $(OBJ)/%.res: %.rc
-@$(MKDIR) -p $(dir $@) -@$(MKDIR) -p $(dir $@)
rc /fo $@ /dVERSION=\"$(VERSION)\" $^ rc /fo $@ /dVERSION=\"$(VERSION)\" $^
%.o: %.res %.o: %.res
cvtres /OUT:"$@" $^ cvtres /OUT:"$@" $^
@ -320,6 +352,15 @@ $(BIN)/SDL/SDL2.dll:
@$(eval MATCH := $(shell where $$LIB:SDL2.dll)) @$(eval MATCH := $(shell where $$LIB:SDL2.dll))
cp "$(MATCH)" $@ cp "$(MATCH)" $@
# GTK3
$(BIN)/gtk3/sameboy: $(CORE_OBJECTS) $(GTK3_OBJECTS)
-@$(MKDIR) -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS) $(GTK3_LDFLAGS)
ifeq ($(CONF), release)
strip $@
endif
# Tester # Tester
$(BIN)/tester/sameboy_tester: $(CORE_OBJECTS) $(TESTER_OBJECTS) $(BIN)/tester/sameboy_tester: $(CORE_OBJECTS) $(TESTER_OBJECTS)
@ -357,6 +398,15 @@ $(BIN)/SDL/Shaders: Shaders
-@$(MKDIR) -p $@ -@$(MKDIR) -p $@
cp -rf Shaders/*.fsh $@ cp -rf Shaders/*.fsh $@
# Fugly resource hack
gtk3/resources/bootroms/%.bin: $(BOOTROMS_DIR)/%.bin
-@$(MKDIR) -p gtk3/resources/gtk3/resources/bootroms/
cp -f $< gtk3/resources/$@
gtk3/resources/Shaders/%.fsh: Shaders/%.fsh
-@$(MKDIR) -p gtk3/resources/gtk3/resources/Shaders/
cp -rf $< gtk3/resources/$@
# Boot ROMs # Boot ROMs
$(OBJ)/%.1bpp: %.png $(OBJ)/%.1bpp: %.png

264
gtk3/main.c Normal file
View File

@ -0,0 +1,264 @@
#include <gtk/gtk.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <Core/gb.h>
#define str(x) #x
#define xstr(x) str(x)
#define RESOURCE_PREFIX "/io/github/sameboy/"
#define APP_ID "io.github.sameboy"
GtkBuilder *builder;
GtkWindow *main_window;
GtkGLArea *gl_area;
GB_gameboy_t gb;
typedef struct UserData {
bool fullscreen;
GFile *file;
} UserData;
// Determines if a ComboBox entry should be converted into a separator.
// Each element with a text value of `<separator>` will be converted into a separator element.
static gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
gchar *text = NULL;
gtk_tree_model_get(model, iter, 0, &text, -1);
gboolean result = g_strcmp0("<separator>", text) == 0;
return result;
}
// Recursively goes through all children of the given container and sets
// our `is_separator` function to all children of type`GtkComboBox`
static void set_combo_box_row_separator_func(GtkContainer *container) {
GList *list = gtk_container_get_children(container);
while (list) {
if (GTK_IS_COMBO_BOX(list->data)) {
gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(list->data), is_separator, NULL, NULL);
}
if (GTK_IS_CONTAINER(list->data)) {
set_combo_box_row_separator_func(GTK_CONTAINER(list->data));
}
list = list->next;
}
g_list_free_full(list, NULL);
}
// Returns true if the application should show a menubar
static gboolean show_menubar(void) {
GtkSettings *settings = gtk_settings_get_default();
gboolean result;
g_object_get(settings, "gtk-shell-shows-menubar", &result, NULL);
return result;
}
// Returns a GObject by ID from our GtkBuilder instance
static GObject *get_object(gchararray id) {
return gtk_builder_get_object(builder, id);
}
// Returns a `GApplication`s `GMenuModel` by ID
// GApplication menus are loaded from `gtk/menus.ui`, `gtk/menus-traditional.ui` and `gtk/menus-common.ui`.
static GMenuModel *get_menu_model(GApplication *app, const char *id) {
GMenu *menu;
menu = gtk_application_get_menu_by_id(GTK_APPLICATION(app), id);
return menu ? G_MENU_MODEL(g_object_ref_sink(menu)) : NULL;
}
// app.quit GAction
// Exits the application
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
g_application_quit(G_APPLICATION(user_data));
}
// app.about GAction
// Opens the about dialog
static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer user_data) {
GObject *dialog = get_object("about_dialog");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_hide(GTK_WIDGET(dialog));
}
// List of GActions for the `app` prefix
static GActionEntry app_entries[] = {
{ "quit", activate_quit, NULL, NULL, NULL },
{ "about", activate_about, NULL, NULL, NULL },
};
G_MODULE_EXPORT void on_show_window(GtkWidget *w, gpointer window) {
gtk_widget_show_all(GTK_WIDGET(window));
}
G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_data_gptr) {
GtkComboBox *box = GTK_COMBO_BOX(w);
g_print("Active: %s", gtk_combo_box_get_active_id(box));
}
// This functions gets called immediately after registration of the GApplication
static void startup(GApplication *app, gpointer user_data_gptr) {
// UserData *user_data = user_data_gptr;
builder = gtk_builder_new_from_resource(RESOURCE_PREFIX "ui/window.ui");
gtk_builder_connect_signals(builder, NULL);
g_action_map_add_action_entries(G_ACTION_MAP(app), app_entries, G_N_ELEMENTS(app_entries), app);
GtkWindow *preferences = GTK_WINDOW(get_object("preferences"));
set_combo_box_row_separator_func(GTK_CONTAINER(preferences));
GtkWindow *vram_viewer = GTK_WINDOW(get_object("vram_viewer"));
set_combo_box_row_separator_func(GTK_CONTAINER(vram_viewer));
// Handle the whole menubar situation …
if (show_menubar()) {
// Use a standard window as main window
main_window = GTK_WINDOW(get_object("main_no_titlebar"));
gtk_widget_destroy(GTK_WIDGET(get_object("main_with_titlebar")));
// Hide hamburger button
GtkMenuButton *hamburger_button = GTK_MENU_BUTTON(get_object("hamburger_button"));
gtk_widget_hide(GTK_WIDGET(hamburger_button));
gtk_widget_set_no_show_all(GTK_WIDGET(hamburger_button), TRUE);
GMenuModel *menubar = get_menu_model(app, "menubar");
gtk_application_set_menubar(GTK_APPLICATION(app), menubar);
}
else {
// Use a window with a custom title bar
main_window = GTK_WINDOW(get_object("main_with_titlebar"));
gtk_widget_destroy(GTK_WIDGET(get_object("main_no_titlebar")));
// Disable menubar
gtk_application_set_menubar(GTK_APPLICATION(app), NULL);
// Hook menubar up to the hamburger button
GtkMenuButton *hamburger_button = GTK_MENU_BUTTON(get_object("hamburger_button"));
GMenuModel *hamburger_menu = get_menu_model(app, "menubar");
gtk_menu_button_set_menu_model(hamburger_button, hamburger_menu);
}
gtk_window_set_title(main_window, "SameBoy v" xstr(VERSION));
// Define a set of window icons
GList *icon_list = NULL;
static char* icons[] = {
RESOURCE_PREFIX "logo_256.png",
RESOURCE_PREFIX "logo_128.png",
RESOURCE_PREFIX "logo_64.png",
RESOURCE_PREFIX "logo_48.png",
RESOURCE_PREFIX "logo_32.png",
RESOURCE_PREFIX "logo_16.png"
};
// Create list of GdkPixbufs
for (int i = 0; i < (sizeof(icons) / sizeof(const char*)); ++i) {
GdkPixbuf *icon = gdk_pixbuf_new_from_resource(icons[i], NULL);
if (!icon) continue;
icon_list = g_list_prepend(icon_list, icon);
}
// Let GTK choose the proper icon
gtk_window_set_icon_list(main_window, icon_list);
// Add missing information to the about dialog
GtkAboutDialog *about_dialog = GTK_ABOUT_DIALOG(get_object("about_dialog"));
gtk_about_dialog_set_logo(about_dialog, g_list_nth_data(icon_list, 3)); // reuse the 64x64 icon
gtk_about_dialog_set_version(about_dialog, "v" xstr(VERSION));
g_list_free(icon_list);
GList *children = gtk_container_get_children(GTK_CONTAINER(main_window));
gl_area = GTK_GL_AREA(g_list_first(children));
g_list_free(children);
}
// This function gets called when the GApplication gets activated, i.e. it is ready to show widgets.
static void activate(GApplication *app, gpointer user_data_gptr) {
UserData *user_data = user_data_gptr;
if (user_data->fullscreen) {
gtk_window_fullscreen(main_window);
}
g_signal_connect(main_window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_application_add_window(GTK_APPLICATION(app), main_window);
gtk_widget_show_all(GTK_WIDGET(main_window));
}
// This function gets called when there are files to open.
// Note: When `open` gets called `activate` wont fire unless we call it ourselves.
static void open(GApplication *app, GFile **files, gint n_files, const gchar *hint, gpointer user_data_gptr) {
UserData *user_data = user_data_gptr;
if (n_files > 1) {
g_printerr("More than one file specified\n");
g_application_quit(app);
return;
}
user_data->file = files[0];
// We have handled the files, now activate the application
activate(app, user_data_gptr);
}
// This function gets called after the parsing of the commandline options has occurred.
static gint handle_local_options(GApplication *app, GVariantDict *options, gpointer user_data_gptr) {
UserData *user_data = user_data_gptr;
guint32 count;
if (g_variant_dict_lookup(options, "version", "b", &count)) {
g_print("SameBoy v" xstr(VERSION) "\n");
return EXIT_SUCCESS;
}
if (g_variant_dict_lookup(options, "fullscreen", "b", &count)) {
user_data->fullscreen = true;
}
return -1;
}
int main (int argc, char *argv[]) {
// Create our GApplication and tell GTK that we are able to handle files
GtkApplication *app = gtk_application_new(APP_ID, G_APPLICATION_HANDLES_OPEN);
UserData user_data = { NULL };
// Define our command line parameters
GOptionEntry entries[] = {
{ "version", 'v', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Show the application version", NULL },
{ "fullscreen", 'f', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, NULL, "Start in fullscreen mode", NULL },
{ NULL }
};
// Setup our command line information
g_application_add_main_option_entries(G_APPLICATION(app), entries);
g_application_set_option_context_parameter_string(G_APPLICATION(app), "[FILE…]");
g_application_set_option_context_summary(G_APPLICATION(app), "SameBoy is an open source Game Boy (DMG) and Game Boy Color (CGB) emulator.");
// Add signal handlers
g_signal_connect(app, "handle-local-options", G_CALLBACK(handle_local_options), &user_data);
g_signal_connect(app, "startup", G_CALLBACK(startup), &user_data);
g_signal_connect(app, "activate", G_CALLBACK(activate), &user_data);
g_signal_connect(app, "open", G_CALLBACK(open), &user_data);
// Start our GApplication main loop
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}

View File

@ -0,0 +1,422 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License (MIT)
Copyright (c) 2015-2019 Lior Halphon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Author: Maximilian Mader
-->
<interface>
<!-- interface-requires gtk+ 3.0 -->
<!-- menubar is in common since on ubuntu would be picked from menus-traditional, and on osx from menus -->
<menu id="menubar">
<section>
<submenu>
<attribute name="label" translatable="yes">_SameBoy</attribute>
<section>
<attribute name="id">sameboy-section-0</attribute>
<item>
<attribute name="label" translatable="yes">About SameBoy</attribute>
<attribute name="action">app.about</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>
</section>
<section>
<attribute name="id">sameboy-section-1</attribute>
<item>
<attribute name="label" translatable="yes">Hide SameBoy</attribute>
<attribute name="action">app.hide_app</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Hide Others</attribute>
<attribute name="action">app.hide_others</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Show All</attribute>
<attribute name="action">app.show_all</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Quit SameBoy</attribute>
<attribute name="action">app.quit</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_File</attribute>
<section>
<attribute name="id">file-section-0</attribute>
<item>
<attribute name="label" translatable="yes">_Open</attribute>
<attribute name="action">win.open</attribute>
</item>
<submenu>
<attribute name="label" translatable="yes">Open _Recent</attribute>
<section>
<attribute name="id">recent-files-section</attribute>
</section>
</submenu>
</section>
<section>
<attribute name="id">file-section-1</attribute>
<item>
<attribute name="label" translatable="yes">Close</attribute>
<attribute name="action">win.close</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Edit</attribute>
<section>
<attribute name="id">edit-section-0</attribute>
<item>
<attribute name="label" translatable="yes">Undo</attribute>
<attribute name="action">win.undo</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Redo</attribute>
<attribute name="action">win.redo</attribute>
</item>
</section>
<section>
<attribute name="id">edit-section-1</attribute>
<item>
<attribute name="label" translatable="yes">Cut</attribute>
<attribute name="action">win.cut</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Copy</attribute>
<attribute name="action">win.copy</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Paste</attribute>
<attribute name="action">win.paste</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Delete</attribute>
<attribute name="action">win.delete</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Select All</attribute>
<attribute name="action">win.select_all</attribute>
</item>
</section>
<section>
<submenu>
<attribute name="label" translatable="yes">Find</attribute>
<section>
<attribute name="id">find-section-0</attribute>
<item>
<attribute name="label" translatable="yes">Find…</attribute>
<attribute name="action">win.find</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Find Next</attribute>
<attribute name="action">win.find_next</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Find Previous</attribute>
<attribute name="action">win.find_previous</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Use Selection for Find</attribute>
<attribute name="action">win.find_selection</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Jump to Selection</attribute>
<attribute name="action">win.jump_selection</attribute>
</item>
</section>
</submenu>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">E_mulation</attribute>
<section>
<attribute name="id">emulation-section-0</attribute>
<item>
<attribute name="label" translatable="yes">Reset</attribute>
<attribute name="action">win.reset</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Pause</attribute>
<attribute name="action">win.pause</attribute>
</item>
</section>
<section>
<attribute name="id">emulation-section-1</attribute>
<submenu>
<attribute name="label" translatable="yes">Save State</attribute>
<item>
<attribute name="label" translatable="yes">Slot 1</attribute>
<attribute name="save_slot">0</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 2</attribute>
<attribute name="save_slot">1</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 3</attribute>
<attribute name="save_slot">2</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 4</attribute>
<attribute name="save_slot">3</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 5</attribute>
<attribute name="save_slot">4</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 6</attribute>
<attribute name="save_slot">5</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 7</attribute>
<attribute name="save_slot">6</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 8</attribute>
<attribute name="save_slot">7</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 9</attribute>
<attribute name="save_slot">8</attribute>
<attribute name="action">win.save_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 10</attribute>
<attribute name="save_slot">9</attribute>
<attribute name="action">win.save_state</attribute>
</item>
</submenu>
<submenu>
<attribute name="label" translatable="yes">Save State</attribute>
<item>
<attribute name="label" translatable="yes">Slot 1</attribute>
<attribute name="save_slot">0</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 2</attribute>
<attribute name="save_slot">1</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 3</attribute>
<attribute name="save_slot">2</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 4</attribute>
<attribute name="save_slot">3</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 5</attribute>
<attribute name="save_slot">4</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 6</attribute>
<attribute name="save_slot">5</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 7</attribute>
<attribute name="save_slot">6</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 8</attribute>
<attribute name="save_slot">7</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 9</attribute>
<attribute name="save_slot">8</attribute>
<attribute name="action">win.load_state</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Slot 10</attribute>
<attribute name="save_slot">9</attribute>
<attribute name="action">win.load_state</attribute>
</item>
</submenu>
</section>
<section>
<attribute name="id">emulation-section-2</attribute>
<item>
<attribute name="label" translatable="yes">Game Boy</attribute>
<attribute name="action">win.change_model</attribute>
<attribute name="model">DMG</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Super Game Boy</attribute>
<attribute name="action">win.change_model</attribute>
<attribute name="model">SGB</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Game Boy Color</attribute>
<attribute name="action">win.change_model</attribute>
<attribute name="model">CGB</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Game Boy Advance</attribute>
<attribute name="action">win.change_model</attribute>
<attribute name="model">AGB</attribute>
</item>
</section>
<section>
<attribute name="id">emulation-section-3</attribute>
<item>
<attribute name="label" translatable="yes">Mute Sound</attribute>
<attribute name="action">win.toggle_mute</attribute>
</item>
</section>
<section>
<attribute name="id">emulation-section-4</attribute>
<item>
<attribute name="label" translatable="yes">Blend Frames</attribute>
<attribute name="action">win.toggle_blend_frames</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Connectivity</attribute>
<section>
<attribute name="id">connectivity-section-0</attribute>
<item>
<attribute name="label" translatable="yes">None</attribute>
<attribute name="action">win.change_serial_device</attribute>
<attribute name="serial_device">none</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Game Boy Printer</attribute>
<attribute name="action">win.change_serial_device</attribute>
<attribute name="serial_device">gb_printer</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Developer</attribute>
<section>
<attribute name="id">developer-section-0</attribute>
<item>
<attribute name="label" translatable="yes">Developer Mode</attribute>
<attribute name="action">win.toggle_developer_mode</attribute>
</item>
</section>
<section>
<attribute name="id">developer-section-1</attribute>
<item>
<attribute name="label" translatable="yes">Show Console</attribute>
<attribute name="action">win.show_console</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Clear Console</attribute>
<attribute name="action">win.clear_console</attribute>
</item>
</section>
<section>
<attribute name="id">developer-section-2</attribute>
<item>
<attribute name="label" translatable="yes">Break Debugger</attribute>
<attribute name="action">win.break_debugger</attribute>
</item>
</section>
<section>
<attribute name="id">developer-section-3</attribute>
<item>
<attribute name="label" translatable="yes">Show Memory Viewer</attribute>
<attribute name="action">win.open_memory_viewer</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Show VRAM Viewer</attribute>
<attribute name="action">win.open_vram_viewer</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Window</attribute>
<section>
<attribute name="id">window-section-0</attribute>
<item>
<attribute name="label" translatable="yes">Minimize</attribute>
<attribute name="action">win.minimize</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Zoom</attribute>
<attribute name="action">win.zoom</attribute>
</item>
</section>
<section>
<attribute name="id">window-section-1</attribute>
<item>
<attribute name="label" translatable="yes">Bring All to Front</attribute>
<attribute name="action">win.bring_to_front</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Help</attribute>
<section>
<attribute name="id">help-section-0</attribute>
<item>
<attribute name="label" translatable="yes">SameBoy Help</attribute>
<attribute name="action">win.help</attribute>
</item>
</section>
</submenu>
</section>
</menu>
</interface>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License (MIT)
Copyright (c) 2015-2019 Lior Halphon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Author: Maximilian Mader
-->
<interface>
<!-- interface-requires gtk+ 3.0 -->
</interface>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License (MIT)
Copyright (c) 2015-2019 Lior Halphon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Author: Maximilian Mader
-->
<interface>
<!-- interface-requires gtk+ 3.0 -->
</interface>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

1610
gtk3/resources/ui/window.ui Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/io/github/sameboy">
<file preprocess="xml-stripblanks" compressed="true">ui/window.ui</file>
<file preprocess="xml-stripblanks">gtk/menus.ui</file>
<file preprocess="xml-stripblanks">gtk/menus-common.ui</file>
<file preprocess="xml-stripblanks">gtk/menus-traditional.ui</file>
<file alias="logo_256.png">pixmaps/logo/logo_256.png</file>
<file alias="logo_128.png">pixmaps/logo/logo_128.png</file>
<file alias="logo_64.png">pixmaps/logo/logo_64.png</file>
<file alias="logo_48.png">pixmaps/logo/logo_48.png</file>
<file alias="logo_32.png">pixmaps/logo/logo_32.png</file>
<file alias="logo_16.png">pixmaps/logo/logo_16.png</file>
<!-- Boot ROMs, generated at compile time -->
<!-- The file path is a hack to get automatic dependency generation working-->
<file compressed="true" alias="bootroms/dmg_boot.bin">gtk3/resources/bootroms/dmg_boot.bin</file>
<file compressed="true" alias="bootroms/cgb_boot.bin">gtk3/resources/bootroms/cgb_boot.bin</file>
<file compressed="true" alias="bootroms/agb_boot.bin">gtk3/resources/bootroms/agb_boot.bin</file>
<file compressed="true" alias="bootroms/sgb_boot.bin">gtk3/resources/bootroms/sgb_boot.bin</file>
<file compressed="true" alias="bootroms/sgb2_boot.bin">gtk3/resources/bootroms/sgb2_boot.bin</file>
<!-- Shaders -->
<!-- The file path is a hack to get automatic dependency generation working-->
<file compressed="true" alias="Shaders/AAOmniScaleLegacy.fsh">gtk3/resources/Shaders/AAOmniScaleLegacy.fsh</file>
<file compressed="true" alias="Shaders/AAScale2x.fsh">gtk3/resources/Shaders/AAScale2x.fsh</file>
<file compressed="true" alias="Shaders/AAScale4x.fsh">gtk3/resources/Shaders/AAScale4x.fsh</file>
<file compressed="true" alias="Shaders/Bilinear.fsh">gtk3/resources/Shaders/Bilinear.fsh</file>
<file compressed="true" alias="Shaders/CRT.fsh">gtk3/resources/Shaders/CRT.fsh</file>
<file compressed="true" alias="Shaders/HQ2x.fsh">gtk3/resources/Shaders/HQ2x.fsh</file>
<file compressed="true" alias="Shaders/LCD.fsh">gtk3/resources/Shaders/LCD.fsh</file>
<file compressed="true" alias="Shaders/MasterShader.fsh">gtk3/resources/Shaders/MasterShader.fsh</file>
<file compressed="true" alias="Shaders/NearestNeighbor.fsh">gtk3/resources/Shaders/NearestNeighbor.fsh</file>
<file compressed="true" alias="Shaders/OmniScale.fsh">gtk3/resources/Shaders/OmniScale.fsh</file>
<file compressed="true" alias="Shaders/OmniScaleLegacy.fsh">gtk3/resources/Shaders/OmniScaleLegacy.fsh</file>
<file compressed="true" alias="Shaders/Scale2x.fsh">gtk3/resources/Shaders/Scale2x.fsh</file>
<file compressed="true" alias="Shaders/Scale4x.fsh">gtk3/resources/Shaders/Scale4x.fsh</file>
<file compressed="true" alias="Shaders/SmoothBilinear.fsh">gtk3/resources/Shaders/SmoothBilinear.fsh</file>
<file>pixmaps/CPU.png</file>
<file>pixmaps/Display.png</file>
<file>pixmaps/Joypad.png</file>
<file>pixmaps/Speaker.png</file>
</gresource>
</gresources>