Skip to content

Commit

Permalink
Associate native window to NFD parent window
Browse files Browse the repository at this point in the history
  • Loading branch information
drhelius committed Jan 5, 2025
1 parent e76db70 commit d71ff7f
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 27 deletions.
31 changes: 15 additions & 16 deletions platforms/desktop-shared/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#define APPLICATION_IMPORT
#include "application.h"

static SDL_Window* sdl_window;
static SDL_GLContext gl_context;
static bool running = true;
static bool paused_when_focus_lost = false;
Expand Down Expand Up @@ -65,7 +64,7 @@ int application_init(const char* rom_file, const char* symbol_file)

gui_init();

ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context);
ImGui_ImplSDL2_InitForOpenGL(application_sdl_window, gl_context);

renderer_init();

Expand Down Expand Up @@ -121,17 +120,17 @@ void application_trigger_quit(void)

void application_trigger_fullscreen(bool fullscreen)
{
SDL_SetWindowFullscreen(sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetWindowFullscreen(application_sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}

void application_trigger_fit_to_content(int width, int height)
{
SDL_SetWindowSize(sdl_window, width, height);
SDL_SetWindowSize(application_sdl_window, width, height);
}

void application_update_title(char* title)
{
SDL_SetWindowTitle(sdl_window, title);
SDL_SetWindowTitle(application_sdl_window, title);
}

static int sdl_init(void)
Expand All @@ -158,12 +157,12 @@ static int sdl_init(void)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
sdl_window = SDL_CreateWindow(GEARBOY_TITLE " " GEARBOY_VERSION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config_emulator.window_width, config_emulator.window_height, window_flags);
gl_context = SDL_GL_CreateContext(sdl_window);
SDL_GL_MakeCurrent(sdl_window, gl_context);
application_sdl_window = SDL_CreateWindow(GEARBOY_TITLE " " GEARBOY_VERSION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config_emulator.window_width, config_emulator.window_height, window_flags);
gl_context = SDL_GL_CreateContext(application_sdl_window);
SDL_GL_MakeCurrent(application_sdl_window, gl_context);
SDL_GL_SetSwapInterval(0);

SDL_SetWindowMinimumSize(sdl_window, 500, 300);
SDL_SetWindowMinimumSize(application_sdl_window, 500, 300);

application_gamepad_mappings = SDL_GameControllerAddMappingsFromRW(SDL_RWFromFile("gamecontrollerdb.txt", "rb"), 1);

Expand Down Expand Up @@ -196,8 +195,8 @@ static int sdl_init(void)

int w, h;
int display_w, display_h;
SDL_GetWindowSize(sdl_window, &w, &h);
SDL_GL_GetDrawableSize(sdl_window, &display_w, &display_h);
SDL_GetWindowSize(application_sdl_window, &w, &h);
SDL_GL_GetDrawableSize(application_sdl_window, &display_w, &display_h);

if (w > 0 && h > 0)
{
Expand All @@ -216,7 +215,7 @@ static void sdl_destroy(void)
{
SDL_GameControllerClose(application_gamepad);
SDL_GL_DeleteContext(gl_context);
SDL_DestroyWindow(sdl_window);
SDL_DestroyWindow(application_sdl_window);
SDL_Quit();
}

Expand All @@ -232,7 +231,7 @@ static void sdl_events(void)
break;
}

if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(sdl_window))
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(application_sdl_window))
{
running = false;
break;
Expand All @@ -257,7 +256,7 @@ static void sdl_events_emu(const SDL_Event* event)
char* dropped_filedir = event->drop.file;
gui_load_rom(dropped_filedir);
SDL_free(dropped_filedir);
SDL_SetWindowInputFocus(sdl_window);
SDL_SetWindowInputFocus(application_sdl_window);
break;
}
case SDL_WINDOWEVENT:
Expand Down Expand Up @@ -533,7 +532,7 @@ static void render(void)
renderer_render();
renderer_end_render();

SDL_GL_SwapWindow(sdl_window);
SDL_GL_SwapWindow(application_sdl_window);
}

static void frame_throttle(void)
Expand Down Expand Up @@ -575,7 +574,7 @@ static void save_window_size(void)
if (!config_emulator.fullscreen)
{
int width, height;
SDL_GetWindowSize(sdl_window, &width, &height);
SDL_GetWindowSize(application_sdl_window, &width, &height);
config_emulator.window_width = width;
config_emulator.window_height = height;
}
Expand Down
1 change: 1 addition & 0 deletions platforms/desktop-shared/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define EXTERN extern
#endif

EXTERN SDL_Window* application_sdl_window;
EXTERN SDL_GameController* application_gamepad;
EXTERN int application_gamepad_mappings;
EXTERN float application_display_scale;
Expand Down
98 changes: 87 additions & 11 deletions platforms/desktop-shared/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
* along with this program. If not, see http://www.gnu.org/licenses/
*
*/

#include <math.h>
#include "imgui/imgui.h"
#include "imgui/fonts/RobotoMedium.h"
#include "nfd/nfd.h"
#include "nfd/nfd_sdl2.h"
#include "config.h"
#include "emu.h"
#include "../../src/gearboy.h"
Expand Down Expand Up @@ -66,6 +68,7 @@ static void file_dialog_load_dmg_bootrom(void);
static void file_dialog_load_gbc_bootrom(void);
static void file_dialog_load_symbols(void);
static void file_dialog_save_screenshot(void);
static void file_dialog_set_native_window(SDL_Window* window, nfdwindowhandle_t* native_window);
static void keyboard_configuration_item(const char* text, SDL_Scancode* key);
static void gamepad_configuration_item(const char* text, int* button);
static void popup_modal_keyboard(void);
Expand Down Expand Up @@ -1129,7 +1132,13 @@ static void file_dialog_open_rom(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[4] = { { "ROM Files", "gb,gbc,cgb,sgb,dmg,rom,zip" }, { "Game Boy", "gb,dmg" }, { "Game Boy Color", "gbc,cgb" }, { "Super Game Boy", "sgb" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 4, config_emulator.last_open_path.c_str());
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 4;
args.defaultPath = config_emulator.last_open_path.c_str();
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
std::string path = outPath;
Expand All @@ -1148,7 +1157,13 @@ static void file_dialog_load_ram(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "RAM Files", "sav" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
emu_load_ram(outPath, config_emulator.force_dmg, get_mbc(config_emulator.mbc), config_emulator.force_gba);
Expand All @@ -1164,7 +1179,14 @@ static void file_dialog_save_ram(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "RAM Files", "sav" } };
nfdresult_t result = NFD_SaveDialog(&outPath, filterItem, 1, NULL, NULL);
nfdsavedialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
args.defaultName = NULL;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_SaveDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
emu_save_ram(outPath);
Expand All @@ -1180,7 +1202,13 @@ static void file_dialog_load_state(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "Save State Files", "state" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
std::string message("Loading state from ");
Expand All @@ -1199,7 +1227,14 @@ static void file_dialog_save_state(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "Save State Files", "state" } };
nfdresult_t result = NFD_SaveDialog(&outPath, filterItem, 1, NULL, NULL);
nfdsavedialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
args.defaultName = NULL;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_SaveDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
std::string message("Saving state to ");
Expand All @@ -1217,7 +1252,11 @@ static void file_dialog_save_state(void)
static void file_dialog_choose_save_file_path(void)
{
nfdchar_t *outPath;
nfdresult_t result = NFD_PickFolder(&outPath, savefiles_path);
nfdpickfolderu8args_t args = { };
args.defaultPath = savefiles_path;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_PickFolderU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
strcpy(savefiles_path, outPath);
Expand All @@ -1233,7 +1272,11 @@ static void file_dialog_choose_save_file_path(void)
static void file_dialog_choose_savestate_path(void)
{
nfdchar_t *outPath;
nfdresult_t result = NFD_PickFolder(&outPath, savestates_path);
nfdpickfolderu8args_t args = { };
args.defaultPath = savestates_path;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_PickFolderU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
strcpy(savestates_path, outPath);
Expand All @@ -1250,7 +1293,13 @@ static void file_dialog_load_dmg_bootrom(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "BIOS Files", "bin,rom,bios,gb" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
strcpy(dmg_bootrom_path, outPath);
Expand All @@ -1268,7 +1317,13 @@ static void file_dialog_load_gbc_bootrom(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "BIOS Files", "bin,rom,bios,gbc" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = config_emulator.last_open_path.c_str();
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
strcpy(gbc_bootrom_path, outPath);
Expand All @@ -1286,7 +1341,13 @@ static void file_dialog_load_symbols(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "Symbol Files", "sym" } };
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
nfdopendialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = NULL;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
gui_debug_reset_symbols();
Expand All @@ -1303,7 +1364,14 @@ static void file_dialog_save_screenshot(void)
{
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "PNG Files", "png" } };
nfdresult_t result = NFD_SaveDialog(&outPath, filterItem, 1, NULL, NULL);
nfdsavedialogu8args_t args = { };
args.filterList = filterItem;
args.filterCount = 1;
args.defaultPath = NULL;
args.defaultName = NULL;
file_dialog_set_native_window(application_sdl_window, &args.parentWindow);

nfdresult_t result = NFD_SaveDialogU8_With(&outPath, &args);
if (result == NFD_OKAY)
{
call_save_screenshot(outPath);
Expand All @@ -1315,6 +1383,14 @@ static void file_dialog_save_screenshot(void)
}
}

static void file_dialog_set_native_window(SDL_Window* window, nfdwindowhandle_t* native_window)
{
if (!NFD_GetNativeWindowFromSDLWindow(window, native_window))
{
Log("NFD_GetNativeWindowFromSDLWindow failed: %s\n", SDL_GetError());
}
}

static void keyboard_configuration_item(const char* text, SDL_Scancode* key)
{
ImGui::Text("%s", text);
Expand Down
76 changes: 76 additions & 0 deletions platforms/desktop-shared/nfd/nfd_sdl2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Native File Dialog Extended
Repository: https://github.com/btzy/nativefiledialog-extended
License: Zlib
Authors: Bernard Teo
This header contains a function to convert an SDL window handle to a native window handle for
passing to NFDe.
This is meant to be used with SDL2, but if there are incompatibilities with future SDL versions,
we can conditionally compile based on SDL_MAJOR_VERSION.
*/

#ifndef _NFD_SDL2_H
#define _NFD_SDL2_H

#include <SDL_error.h>
#include <SDL_syswm.h>
#include <stdbool.h>
#include "nfd.h"

#ifdef __cplusplus
extern "C" {
#define NFD_INLINE inline
#else
#define NFD_INLINE static inline
#endif // __cplusplus

/**
* Converts an SDL window handle to a native window handle that can be passed to NFDe.
* @param sdlWindow The SDL window handle.
* @param[out] nativeWindow The output native window handle, populated if and only if this function
* returns true.
* @return Either true to indicate success, or false to indicate failure. If false is returned,
* you can call SDL_GetError() for more information. However, it is intended that users ignore the
* error and simply pass a value-initialized nfdwindowhandle_t to NFDe if this function fails. */
NFD_INLINE bool NFD_GetNativeWindowFromSDLWindow(SDL_Window* sdlWindow,
nfdwindowhandle_t* nativeWindow) {
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(sdlWindow, &info)) {
return false;
}
switch (info.subsystem) {
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
case SDL_SYSWM_WINDOWS:
nativeWindow->type = NFD_WINDOW_HANDLE_TYPE_WINDOWS;
nativeWindow->handle = (void*)info.info.win.window;
return true;
#endif
#if defined(SDL_VIDEO_DRIVER_COCOA)
case SDL_SYSWM_COCOA:
nativeWindow->type = NFD_WINDOW_HANDLE_TYPE_COCOA;
nativeWindow->handle = (void*)info.info.cocoa.window;
return true;
#endif
#if defined(SDL_VIDEO_DRIVER_X11)
case SDL_SYSWM_X11:
nativeWindow->type = NFD_WINDOW_HANDLE_TYPE_X11;
nativeWindow->handle = (void*)info.info.x11.window;
return true;
#endif
default:
// Silence the warning in case we are not using a supported backend.
(void)nativeWindow;
SDL_SetError("Unsupported native window type.");
return false;
}
}

#undef NFD_INLINE
#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _NFD_SDL2_H

0 comments on commit d71ff7f

Please sign in to comment.