Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Linux support #106

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
3 changes: 2 additions & 1 deletion Plugins/Linux/StandaloneFileBrowser/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
cmake-build-debug
cmake-build-debug
build
11 changes: 5 additions & 6 deletions Plugins/Linux/StandaloneFileBrowser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.12)
project(StandaloneFileBrowser C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_C_FLAGS_DEBUG "-g")
set(CMAKE_C_FLAGS_RELEASE "-O2")

# Use the package PkgConfig to detect GTK+ headers/library files
FIND_PACKAGE(PkgConfig REQUIRED)
Expand All @@ -15,10 +18,6 @@ LINK_DIRECTORIES(${GTK3_LIBRARY_DIRS})
# Add other flags to the compiler
ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER})

add_library(${PROJECT_NAME} SHARED library.c library.h)
add_executable(dialog dialog.c)

TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${GTK3_LIBRARIES})

add_executable(${PROJECT_NAME}_EXE main.c)

TARGET_LINK_LIBRARIES(${PROJECT_NAME}_EXE ${PROJECT_NAME} ${GTK3_LIBRARIES})
TARGET_LINK_LIBRARIES(dialog ${GTK3_LIBRARIES})
22 changes: 22 additions & 0 deletions Plugins/Linux/StandaloneFileBrowser/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
LD = ld
CC = gcc
COPTS = -O2 -Wall -Wextra

.PHONY: all
all: build/main build/libStandaloneFileBrowser.so

build/dialog: dialog.c
mkdir -p build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make
build/dialog.bin.o: build/dialog
$(LD) -r -b binary -o build/dialog.bin.o build/dialog
build/library.o: library.c library.h
$(CC) $(COPTS) -o build/library.o -c library.c -fPIC
build/libStandaloneFileBrowser.so: build/dialog.bin.o build/library.o
$(CC) $(COPTS) -o build/libStandaloneFileBrowser.so build/library.o build/dialog.bin.o -shared
build/main: build/libStandaloneFileBrowser.so main.c library.h
$(CC) $(COPTS) -o build/main main.c build/libStandaloneFileBrowser.so

.PHONY: clean
clean:
rm -rf build
238 changes: 238 additions & 0 deletions Plugins/Linux/StandaloneFileBrowser/dialog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#include <stddef.h>
#include <gtk/gtk.h>
#include <string.h>
#include <malloc.h>
#include <stdbool.h>
#include <unistd.h>

char* strcat_realloc(char* str1, const char* str2) {
char* new_str;
size_t length;
size_t str1length;

if (str2 == NULL)
return str1;
str1length = 0;
if (str1 != NULL)
str1length = strlen(str1);
length = strlen(str2) + str1length;
new_str = (char*) realloc(str1, (1 + length) * sizeof(char));
if (new_str == NULL)
return str1;
new_str[str1length] = '\0';

strcat(new_str, str2);

return new_str;
}

// Rewrite strcpy() to avoid linking with memcpy function of high version (2.14) glibc ABI
char *strcpy_menci(char* dst, const char* src) {
char *p = dst;
do *p++ = *src; while (*src++);
return dst;
}

void DialogInit() {
gtk_init(0, NULL);
}

const char*
GTKOpenPanel(const char* title, const char* directory, const char* extension, bool multiselect,
GtkFileChooserAction action);

const char*
GTKSavePanel(const char* title, const char* directory, const char* defaultName, const char* filters);

void GTKSetFilters(const char* extension, GtkWidget* dialog);

const char* DialogOpenFilePanel(const char* title, const char* directory, const char* extension,
bool multiselect) {
return GTKOpenPanel(title, directory, extension, multiselect,
GTK_FILE_CHOOSER_ACTION_OPEN);
}

const char* DialogOpenFolderPanel(const char* title, const char* directory, bool multiselect) {
return GTKOpenPanel(title, directory, "", multiselect,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
}

const char* DialogSaveFilePanel(const char* title, const char* directory, const char* defaultName,
const char* filters) {
return GTKSavePanel(title, directory, defaultName, filters);
}

const char*
GTKOpenPanel(const char* title, const char* directory, const char* extensions, bool multiselect,
GtkFileChooserAction action) {
char* filename = NULL;
GtkWidget* dialog;
gint res;

dialog = gtk_file_chooser_dialog_new(title,
NULL,
action,
("_Cancel"),
GTK_RESPONSE_CANCEL,
("_Open"),
GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_select_multiple((GtkFileChooser*) dialog, multiselect);
gtk_file_chooser_set_current_folder((GtkFileChooser*) dialog, directory);

GTKSetFilters(extensions, dialog);

res = gtk_dialog_run(GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT) {
GtkFileChooser* chooser = GTK_FILE_CHOOSER (dialog);

if (multiselect) {
GSList* filenamepus = gtk_file_chooser_get_filenames(chooser);

int nIndex;
GSList* node;

char split[] = {(char)28, 0};
for (nIndex = 0; (node = g_slist_nth(filenamepus, (guint) nIndex)); nIndex++) {
if (nIndex == 0) {
filename = malloc((strlen(node->data) + 1) * sizeof(char));
strcpy_menci(filename, node->data);
continue;
}
filename = strcat_realloc(filename, split);
filename = strcat_realloc(filename, node->data);

g_free(node->data);
}
g_slist_free(filenamepus);
} else {
char* name = gtk_file_chooser_get_filename(chooser);
filename = malloc(strlen(name) * sizeof(char) + 1);
strcpy_menci(filename, name);
g_free(name);
}
} else { // if (res == GTK_RESPONSE_CANCEL) {
filename = malloc(sizeof(char));
filename[0] = '\0';
}

gtk_widget_destroy(dialog);

while (gtk_events_pending ())
gtk_main_iteration ();
return filename;
}

const char*
GTKSavePanel(const char* title, const char* directory, const char* defaultName, const char* filters) {
char* filename = NULL;
GtkWidget *dialog;
GtkFileChooser *chooser;
gint res;

dialog = gtk_file_chooser_dialog_new ("Save File",
NULL,
GTK_FILE_CHOOSER_ACTION_SAVE,
("_Cancel"),
GTK_RESPONSE_CANCEL,
("_Save"),
GTK_RESPONSE_ACCEPT,
NULL);
chooser = GTK_FILE_CHOOSER (dialog);

gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
gtk_file_chooser_set_current_name(chooser, defaultName);
gtk_file_chooser_set_current_folder(chooser, directory);

GTKSetFilters(filters, dialog);

res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_ACCEPT)
{
char* name = gtk_file_chooser_get_filename(chooser);
filename = malloc(strlen(name) * sizeof(char) + 1);
strcpy_menci(filename, name);
g_free(name);
}
else if (res == GTK_RESPONSE_CANCEL) {
filename = malloc(sizeof(char));
filename[0] = '\0';
}

gtk_widget_destroy (dialog);

while (gtk_events_pending ())
gtk_main_iteration ();
return filename;
}

void GTKSetFilters(const char* extensions, GtkWidget* dialog) {
if (extensions == NULL || strlen(extensions) == 0) {
return;
}

// Image Files;png,jpg,jpeg|Sound Files;mp3,wav|All Files;*
char* extensions_tok = malloc(sizeof(char) * (1+ strlen(extensions)));
extensions_tok = strcpy_menci(extensions_tok, extensions);
char* extensions_tok_beginning = extensions_tok;

char *extension_filters;
char *name_or_filters;
char *ext;
while ((extension_filters = strtok_r(extensions_tok, "|", &extensions_tok))) {
puts(extension_filters);
int i = 0;
GtkFileFilter* filter = gtk_file_filter_new();
if (extension_filters[0] == ';') { // no filter name
++i;
}
while ((name_or_filters = strtok_r(extension_filters, ";", &extension_filters))) {
puts(name_or_filters);
if (i == 0) {
// Filter Name
gtk_file_filter_set_name(filter, name_or_filters);
} else {
// Filter extentions
while ((ext = strtok_r(name_or_filters, ",", &name_or_filters))) {
puts(ext);
if (ext[0] == '*') {
gtk_file_filter_add_pattern(filter, ext);
} else {
char* ext_s;// = "*.";
ext_s = malloc(3 * sizeof(char));
ext_s = strcpy_menci(ext_s, "*.");
ext_s = strcat_realloc(ext_s, ext);
gtk_file_filter_add_pattern(filter, ext_s);
free(ext_s);
}
}
}
++i;
}
gtk_file_chooser_add_filter((GtkFileChooser*) dialog, filter);
}

free(extensions_tok_beginning);
}

int main(int argc, char *argv[]) {
DialogInit();

// fprintf(stderr, "operation = %s\n", argv[1]);

const char *result = NULL;
if (strcmp(argv[1], "DialogOpenFolderPanel") == 0) {
result = DialogOpenFolderPanel(argv[2], argv[3], argv[4][0] == '1');
} else if (strcmp(argv[1], "DialogOpenFilePanel") == 0) {
result = DialogOpenFilePanel(argv[2], argv[3], argv[4], argv[5][0] == '1');
} else if (strcmp(argv[1], "DialogSaveFilePanel") == 0) {
result = DialogSaveFilePanel(argv[2], argv[3], argv[4], argv[5]);
}

size_t size = result ? strlen(result) : 0;
write(STDOUT_FILENO, &size, sizeof(size));
if (result)
write(STDOUT_FILENO, result, size);

return 0;
}
Loading