IDEA-240623: use separate glib-loop (in separate thread with thread-default context)

fixed IDEA-240623 KDE Global Menu does not work. But it's work with PhpStorm

GitOrigin-RevId: 56b75d6ae4209a12dfc4fcbbc6e9486b07e868d2
This commit is contained in:
artem.bochkarev
2021-02-26 14:08:55 +03:00
committed by intellij-monorepo-bot
parent 5ed90ce495
commit 60272bba37
6 changed files with 60 additions and 61 deletions

Binary file not shown.

View File

@@ -23,15 +23,15 @@ endif (__DBUSMENU_HAVE_W_ALL)
find_library(LIB_GLIB NAMES glib libglib libglib-2.0.so.0 PATHS /lib/x86_64-linux-gnu)
MESSAGE("LIB_GLIB: " ${LIB_GLIB})
find_library(LIB_DBUSMENU NAMES libdbusmenu-glib.so PATHS /usr/lib/x86_64-linux-gnu)
MESSAGE("LIB_DBUSMENU: " ${LIB_DBUSMENU})
find_library(LIB_GIO NAMES libgio-2.0.so.0 PATHS /usr/lib/x86_64-linux-gnu)
MESSAGE("LIB_GIO: " ${LIB_GIO})
find_library(LIB_GOBJ NAMES libgobject-2.0.so.0 PATHS /usr/lib/x86_64-linux-gnu)
MESSAGE("LIB_GOBJ: " ${LIB_GOBJ})
# use patched library
set(LIB_DBUSMENU "${PROJECT_SOURCE_DIR}/libdbusmenu-glib.a")
set(GLIB_INCLUDE_DIRS /usr/include/glib-2.0 /usr/lib/x86_64-linux-gnu/glib-2.0/include)
set(DBUSMENU_GLIB_INCLUDE_DIRS /usr/include/libdbusmenu-glib-0.4)
@@ -48,12 +48,16 @@ set(SOURCE_FILES DbusMenuWrapper.c)
add_library(dbm SHARED ${SOURCE_FILES})
target_link_libraries(dbm ${LIB_GLIB} ${LIB_GIO} ${LIB_DBUSMENU} ${LIB_GOBJ})
add_executable(dbmexec test.cc)
target_link_libraries(dbmexec dbm ${LIB_GLIB} ${LIB_GIO} ${LIB_DBUSMENU} ${LIB_DBUSMENU_GTK} ${LIB_GOBJ} ${LIB_GTK} ${LIB_GDK})
if (TESTS_ENABLED)
find_library(LIB_GTK NAMES libgtk-3.so PATHS /usr/lib/x86_64-linux-gnu)
MESSAGE("LIB_GTK: " ${LIB_GTK})
add_custom_command(TARGET dbm POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:dbm> /home/parallels/projects/IDEA/community/bin/linux/libdbm64.so)
add_custom_command(TARGET dbm POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:dbm> /home/parallels/IdeaProjects/TestMenu/libdbm.so)
set(GTK_INCLUDE_DIRS /usr/include/gtk-3.0)
include_directories(${GTK_INCLUDE_DIRS} /usr/include/pango-1.0 /usr/include/harfbuzz /usr/include/cairo /usr/include/gdk-pixbuf-2.0 /usr/include/atk-1.0)
find_library(LIB_GDK NAMES libgdk-3.so PATHS /usr/lib/x86_64-linux-gnu) # needs to get xid from GtkWidget
MESSAGE("LIB_GDK: " ${LIB_GDK})
add_executable(dbmexec test.cc)
target_link_libraries(dbmexec dbm ${LIB_GLIB} ${LIB_GIO} ${LIB_DBUSMENU} ${LIB_DBUSMENU_GTK} ${LIB_GOBJ} ${LIB_GTK} ${LIB_GDK})
endif(TESTS_ENABLED)

View File

@@ -21,7 +21,8 @@
static jlogger _ourLogger = NULL;
static jrunnable _ourOnServiceAppearedCallback = NULL;
static jrunnable _ourOnServiceVanishedCallback = NULL;
static guint _ourServiceNameWatcher = 0;
static GMainContext * glib_main_context = NULL;
typedef struct _WndInfo {
guint32 xid;
@@ -79,25 +80,20 @@ static void _onNameVanished(GDBusConnection *connection, const gchar *name, gpoi
(*((jrunnable) _ourOnServiceVanishedCallback))();
}
void startWatchDbus(jlogger jlog, jrunnable onAppmenuServiceAppeared, jrunnable onAppmenuServiceVanished) {
// NOTE: main-loop is necessary for communication with dbus (via glib and it's signals)
// It is started in java (see invocation com.sun.javafx.application.PlatformImpl.startup())
_ourLogger = jlog;
// NOTE: main-loop is necessary for communication with dbus (via glib and it's signals)
void runMainLoop(jlogger jlogger, jrunnable onAppmenuServiceAppeared, jrunnable onAppmenuServiceVanished) {
glib_main_context = g_main_context_new();
g_main_context_push_thread_default(glib_main_context); // make this ctx default for current thread
_ourLogger = jlogger;
_ourOnServiceAppearedCallback = onAppmenuServiceAppeared;
_ourOnServiceVanishedCallback = onAppmenuServiceVanished;
_ourServiceNameWatcher = g_bus_watch_name(G_BUS_TYPE_SESSION, DBUS_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE, _onNameAppeared, _onNameVanished, NULL, NULL);
g_bus_watch_name(G_BUS_TYPE_SESSION, DBUS_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE, _onNameAppeared, _onNameVanished, NULL, NULL);
// NOTE: Callbacks will be invoked in the thread-default main context of the thread you are calling g_bus_watch_name from.
// _info("start watching for dbus name 'com.canonical.AppMenu.Registrar'");
}
void stopWatchDbus() {
g_bus_unwatch_name(_ourServiceNameWatcher);
// _info("glib main loop is stopped");
}
// used when javaFX can't be started
void runMainLoop(jlogger jlogger, jrunnable onAppmenuServiceAppeared, jrunnable onAppmenuServiceVanished) {
startWatchDbus(jlogger, onAppmenuServiceAppeared, onAppmenuServiceVanished);
g_main_loop_run(g_main_loop_new(g_main_context_new(), FALSE));
GMainLoop * main_loop = g_main_loop_new(glib_main_context, FALSE);
g_main_loop_run(main_loop);
}
static void _onDbusOwnerChange(GObject *gobject, GParamSpec *pspec, gpointer user_data) {
@@ -199,8 +195,10 @@ static void _releaseWindow(WndInfo *wi) {
if (wi->registrar != NULL) {
_unregisterWindow(wi->xid, wi->registrar);
if (wi->linkedXids != NULL) {
for (GList* l = wi->linkedXids; l != NULL; l = l->next)
_unregisterWindow((guint32)l->data, wi->registrar);
for (GList* l = wi->linkedXids; l != NULL; l = l->next) {
const guint32 xid = ((unsigned long)l->data) & 0xFFFFFFFF;
_unregisterWindow(xid, wi->registrar);
}
}
g_object_unref(wi->registrar);
@@ -326,7 +324,7 @@ void bindNewWindow(WndInfo * wi, guint32 windowXid) {
}
// _logmsg(LOG_LEVEL_INFO, "bind new window 0x%lx", windowXid);
wi->linkedXids = g_list_append(wi->linkedXids, (gpointer)windowXid);
wi->linkedXids = g_list_append(wi->linkedXids, (void *)(unsigned long)windowXid);
}
void unbindWindow(WndInfo * wi, guint32 windowXid) {
@@ -337,7 +335,7 @@ void unbindWindow(WndInfo * wi, guint32 windowXid) {
_unregisterWindow(windowXid, wi->registrar);
if (wi->linkedXids != NULL)
wi->linkedXids = g_list_remove(wi->linkedXids, (gpointer)windowXid);
wi->linkedXids = g_list_remove(wi->linkedXids, (void *)(unsigned long)windowXid);
}
static gboolean _execReleaseWindow(gpointer user_data) {
@@ -510,7 +508,18 @@ static gboolean _showMenuItem(gpointer item) {
return FALSE;
}
void showMenuItem(DbusmenuMenuitem* item) { g_idle_add(_showMenuItem, item); }
static guint
execInMainContext(GSourceFunc func, gpointer data) {
GSource *source = g_timeout_source_new(0);
g_source_set_callback(source, func, data, NULL);
guint result = g_source_attach(source, glib_main_context);
g_source_unref(source);
return result;
}
void showMenuItem(DbusmenuMenuitem* item) {
execInMainContext(_showMenuItem, item);
}
void setItemLabel(DbusmenuMenuitem *item, const char *label) {
dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, label);
@@ -577,5 +586,10 @@ static gboolean _execJRunnable(gpointer user_data) {
void execOnMainLoop(jrunnable run) {
// _info("scheduled execOnMain");
g_idle_add(_execJRunnable, run);
if (glib_main_context == NULL) {
_logmsg(LOG_LEVEL_ERROR, "execOnMainLoop: glib_main_context wasn't initialized");
return;
}
execInMainContext(_execJRunnable, run);
}

Binary file not shown.

View File

@@ -7,7 +7,6 @@
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
static void _onDestroyWindow(void) {
gtk_main_quit();
return;
@@ -30,23 +29,16 @@ int main (int argv, char ** argc) {
WndInfo* wi = registerWindow(wndxid, &_testHandler);
// populate menu
DbusmenuMenuitem* root1 = addRootMenu(wi, 1);
setItemLabel(root1, "root1");
DbusmenuMenuitem* root1 = addRootMenu(wi, 1, "root1");
FILE *f;
char buffer[1024*1024];
gsize length;
f = fopen ("../test.png", "r");
length = fread (buffer, 1, sizeof(buffer), f);
fclose (f);
DbusmenuMenuitem* item1 = addMenuItem(root1, 2, true);
setItemLabel(item1, "item1");
setItemIcon(item1, buffer, length);
DbusmenuMenuitem* sub1 = addMenuItem(sub1, 3, false);
setItemLabel(sub1, "sub1");
setItemIcon(sub1, buffer, length);
DbusmenuMenuitem* item1 = addMenuItem(root1, 2, "item1", ITEM_SIMPLE, 0);
// setItemIcon(item1, buffer, length);
DbusmenuMenuitem* sub1 = addMenuItem(item1, 3, "sub1", ITEM_SUBMENU, 0);
// setItemIcon(sub1, buffer, length);
// run main loop
gtk_main();

View File

@@ -53,8 +53,6 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
interface GlobalMenuLib extends Library {
void startWatchDbus(JLogger jlogger, JRunnable onAppmenuServiceAppeared, JRunnable onAppmenuServiceVanished);
void runMainLoop(JLogger jlogger, JRunnable onAppmenuServiceAppeared, JRunnable onAppmenuServiceVanished);
void execOnMainLoop(JRunnable run);
@@ -218,19 +216,10 @@ public final class GlobalMenuLinux implements LinuxGlobalMenuEventHandler, Dispo
}
};
// NOTE: Linux implementation of JavaFX starts native main loop with GtkApplication._runLoop()
try {
Class<?> platformImpl = Class.forName("com.sun.javafx.application.PlatformImpl");
Method startup = platformImpl.getMethod("startup", Runnable.class);
Runnable r = () -> ourLib.startWatchDbus(ourGLogger, ourOnAppmenuServiceAppeared, ourOnAppmenuServiceVanished);
startup.invoke(null, r);
}
catch (Throwable e) {
LOG.info("can't start main loop via JavaFX (will run it manually): " + e.getMessage());
final Thread glibMain = new Thread(() -> ourLib.runMainLoop(ourGLogger, ourOnAppmenuServiceAppeared, ourOnAppmenuServiceVanished),
"GlobalMenuLinux loop");
glibMain.start();
}
final String threadName = "GlobalMenuLinux loop";
new Thread(() -> ourLib.runMainLoop(ourGLogger, ourOnAppmenuServiceAppeared, ourOnAppmenuServiceVanished),
threadName).start();
LOG.info("Start glib main loop in thread: " + threadName);
}
}