M src/meson.build +4 -1
@@ 2,6 2,7 @@ project('wofij', 'c', 'java', default_op
cc = meson.get_compiler('c')
wofi = dependency('wofi')
+pixbuf = dependency('gdk-pixbuf-2.0')
java_home = get_option('jdk_home')
mode_class = get_option('mode_class')
@@ 20,16 21,18 @@ srcdir = '../wofi_jni/src'
inc = include_directories('../wofi_jni/inc', java_home + '/include', java_home + '/include/linux')
-deps = [wofi, jvm]
+deps = [wofi, jvm, pixbuf]
jsources = [jsrcdir + '/Cache.java',
jsrcdir + '/Map.java',
jsrcdir + '/Mode.java',
jsrcdir + '/Widget.java',
+ jsrcdir + '/WidgetBuilder.java',
jsrcdir + '/Wofi.java']
sources = [srcdir + '/cache_jni.c',
srcdir + '/map_jni.c',
+ srcdir + '/widget_builder_jni.c',
srcdir + '/wofi_jni.c']
jar(meson.project_name(), jsources)
M src/ninja/scoopta/software/wofij/Widget.java +5 -1
@@ 1,5 1,5 @@
/*
- * Copyright (C) 2020 Scoopta
+ * Copyright (C) 2020-2022 Scoopta
* This file is part of WofiJ
* WofiJ is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ 31,4 31,8 @@ public final class Widget {
}
widget = Wofi.createWidget(wofi.mode, ctext.getBytes(), (searchText + "\0").getBytes(), cactions.getBytes(), actions.length);
}
+
+ Widget(long widget) {
+ this.widget = widget;
+ }
}
A => src/ninja/scoopta/software/wofij/WidgetBuilder.java +68 -0
@@ 0,0 1,68 @@
+/*
+ * Copyright (C) 2022 Scoopta
+ * This file is part of WofiJ
+ * WofiJ is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ WofiJ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with WofiJ. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ninja.scoopta.software.wofij;
+
+public final class WidgetBuilder {
+ private final long builder;
+
+ public WidgetBuilder(Wofi wofi, int actions) {
+ builder = init(wofi.mode, actions);
+ }
+
+ private WidgetBuilder(long builder) {
+ this.builder = builder;
+ }
+
+ public final void setSearchText(String searchText) {
+ setSearchText(builder, (searchText + "\0").getBytes());
+ }
+
+ public final void setAction(String action) {
+ setAction(builder, (action + "\0").getBytes());
+ }
+
+ public final void insertText(String text, String... classes) {
+ String cclasses = "";
+ for(String tmp : classes) {
+ cclasses += tmp + "\0";
+ }
+ insertText(builder, (text + "\0").getBytes(), cclasses.getBytes(), classes.length);
+ }
+
+ public final WidgetBuilder getIdx(int idx) {
+ return new WidgetBuilder(getIdx(builder, idx));
+ }
+
+ public final Widget getWidget() {
+ return new Widget(getWidget(builder));
+ }
+
+ private static final native long init(long mode, int actions);
+
+ private static final native void setSearchText(long builder, byte[] searchText);
+
+ private static final native void setAction(long builder, byte[] action);
+
+ private static final native void insertText(long builder, byte[] text, byte[] classes, int classCount);
+
+ private static final native void insertImage(long builder, long pixbuf, byte[] classes, int classCount);
+
+ private static final native long getIdx(long builder, int idx);
+
+ private static final native long getWidget(long builder);
+}
A => wofi_jni/inc/widget_builder_jni.h +25 -0
@@ 0,0 1,25 @@
+/*
+ * Copyright (C) 2022 Scoopta
+ * This file is part of WofiJ
+ * WofiJ is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ WofiJ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with WofiJ. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WIDGET_BUILDER_JNI_H
+#define WIDGET_BUILDER_JNI_H
+
+#include <jni.h>
+
+void widget_builder_jni_init(JNIEnv* env);
+
+#endif
A => wofi_jni/src/widget_builder_jni.c +140 -0
@@ 0,0 1,140 @@
+/*
+ * Copyright (C) 2022 Scoopta
+ * This file is part of WofiJ
+ * WofiJ is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ WofiJ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with WofiJ. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <widget_builder_jni.h>
+
+#include <widget_builder_api.h>
+
+static struct widget_builder* init(JNIEnv* env, jclass class, struct mode* mode, jint actions) {
+ (void) env;
+ (void) class;
+ return wofi_widget_builder_init(mode, actions);
+}
+
+static void set_search_text(JNIEnv* env, jclass class, struct widget_builder* builder, jbyteArray arr) {
+ (void) class;
+ char* search_text = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ wofi_widget_builder_set_search_text(builder, search_text);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, search_text, 0);
+}
+
+static void set_action(JNIEnv* env, jclass class, struct widget_builder* builder, jbyteArray arr) {
+ (void) class;
+ char* action = (*env)->GetPrimitiveArrayCritical(env, arr, NULL);
+ wofi_widget_builder_set_action(builder, action);
+ (*env)->ReleasePrimitiveArrayCritical(env, arr, action, 0);
+}
+
+static void insert_text(JNIEnv* env, jclass class, struct widget_builder* builder, jbyteArray text, jbyteArray classes, jint class_count) {
+ (void) class;
+ char* text_str = (*env)->GetPrimitiveArrayCritical(env, text, NULL);
+ char* class_str = (*env)->GetPrimitiveArrayCritical(env, classes, NULL);
+
+ char* tmp_class = class_str;
+
+ struct wl_list class_list;
+ wl_list_init(&class_list);
+
+ for(ssize_t count = 0; count < class_count; ++count) {
+ struct css_class* node = malloc(sizeof(struct css_class));
+ node->class = tmp_class;
+ tmp_class += strlen(tmp_class) + 1;
+ wl_list_insert(&class_list, &node->link);
+ }
+
+ wofi_widget_builder_insert_text_with_list(builder, text_str, &class_list);
+
+ struct css_class* node, *tmp;
+ wl_list_for_each_safe(node, tmp, &class_list, link) {
+ free(node);
+ }
+
+ (*env)->ReleasePrimitiveArrayCritical(env, classes, class_str, 0);
+ (*env)->ReleasePrimitiveArrayCritical(env, text, text_str, 0);
+}
+
+static void insert_image(JNIEnv* env, jclass class, struct widget_builder* builder, GdkPixbuf* pixbuf, jbyteArray classes, jint class_count) {
+ (void) class;
+ char* class_str = (*env)->GetPrimitiveArrayCritical(env, classes, NULL);
+
+ char* tmp_class = class_str;
+
+ struct wl_list class_list;
+ wl_list_init(&class_list);
+
+ for(ssize_t count = 0; count < class_count; ++count) {
+ struct css_class* node = malloc(sizeof(struct css_class));
+ node->class = tmp_class;
+ tmp_class += strlen(tmp_class) + 1;
+ wl_list_insert(&class_list, &node->link);
+ }
+
+ wofi_widget_builder_insert_image_with_list(builder, pixbuf, &class_list);
+
+ struct css_class* node, *tmp;
+ wl_list_for_each_safe(node, tmp, &class_list, link) {
+ free(node);
+ }
+
+ (*env)->ReleasePrimitiveArrayCritical(env, classes, class_str, 0);
+}
+
+static struct widget_builder* get_idx(JNIEnv* env, jclass class, struct widget_builder* builder, jint idx) {
+ (void) env;
+ (void) class;
+ return wofi_widget_builder_get_idx(builder, idx);
+}
+
+static struct widget* get_widget(JNIEnv* env, jclass class, struct widget_builder* builder) {
+ (void) env;
+ (void) class;
+ return wofi_widget_builder_get_widget(builder);
+}
+
+void widget_builder_jni_init(JNIEnv* env) {
+ JNINativeMethod natives[7];
+ natives[0].name = "init";
+ natives[0].signature = "(JI)J";
+ natives[0].fnPtr = init;
+
+ natives[1].name = "setSearchText";
+ natives[1].signature = "(J[B)V";
+ natives[1].fnPtr = set_search_text;
+
+ natives[2].name = "setAction";
+ natives[2].signature = "(J[B)V";
+ natives[2].fnPtr = set_action;
+
+ natives[3].name = "insertText";
+ natives[3].signature = "(J[B[BI)V";
+ natives[3].fnPtr = insert_text;
+
+ natives[4].name = "insertImage";
+ natives[4].signature = "(JJ[BI)V";
+ natives[4].fnPtr = insert_image;
+
+ natives[5].name = "getIdx";
+ natives[5].signature = "(JI)J";
+ natives[5].fnPtr = get_idx;
+
+ natives[6].name = "getWidget";
+ natives[6].signature = "(J)J";
+ natives[6].fnPtr = get_widget;
+
+ jclass widget_builder = (*env)->FindClass(env, "ninja/scoopta/software/wofij/WidgetBuilder");
+ (*env)->RegisterNatives(env, widget_builder, natives, sizeof(natives) / sizeof(JNINativeMethod));
+}
M wofi_jni/src/wofi_jni.c +16 -9
@@ 1,5 1,5 @@
/*
- * Copyright (C) 2020 Scoopta
+ * Copyright (C) 2020-2022 Scoopta
* This file is part of WofiJ
* WofiJ is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ 21,6 21,7 @@
#include <map_jni.h>
#include <cache_jni.h>
+#include <widget_builder_jni.h>
#include <map.h>
#include <utils.h>
@@ 29,8 30,10 @@
#include <jni.h>
static struct mode* mode;
-static JNIEnv* env;
+static JavaVM* jvm;
+static JNIEnv* env, *gtk_env;
static jclass wofi;
+static bool on_gtk_thread = false;
static jbyteArray parse_image_escapes(JNIEnv* env, jclass class, jbyteArray arr) {
(void) class;
@@ 151,7 154,6 @@ void init(struct mode* _mode, struct map
void load(struct mode* _mode) {
mode = _mode;
- JavaVM* jvm;
JavaVMInitArgs args;
JavaVMOption options[1];
#ifdef CLASS_PATH
@@ 234,6 236,7 @@ void load(struct mode* _mode) {
map_jni_init(env);
cache_jni_init(env);
+ widget_builder_jni_init(env);
}
size_t get_arg_count(void) {
@@ 272,14 275,18 @@ bool no_entry(void) {
}
struct widget* get_widget(void) {
- jmethodID method = (*env)->GetStaticMethodID(env, wofi, "getWidget", "()J");
- return (struct widget*) (*env)->CallStaticLongMethod(env, wofi, method);
+ if(!on_gtk_thread) {
+ on_gtk_thread = true;
+ (*jvm)->AttachCurrentThread(jvm, (void**) >k_env, NULL);
+ }
+ jmethodID method = (*gtk_env)->GetStaticMethodID(gtk_env, wofi, "getWidget", "()J");
+ return (struct widget*) (*gtk_env)->CallStaticLongMethod(gtk_env, wofi, method);
}
void exec(const char* cmd) {
- jmethodID method = (*env)->GetStaticMethodID(env, wofi, "exec", "([B)V");
+ jmethodID method = (*gtk_env)->GetStaticMethodID(gtk_env, wofi, "exec", "([B)V");
size_t cmd_l = strlen(cmd);
- jbyteArray arr = (*env)->NewByteArray(env, cmd_l);
- (*env)->SetByteArrayRegion(env, arr, 0, cmd_l, (jbyte*) cmd);
- (*env)->CallStaticVoidMethod(env, wofi, method, arr);
+ jbyteArray arr = (*gtk_env)->NewByteArray(gtk_env, cmd_l);
+ (*gtk_env)->SetByteArrayRegion(gtk_env, arr, 0, cmd_l, (jbyte*) cmd);
+ (*gtk_env)->CallStaticVoidMethod(gtk_env, wofi, method, arr);
}