GTK Event Dispatch main loop is now created in the 'non-deprecated' way.

This commit is contained in:
nathan 2017-11-15 21:34:39 +01:00
parent c1520e1533
commit 5e3fec0909
8 changed files with 174 additions and 48 deletions

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.jna.linux;
import com.sun.jna.Pointer;
public
class GMainContext extends GObject {
public
GMainContext() {
}
public
GMainContext(Pointer p) {
super(p);
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.jna.linux;
import com.sun.jna.Pointer;
public
class GMainLoop extends GObject {
public
GMainLoop() {
}
public
GMainLoop(Pointer p) {
super(p);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2017 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.jna.linux;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
public
class GObject extends PointerType {
public
GObject() {
}
public
GObject(Pointer p) {
super(p);
}
@Override
protected
void finalize() throws Throwable {
super.finalize();
}
public
void ref() {
Gobject.g_object_ref(getPointer());
}
public
void unref() {
Gobject.g_object_unref(getPointer());
}
}

View File

@ -44,6 +44,7 @@ class Gobject {
// objdump -T /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 | grep block
public static native void g_object_ref(Pointer object);
public static native void g_object_unref(Pointer object);
public static native void g_object_force_floating(Pointer object);

View File

@ -57,18 +57,6 @@ interface Gtk {
Function gtk_status_icon_position_menu = GtkLoader.gtk_status_icon_position_menu;
/**
* Adds a function to be called whenever there are no higher priority events pending. If the function returns FALSE it is automatically
* removed from the list of event sources and will not be called again.
* <p>
* This variant of g_idle_add_full() calls function with the GDK lock held. It can be thought of a MT-safe version for GTK+ widgets
* for the following use case, where you have to worry about idle_callback() running in thread A and accessing self after it has
* been finalized in thread B.
*/
int gdk_threads_add_idle_full(int priority, FuncCallback function, Pointer data, Pointer notify);
/**
* This would NORMALLY have a 2nd argument that is a String[] -- however JNA direct-mapping DOES NOT support this. We are lucky
* enough that we just pass 'null' as the second argument, therefore, we don't have to define that parameter here.
@ -76,18 +64,31 @@ interface Gtk {
boolean gtk_init_check(int argc);
/**
* Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the
* innermost invocation of the main loop return.
* Creates a new GMainLoop structure.
*/
void gtk_main();
GMainLoop g_main_loop_new(Pointer context, boolean is_running);
/**
* Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS you know
* what you're doing!
* Runs a main loop until g_main_loop_quit() is called on the loop. If this is called for the thread of the loop's GMainContext,
* it will process events from the loop, otherwise it will simply wait.
*/
void gtk_main_quit();
void g_main_loop_run(GMainLoop loop);
/**
* Stops a GMainLoop from running. Any calls to g_main_loop_run() for the loop will return.
* Note that sources that have already been dispatched when g_main_loop_quit() is called will still be executed.
*/
void g_main_loop_quit(GMainLoop loop);
/**
* Returns the GMainContext of loop .
*/
GMainContext g_main_loop_get_context(GMainLoop loop);
/**
* Invokes a function in such a way that context is owned during the invocation of function .
*/
void g_main_context_invoke(GMainContext c, FuncCallback func, Pointer data);
/**
* Creates a new GtkMenu

View File

@ -29,21 +29,29 @@ public
class Gtk2 implements Gtk {
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk
@Override
public native
int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify);
@Override
public native
boolean gtk_init_check(final int argc);
@Override
public native
void gtk_main();
GMainLoop g_main_loop_new(Pointer context, boolean is_running);
@Override
public native
void gtk_main_quit();
GMainContext g_main_loop_get_context(GMainLoop loop);
@Override
public native
void g_main_loop_run(GMainLoop loop);
@Override
public native
void g_main_context_invoke(GMainContext c, FuncCallback func, Pointer data);
@Override
public native
void g_main_loop_quit(GMainLoop loop);
@Override
public native

View File

@ -128,21 +128,29 @@ class Gtk3 implements Gtk {
this.gtk_widget_get_preferred_size(widget, requisition, null);
}
@Override
public native
int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify);
@Override
public native
boolean gtk_init_check(final int argc);
@Override
public native
void gtk_main();
GMainLoop g_main_loop_new(Pointer context, boolean is_running);
@Override
public native
void gtk_main_quit();
GMainContext g_main_loop_get_context(GMainLoop loop);
@Override
public native
void g_main_loop_run(GMainLoop loop);
@Override
public native
void g_main_context_invoke(GMainContext c, FuncCallback func, Pointer data);
@Override
public native
void g_main_loop_quit(GMainLoop loop);
@Override
public native

View File

@ -52,6 +52,9 @@ class GtkEventDispatch {
@SuppressWarnings("FieldCanBeLocal")
private static Thread gtkUpdateThread = null;
private static GMainLoop mainloop;
private static GMainContext context;
// when debugging the EDT, we need a longer timeout.
private static final boolean debugEDT = false;
@ -72,7 +75,6 @@ class GtkEventDispatch {
// startup the GTK GUI event loop. There can be multiple/nested loops.
if (!GtkLoader.alreadyRunningGTK) {
// If JavaFX/SWT is used, this is UNNECESSARY (we can detect if the GTK main_loop is running)
@ -91,24 +93,22 @@ class GtkEventDispatch {
}
// prep for the event loop.
// GThread.g_thread_init(null); would be needed for g_idle_add()
if (!Gtk2.gtk_init_check(0)) {
throw new RuntimeException("Error starting GTK");
}
// gdk_threads_enter(); would be needed for g_idle_add()
// create the main-loop
mainloop = Gtk2.g_main_loop_new(null, false);
context = Gtk2.g_main_loop_get_context(mainloop);
// blocks until we quit the main loop
Gtk2.g_main_loop_run(mainloop);
if (orig != null) {
Glib.g_log_set_default_handler(orig, null);
}
// blocks unit quit
Gtk2.gtk_main();
// clean up threads
// gdk_threads_leave(); would be needed for g_idle_add()
}
};
gtkUpdateThread.setDaemon(false); // explicitly NOT daemon so that this will hold the JVM open as necessary
@ -302,10 +302,6 @@ class GtkEventDispatch {
@Override
public
int callback(final Pointer data) {
synchronized (gtkCallbacks) {
gtkCallbacks.removeFirst(); // now that we've 'handled' it, we can remove it from our callback list
}
isDispatch.set(true);
try {
@ -314,6 +310,10 @@ class GtkEventDispatch {
isDispatch.set(false);
}
synchronized (gtkCallbacks) {
gtkCallbacks.removeFirst(); // now that we've 'handled' it, we can remove it from our callback list
}
return Gtk2.FALSE; // don't want to call this again
}
};
@ -322,8 +322,8 @@ class GtkEventDispatch {
gtkCallbacks.offer(callback); // prevent GC from collecting this object before it can be called
}
// the correct way to do it. Add with a slightly higher value
Gtk2.gdk_threads_add_idle_full(100, callback, null, null);
// explicitly invoke on our new GTK main loop context
Gtk2.g_main_context_invoke(context, callback, null);
}
/**
@ -352,7 +352,8 @@ class GtkEventDispatch {
void run() {
// If JavaFX/SWT is used, this is UNNECESSARY (and will break SWT/JavaFX shutdown)
if (!GtkLoader.alreadyRunningGTK) {
Gtk2.gtk_main_quit();
Gtk2.g_main_loop_quit(mainloop);
// Gtk2.gtk_main_quit();
}
started = false;