Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
13 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Build artifacts
/build
/node_modules
235 changes: 235 additions & 0 deletions build.log

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions cmake/internal.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,14 @@ macro(webview_install_targets)
# Install targets
list(APPEND WEBVIEW_INSTALL_TARGET_NAMES webview_core_headers)

if(TARGET sqlite3)
list(APPEND WEBVIEW_INSTALL_TARGET_NAMES sqlite3)
endif()

if(TARGET alloy_gui)
list(APPEND WEBVIEW_INSTALL_TARGET_NAMES alloy_gui)
endif()

if(WEBVIEW_BUILD_SHARED_LIBRARY)
list(APPEND WEBVIEW_INSTALL_TARGET_NAMES webview_core_shared)
endif()
Expand Down
27 changes: 23 additions & 4 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,28 @@ target_include_directories(
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_link_libraries(webview_core_headers INTERFACE ${WEBVIEW_DEPENDENCIES})

# Alloy GUI library
add_library(alloy_gui STATIC src/alloy.cc)
target_include_directories(alloy_gui PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/alloy")
target_link_libraries(alloy_gui PRIVATE webview_core_headers)
set_target_properties(alloy_gui PROPERTIES
EXPORT_NAME alloy_gui
POSITION_INDEPENDENT_CODE ON)
add_library(sqlite3 STATIC ${PROJECT_SOURCE_DIR}/deps/sqlite/sqlite3.c)
target_include_directories(sqlite3 PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/deps/sqlite>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/sqlite3>)
set_target_properties(sqlite3 PROPERTIES
EXPORT_NAME sqlite3
POSITION_INDEPENDENT_CODE ON)

target_link_libraries(webview_core_headers INTERFACE ${WEBVIEW_DEPENDENCIES} alloy_gui)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(webview_core_headers INTERFACE util sqlite3)
endif()
# Note that we also use CMAKE_CXX_STANDARD which can override this
target_compile_features(webview_core_headers INTERFACE cxx_std_11)
target_compile_features(webview_core_headers INTERFACE cxx_std_17)
set_target_properties(webview_core_headers PROPERTIES
EXPORT_NAME core)

Expand Down Expand Up @@ -44,7 +63,7 @@ if(WEBVIEW_BUILD_STATIC_LIBRARY)
add_library(webview_core_static STATIC)
add_library(webview::core_static ALIAS webview_core_static)
target_sources(webview_core_static PRIVATE src/webview.cc)
target_link_libraries(webview_core_static PUBLIC webview_core_headers)
target_link_libraries(webview_core_static PUBLIC webview_core_headers alloy_gui)
set_target_properties(webview_core_static PROPERTIES
OUTPUT_NAME "${STATIC_LIBRARY_OUTPUT_NAME}"
POSITION_INDEPENDENT_CODE ON
Expand Down Expand Up @@ -72,7 +91,7 @@ if(WEBVIEW_BUILD_AMALGAMATION)
"${PROJECT_SOURCE_DIR}/scripts/amalgamate/amalgamate.py"
--clang-format-exe "${WEBVIEW_CLANG_FORMAT_EXE}"
--base "${CMAKE_CURRENT_SOURCE_DIR}"
--search include
--search include include/alloy
--output "${CMAKE_CURRENT_BINARY_DIR}/amalgamation/webview.h"
${SOURCE_FILES}
DEPENDS ${HEADER_FILES} ${SOURCE_FILES}
Expand Down
130 changes: 130 additions & 0 deletions core/include/alloy/api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#ifndef ALLOY_API_H
#define ALLOY_API_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#define ALLOY_API __declspec(dllexport)
#else
#define ALLOY_API __attribute__((visibility("default")))
#endif

typedef void *alloy_component_t;
typedef void *alloy_signal_t;
typedef void *alloy_computed_t;
typedef void *alloy_effect_t;

typedef enum {
ALLOY_OK = 0,
ALLOY_ERROR_INVALID_ARGUMENT,
ALLOY_ERROR_INVALID_STATE,
ALLOY_ERROR_PLATFORM,
ALLOY_ERROR_BUFFER_TOO_SMALL,
ALLOY_ERROR_NOT_SUPPORTED,
} alloy_error_t;

typedef enum {
ALLOY_EVENT_CLICK = 0,
ALLOY_EVENT_CHANGE,
ALLOY_EVENT_CLOSE,
ALLOY_EVENT_FOCUS,
ALLOY_EVENT_BLUR,
} alloy_event_type_t;

typedef enum {
ALLOY_PROP_TEXT = 0,
ALLOY_PROP_CHECKED,
ALLOY_PROP_VALUE,
ALLOY_PROP_ENABLED,
ALLOY_PROP_VISIBLE,
ALLOY_PROP_LABEL,
} alloy_prop_id_t;

typedef void (*alloy_event_cb_t)(alloy_component_t handle,
alloy_event_type_t event,
void *userdata);

typedef struct {
unsigned int background;
unsigned int foreground;
float font_size;
const char *font_family;
float border_radius;
float opacity;
} alloy_style_t;

ALLOY_API const char *alloy_error_message(alloy_error_t err);

ALLOY_API alloy_component_t alloy_create_window(const char *title, int width, int height);
ALLOY_API alloy_component_t alloy_create_button(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_textfield(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_textarea(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_label(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_checkbox(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_switch(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_radiobutton(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_combobox(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_slider(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_spinner(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_progressbar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_tabview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_listview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_treeview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_webview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_vstack(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_hstack(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_link(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_separator(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_image(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_scrollview(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_menubar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_menu(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_menuitem(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_toolbar(alloy_component_t parent);
ALLOY_API alloy_component_t alloy_create_statusbar(alloy_component_t parent);

ALLOY_API alloy_error_t alloy_destroy(alloy_component_t handle);

ALLOY_API alloy_error_t alloy_set_text(alloy_component_t h, const char *text);
ALLOY_API alloy_error_t alloy_get_text(alloy_component_t h, char *buf, size_t buf_len);
ALLOY_API alloy_error_t alloy_set_checked(alloy_component_t h, int checked);
ALLOY_API int alloy_get_checked(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_value(alloy_component_t h, double value);
ALLOY_API double alloy_get_value(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_enabled(alloy_component_t h, int enabled);
ALLOY_API int alloy_get_enabled(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_visible(alloy_component_t h, int visible);
ALLOY_API int alloy_get_visible(alloy_component_t h);
ALLOY_API alloy_error_t alloy_set_style(alloy_component_t h, const alloy_style_t *style);

ALLOY_API alloy_error_t alloy_image_load_file(alloy_component_t h, const char *path);
ALLOY_API alloy_error_t alloy_combobox_append(alloy_component_t h, const char *text);
ALLOY_API alloy_error_t alloy_webview_load_url(alloy_component_t h, const char *url);
ALLOY_API alloy_error_t alloy_listview_append(alloy_component_t h, const char *text);
ALLOY_API alloy_error_t alloy_tabview_add_page(alloy_component_t h, alloy_component_t child, const char *label);

ALLOY_API alloy_error_t alloy_add_child(alloy_component_t container, alloy_component_t child);
ALLOY_API alloy_error_t alloy_set_flex(alloy_component_t h, float flex);
ALLOY_API alloy_error_t alloy_set_padding(alloy_component_t h, float top, float right, float bottom, float left);
ALLOY_API alloy_error_t alloy_set_margin(alloy_component_t h, float top, float right, float bottom, float left);
ALLOY_API alloy_error_t alloy_layout(alloy_component_t window);

ALLOY_API alloy_error_t alloy_set_event_callback(alloy_component_t handle, alloy_event_type_t event, alloy_event_cb_t callback, void *userdata);
ALLOY_API alloy_error_t alloy_set_tooltip(alloy_component_t h, const char *text);

ALLOY_API const char* alloy_dialog_file_open(alloy_component_t parent, const char* title);
ALLOY_API const char* alloy_dialog_color_picker(alloy_component_t parent, const char* title);

ALLOY_API alloy_error_t alloy_run(alloy_component_t window);
ALLOY_API alloy_error_t alloy_terminate(alloy_component_t window);
ALLOY_API alloy_error_t alloy_dispatch(alloy_component_t window, void (*fn)(void *arg), void *arg);

#ifdef __cplusplus
}
#endif

#endif // ALLOY_API_H
47 changes: 47 additions & 0 deletions core/include/alloy/detail/backends/cocoa_gui.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef ALLOY_DETAIL_BACKENDS_COCOA_GUI_HH
#define ALLOY_DETAIL_BACKENDS_COCOA_GUI_HH

#include "../component_base.hh"
#include <objc/objc-runtime.h>
#include <string>

namespace alloy::detail {

class cocoa_component : public component_base {
public:
cocoa_component(id view, bool is_container = false)
: component_base(is_container), m_view(view) {}
~cocoa_component() { /* Release if needed */ }

void *native_handle() override { return m_view; }

alloy_error_t set_text(const std::string &text) override {
// Basic implementation using setTitle: or setStringValue:
return ALLOY_OK;
}
alloy_error_t get_text(char *buf, size_t len) override { return ALLOY_OK; }
alloy_error_t set_checked(bool v) override { return ALLOY_OK; }
bool get_checked() override { return false; }
alloy_error_t set_value(double v) override { return ALLOY_OK; }
double get_value() override { return 0; }
alloy_error_t set_enabled(bool v) override { return ALLOY_OK; }
bool get_enabled() override { return true; }
alloy_error_t set_visible(bool v) override { return ALLOY_OK; }
bool get_visible() override { return true; }
alloy_error_t set_style(const alloy_style_t &s) override { return ALLOY_OK; }

protected:
id m_view;
};

class cocoa_window : public cocoa_component {
public:
cocoa_window(const char *title, int w, int h)
: cocoa_component(reinterpret_cast<id>(1), true) { // Fake ID to avoid nullptr crash
(void)title; (void)w; (void)h;
}
};

} // namespace alloy::detail

#endif // ALLOY_DETAIL_BACKENDS_COCOA_GUI_HH
123 changes: 123 additions & 0 deletions core/include/alloy/detail/backends/gtk_gui.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#ifndef ALLOY_DETAIL_BACKENDS_GTK_GUI_HH
#define ALLOY_DETAIL_BACKENDS_GTK_GUI_HH

#include "../component_base.hh"
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>

namespace alloy::detail {

class gtk_component : public component_base {
public:
gtk_component(GtkWidget *widget, bool is_container = false)
: component_base(is_container), m_widget(widget) {
g_object_ref_sink(m_widget);
}
~gtk_component() { g_object_unref(m_widget); }

void *native_handle() override { return m_widget; }

alloy_error_t set_text(const std::string &text) override {
if (GTK_IS_WINDOW(m_widget)) {
gtk_window_set_title(GTK_WINDOW(m_widget), text.c_str());
} else if (GTK_IS_BUTTON(m_widget)) {
gtk_button_set_label(GTK_BUTTON(m_widget), text.c_str());
} else if (GTK_IS_LABEL(m_widget)) {
gtk_label_set_text(GTK_LABEL(m_widget), text.c_str());
} else if (GTK_IS_ENTRY(m_widget)) {
gtk_entry_set_text(GTK_ENTRY(m_widget), text.c_str());
} else if (GTK_IS_LINK_BUTTON(m_widget)) {
gtk_button_set_label(GTK_BUTTON(m_widget), text.c_str());
} else if (GTK_IS_TEXT_VIEW(m_widget)) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(m_widget));
gtk_text_buffer_set_text(buffer, text.c_str(), -1);
}
return ALLOY_OK;
}

alloy_error_t get_text(char *buf, size_t len) override {
const char *text = "";
std::string temp;
if (GTK_IS_WINDOW(m_widget)) text = gtk_window_get_title(GTK_WINDOW(m_widget));
else if (GTK_IS_BUTTON(m_widget)) text = gtk_button_get_label(GTK_BUTTON(m_widget));
else if (GTK_IS_LABEL(m_widget)) text = gtk_label_get_text(GTK_LABEL(m_widget));
else if (GTK_IS_ENTRY(m_widget)) text = gtk_entry_get_text(GTK_ENTRY(m_widget));
else if (GTK_IS_TEXT_VIEW(m_widget)) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(m_widget));
GtkTextIter start, end;
gtk_text_buffer_get_bounds(buffer, &start, &end);
char *raw = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
temp = raw;
g_free(raw);
text = temp.c_str();
}

if (!text) text = "";
size_t n = strlen(text);
if (n >= len) {
if (len > 0) { memcpy(buf, text, len - 1); buf[len - 1] = '\0'; }
return ALLOY_ERROR_BUFFER_TOO_SMALL;
}
memcpy(buf, text, n + 1);
return ALLOY_OK;
}

alloy_error_t set_checked(bool v) override {
if (GTK_IS_TOGGLE_BUTTON(m_widget)) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), v);
} else if (GTK_IS_SWITCH(m_widget)) {
gtk_switch_set_active(GTK_SWITCH(m_widget), v);
}
return ALLOY_OK;
}
bool get_checked() override {
if (GTK_IS_TOGGLE_BUTTON(m_widget)) return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_widget));
if (GTK_IS_SWITCH(m_widget)) return gtk_switch_get_active(GTK_SWITCH(m_widget));
return false;
}

alloy_error_t set_value(double v) override {
if (GTK_IS_PROGRESS_BAR(m_widget)) gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(m_widget), v);
else if (GTK_IS_RANGE(m_widget)) gtk_range_set_value(GTK_RANGE(m_widget), v);
return ALLOY_OK;
}
double get_value() override {
if (GTK_IS_PROGRESS_BAR(m_widget)) return gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(m_widget));
else if (GTK_IS_RANGE(m_widget)) return gtk_range_get_value(GTK_RANGE(m_widget));
return 0;
}

alloy_error_t set_enabled(bool v) override {
gtk_widget_set_sensitive(m_widget, v);
return ALLOY_OK;
}
bool get_enabled() override { return gtk_widget_get_sensitive(m_widget); }

alloy_error_t set_visible(bool v) override {
if (v) gtk_widget_show(m_widget); else gtk_widget_hide(m_widget);
return ALLOY_OK;
}
bool get_visible() override { return gtk_widget_get_visible(m_widget); }

alloy_error_t set_style(const alloy_style_t &s) override {
(void)s;
return ALLOY_OK;
}

protected:
GtkWidget *m_widget;
};

class gtk_window : public gtk_component {
public:
gtk_window(const char *title, int w, int h)
: gtk_component(gtk_window_new(GTK_WINDOW_TOPLEVEL), true) {
gtk_window_set_title(GTK_WINDOW(m_widget), title);
gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h);
g_signal_connect(m_widget, "destroy", G_CALLBACK(+[](GtkWidget *, gpointer) { gtk_main_quit(); }), NULL);
}
};

} // namespace alloy::detail

#endif // ALLOY_DETAIL_BACKENDS_GTK_GUI_HH
Loading