From 3c64dd39ca5dffa03cd1144e780c3a263df444ff Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 28 Aug 2023 22:25:28 +0100 Subject: [PATCH] main: set up gtk and tray icon --- src/main.cxx | 78 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/src/main.cxx b/src/main.cxx index c7eca75..63e534a 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -1,5 +1,6 @@ #include #include +#include #include "browser.hxx" #include "browser/app.hxx" @@ -10,14 +11,19 @@ #endif #if defined(__linux__) +#include +#include #include #include -#include +#include #endif #if defined(CEF_X11) #include +constexpr int img_size = 24; +constexpr int img_bps = 8; + int XErrorHandlerImpl(Display* display, XErrorEvent* event) { fmt::print( "X error received: type {}, serial {}, error_code {}, request_code {}, minor_code {}\n", @@ -35,6 +41,7 @@ int XIOErrorHandlerImpl(Display* display) { } #endif +void GtkStart(CefMainArgs&, Browser::Client*); int BoltRunBrowserProcess(CefMainArgs, CefRefPtr); bool LockXdgDirectories(std::filesystem::path&, std::filesystem::path&); @@ -54,12 +61,6 @@ int BoltRunAnyProcess(CefMainArgs main_args) { } int BoltRunBrowserProcess(CefMainArgs main_args, CefRefPtr cef_app) { -#if defined(CEF_X11) - // X11 error handlers - XSetErrorHandler(XErrorHandlerImpl); - XSetIOErrorHandler(XIOErrorHandlerImpl); -#endif - // find and lock the xdg base directories (or an approximation of them on Windows) std::filesystem::path config_dir; std::filesystem::path data_dir; @@ -89,6 +90,15 @@ int BoltRunBrowserProcess(CefMainArgs main_args, CefRefPtr cef_app return exit_code; } + // start gtk and create a tray icon + GtkStart(main_args, client.get()); + +#if defined(CEF_X11) + // X11 error handlers - must be installed after gtk_init + XSetErrorHandler(XErrorHandlerImpl); + XSetIOErrorHandler(XIOErrorHandlerImpl); +#endif + // Block on the CEF message loop until CefQuitMessageLoop() is called CefRunMessageLoop(); CefShutdown(); @@ -223,3 +233,57 @@ int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t* lpCmdLine, i } } #endif + +// all these features exist in gtk3 and are deprecated for no reason at all, so ignore deprecation warnings +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +static void TrayPopupMenu(GtkStatusIcon* status_icon, guint button, guint32 activate_time, gpointer popup_menu) { + gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time); +} + +static void TrayActivate(GtkStatusIcon* status_icon, gpointer popup_menu) { + TrayPopupMenu(status_icon, gtk_get_current_event()->button.button, gtk_get_current_event_time(), popup_menu); +}; + +static void TrayOpenLauncher(GtkMenuItem*, Browser::Client* client) { + client->OpenLauncher(); +} + +static void TrayExit(GtkMenuItem*, Browser::Client* client) { + client->Exit(); +} + +void GtkStart(CefMainArgs& args, Browser::Client* client) { + gdk_set_allowed_backends("x11"); + gtk_init(&args.argc, &args.argv); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( + client->GetTrayIcon(), + GDK_COLORSPACE_RGB, + true, + img_bps, + img_size, + img_size, + img_size * 4, + [](unsigned char*, void*){}, + nullptr + ); + GtkStatusIcon* icon = gtk_status_icon_new_from_pixbuf(pixbuf); + gtk_status_icon_set_tooltip_text(icon, "Bolt Launcher"); + gtk_status_icon_set_title(icon, "Bolt Launcher"); + GtkWidget* menu = menu = gtk_menu_new(); + GtkWidget* menu_open = gtk_menu_item_new_with_label("Open"); + GtkWidget* menu_exit = gtk_menu_item_new_with_label("Exit"); + g_signal_connect(G_OBJECT(menu_open), "activate", G_CALLBACK(TrayOpenLauncher), client); + g_signal_connect(G_OBJECT(menu_exit), "activate", G_CALLBACK(TrayExit), client); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_open); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_exit); + gtk_widget_show_all (menu); + g_signal_connect(GTK_STATUS_ICON(icon), "activate", G_CALLBACK(TrayActivate), menu); + g_signal_connect(GTK_STATUS_ICON(icon), "popup-menu", G_CALLBACK(TrayPopupMenu), menu); + GtkWidget* menu_bar = gtk_menu_bar_new(); + GtkWidget* menu_item_top_level = gtk_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_item_top_level); + GtkWidget* main_menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item_top_level), main_menu); +} +#pragma GCC diagnostic pop