Skip to content

Instantly share code, notes, and snippets.

@cjxgm
Last active February 11, 2024 16:03
Show Gist options
  • Save cjxgm/4a5d9006a6f9f19ee6daf4974abfa9cf to your computer and use it in GitHub Desktop.
Save cjxgm/4a5d9006a6f9f19ee6daf4974abfa9cf to your computer and use it in GitHub Desktop.
The MessageBox() alternative for Gtk4

Why

You are writing a game in, say GLFW or SDL. Somehow you want to show a fatal error message to the user, preferrably in native style. How?

  • On Windows, you can simply call MessageBox() to show such message.
  • On Linux, you can use the method below.
  • On other platforms, well it's your homework.

How to compile

Just compile it without any flags should work.

# Use gcc
g++ message-box.cpp
./a.out

# Use clang
clang++ message-box.cpp
./a.out

If there are any linking error, you may need to supply -ldl to the compiler.

#include <dlfcn.h>
#include <assert.h>
namespace gtk
{
struct Object;
using Unref = auto (Object*) -> void;
using Try_Init = auto () -> bool;
using Iterate_Main_Context = auto (Object*, bool) -> bool;
using New_Alert_Dialog = auto (char const* fmt, ...) -> Object*;
using Show_Alert_Dialog = auto (Object* self, Object* parent) -> void;
using Set_Alert_Dialog_Detail = auto (Object*, char const*) -> void;
using Count_List_Items = auto (Object*) -> unsigned;
using List_Toplevels = auto () -> Object*;
auto show_messgage_box(char const* title, char const* message) -> void
{
auto lib = dlopen("/usr/lib/libgtk-4.so", RTLD_LAZY | RTLD_LOCAL);
assert(lib);
auto unref = (gtk::Unref*) dlsym(lib, "g_object_unref");
auto iterate_main_context = (gtk::Iterate_Main_Context*) dlsym(lib, "g_main_context_iteration");
auto try_init = (gtk::Try_Init*) dlsym(lib, "gtk_init_check");
auto new_alert_dialog = (gtk::New_Alert_Dialog*) dlsym(lib, "gtk_alert_dialog_new");
auto show_alert_dialog = (gtk::Show_Alert_Dialog*) dlsym(lib, "gtk_alert_dialog_show");
auto set_alert_dialog_detail = (gtk::Set_Alert_Dialog_Detail*) dlsym(lib, "gtk_alert_dialog_set_detail");
auto list_toplevels = (gtk::List_Toplevels*) dlsym(lib, "gtk_window_get_toplevels");
auto count_list_items = (gtk::Count_List_Items*) dlsym(lib, "g_list_model_get_n_items");
assert(unref);
assert(iterate_main_context);
assert(try_init);
assert(new_alert_dialog);
assert(show_alert_dialog);
assert(set_alert_dialog_detail);
assert(list_toplevels);
assert(count_list_items);
if (!try_init()) return;
auto dialog = new_alert_dialog("%s", title);
set_alert_dialog_detail(dialog, message);
show_alert_dialog(dialog, nullptr);
while (count_list_items(list_toplevels()) > 0u) {
iterate_main_context(nullptr, true);
}
unref(dialog);
dlclose(lib);
}
}
int main()
{
gtk::show_messgage_box("Hi", "Hello world!");
gtk::show_messgage_box("Fatal Error", "Something bad happened.\nThere is nothing you can do.");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment