Merge branch 'multithread-dev' into dev
This commit is contained in:
commit
5dbafcb8d5
@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* @defgroup Cairo-Renderer Cairo Renderer
|
* @defgroup Cairo-Renderer Cairo Renderer
|
||||||
* @ingroup renderers
|
* @ingroup GdsOutputRenderer
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* @defgroup external-renderer External Shared Object Renderer
|
* @defgroup ExternalRenderer External Shared Object Renderer
|
||||||
* @ingroup renderers
|
* @ingroup GdsOutputRenderer
|
||||||
|
*
|
||||||
|
* @subsection ExternalRendererProps Properties
|
||||||
|
* This class inherits all properties from its parent @ref GdsOutputRenderer.
|
||||||
|
* In addition to that, it implements the following properties:
|
||||||
|
*
|
||||||
|
* Property Name | Description
|
||||||
|
* -----------------|----------------------------------------------------------------
|
||||||
|
* shared-object-path | Path to the shared object used for rendering
|
||||||
|
*
|
||||||
|
* All these properties have to be set for rendering.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
34
doxygen/gds-output-renderer.dox
Normal file
34
doxygen/gds-output-renderer.dox
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup GdsOutputRenderer GDS Output Renderer base class
|
||||||
|
*
|
||||||
|
* The renderers are used to convert the cell structures read from the GDS layout file
|
||||||
|
* into different output formats.
|
||||||
|
*
|
||||||
|
* The GdsOutputRenderer base class is used to derive all renderers from.
|
||||||
|
*
|
||||||
|
* @warning Although the GdsOutputRenderer class provides compatibility for asynchronous rendering,
|
||||||
|
* the class is not thread safe / re-entrant. Only use it from a signle context. Not even the rendering function called is allowed to modifiy this object.
|
||||||
|
*
|
||||||
|
* A allowed function to be called from the async rendering thread is #gds_output_renderer_update_gui_status_from_async and the get functions for the properties.
|
||||||
|
*
|
||||||
|
* @note The context that owned the renderer has to ensure that only one rendering is active at a time for a single instance of a renderer.
|
||||||
|
*
|
||||||
|
* By default this class implements the following features:
|
||||||
|
*
|
||||||
|
* @subsection GdsOutputRendererProps Properties
|
||||||
|
* Property Name | Description
|
||||||
|
* -----------------|----------------------------------------------------------------
|
||||||
|
* layer-settings | LayerSettings object containing the layer rendering information
|
||||||
|
* output-file | Output file name for rendering
|
||||||
|
*
|
||||||
|
* All these properties have to be set for rendering.
|
||||||
|
*
|
||||||
|
* @subsection GdsOutputRendererSignals Signals / Events
|
||||||
|
* Signal Name | Description | Callback prototype
|
||||||
|
* -----------------|-------------------------------------------------|-----------------------------------------------------------
|
||||||
|
* async-finished | The asynchronous rendering is finished | void callback(GdsOutputRenderer *src, gpointer user_data)
|
||||||
|
* progress-changed | The asynchronous rendering progress changed | void callback(GdsOutputRenderer *src, const char *progress, gpointer user_data)
|
||||||
|
*
|
||||||
|
* @note The `char *progress` supplied to the callback function must not be modified or freed.
|
||||||
|
*
|
||||||
|
*/
|
@ -1,4 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* @defgroup LaTeX-Renderer LaTeX/TikZ Renderer
|
* @defgroup LaTeX-Renderer LaTeX/TikZ Renderer
|
||||||
* @ingroup renderers
|
* @ingroup GdsOutputRenderer
|
||||||
|
*
|
||||||
|
* This is the class implementing the Latex / tikz output rendering
|
||||||
|
|
||||||
|
* @subsection LaTeXRendererProps Properties
|
||||||
|
* This class inherits all properties from its parent @ref GdsOutputRenderer.
|
||||||
|
* In addition to that, it implements the following properties:
|
||||||
|
*
|
||||||
|
* Property Name | Description
|
||||||
|
* -----------------|----------------------------------------------------------------
|
||||||
|
* standalone | Configure output LaTeX document to be standalone compilable (requires standalone documentclass)
|
||||||
|
* pdf-layers | Create OCG layers in LaTeX output
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* @defgroup renderers Output Renderers
|
|
||||||
*
|
|
||||||
* The renderers are used to convert the cell structures read from the GDS layout file
|
|
||||||
* into different output formats.
|
|
||||||
*
|
|
||||||
* Currently the renders are statically implemented without the use of GObjects.
|
|
||||||
* This will probably change in future releases in order to make it easier to integrate new rendering methods.
|
|
||||||
*/
|
|
103
gds-render-gui.c
103
gds-render-gui.c
@ -47,6 +47,11 @@ enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
|
|||||||
|
|
||||||
static guint gds_render_gui_signals[SIGNAL_COUNT];
|
static guint gds_render_gui_signals[SIGNAL_COUNT];
|
||||||
|
|
||||||
|
struct gui_button_states {
|
||||||
|
gboolean rendering_active;
|
||||||
|
gboolean valid_cell_selected;
|
||||||
|
};
|
||||||
|
|
||||||
struct _GdsRenderGui {
|
struct _GdsRenderGui {
|
||||||
/* Parent GObject */
|
/* Parent GObject */
|
||||||
GObject parent;
|
GObject parent;
|
||||||
@ -54,6 +59,9 @@ struct _GdsRenderGui {
|
|||||||
/* Custom fields */
|
/* Custom fields */
|
||||||
GtkWindow *main_window;
|
GtkWindow *main_window;
|
||||||
GtkWidget *convert_button;
|
GtkWidget *convert_button;
|
||||||
|
GtkWidget *open_button;
|
||||||
|
GtkWidget *load_layer_button;
|
||||||
|
GtkWidget *save_layer_button;
|
||||||
GtkTreeStore *cell_tree_store;
|
GtkTreeStore *cell_tree_store;
|
||||||
GtkWidget *cell_search_entry;
|
GtkWidget *cell_search_entry;
|
||||||
LayerSelector *layer_selector;
|
LayerSelector *layer_selector;
|
||||||
@ -62,6 +70,7 @@ struct _GdsRenderGui {
|
|||||||
ActivityBar *activity_status_bar;
|
ActivityBar *activity_status_bar;
|
||||||
struct render_settings render_dialog_settings;
|
struct render_settings render_dialog_settings;
|
||||||
ColorPalette *palette;
|
ColorPalette *palette;
|
||||||
|
struct gui_button_states button_state_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
|
G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
|
||||||
@ -240,6 +249,23 @@ end_destroy:
|
|||||||
gtk_widget_destroy(open_dialog);
|
gtk_widget_destroy(open_dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_button_state_changes(GdsRenderGui *self)
|
||||||
|
{
|
||||||
|
gboolean convert_button_state = FALSE;
|
||||||
|
gboolean open_gds_button_state = FALSE;
|
||||||
|
|
||||||
|
/* Calculate states */
|
||||||
|
if (!self->button_state_data.rendering_active) {
|
||||||
|
open_gds_button_state = TRUE;
|
||||||
|
if (self->button_state_data.valid_cell_selected)
|
||||||
|
convert_button_state = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply states */
|
||||||
|
gtk_widget_set_sensitive(self->convert_button, convert_button_state);
|
||||||
|
gtk_widget_set_sensitive(self->open_button, open_gds_button_state);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for auto coloring button
|
* @brief Callback for auto coloring button
|
||||||
* @param button
|
* @param button
|
||||||
@ -254,6 +280,29 @@ static void on_auto_color_clicked(gpointer button, gpointer user)
|
|||||||
layer_selector_auto_color_layers(self->layer_selector, self->palette, 1.0);
|
layer_selector_auto_color_layers(self->layer_selector, self->palette, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void async_rendering_finished_callback(GdsOutputRenderer *renderer, gpointer gui)
|
||||||
|
{
|
||||||
|
GdsRenderGui *self;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(gui);
|
||||||
|
|
||||||
|
self->button_state_data.rendering_active = FALSE;
|
||||||
|
process_button_state_changes(self);
|
||||||
|
activity_bar_set_ready(self->activity_status_bar);
|
||||||
|
|
||||||
|
g_object_unref(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void async_rendering_status_update_callback(GdsOutputRenderer *renderer, const char *status_message, gpointer data)
|
||||||
|
{
|
||||||
|
GdsRenderGui *gui;
|
||||||
|
(void)renderer;
|
||||||
|
|
||||||
|
gui = RENDERER_GUI(data);
|
||||||
|
|
||||||
|
activity_bar_set_busy(gui->activity_status_bar, status_message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert button callback
|
* @brief Convert button callback
|
||||||
* @param button
|
* @param button
|
||||||
@ -283,6 +332,10 @@ static void on_convert_clicked(gpointer button, gpointer user)
|
|||||||
if (!self)
|
if (!self)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Abort if rendering is already active */
|
||||||
|
if (self->button_state_data.rendering_active == TRUE)
|
||||||
|
return;
|
||||||
|
|
||||||
sett = &self->render_dialog_settings;
|
sett = &self->render_dialog_settings;
|
||||||
|
|
||||||
/* Get selected cell */
|
/* Get selected cell */
|
||||||
@ -369,16 +422,33 @@ static void on_convert_clicked(gpointer button, gpointer user)
|
|||||||
case RENDERER_CAIROGRAPHICS_PDF:
|
case RENDERER_CAIROGRAPHICS_PDF:
|
||||||
render_engine = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
|
render_engine = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
/* Abort rendering */
|
||||||
|
render_engine = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_engine) {
|
if (render_engine) {
|
||||||
gds_output_renderer_set_output_file(render_engine, file_name);
|
gds_output_renderer_set_output_file(render_engine, file_name);
|
||||||
gds_output_renderer_set_layer_settings(render_engine, layer_settings);
|
gds_output_renderer_set_layer_settings(render_engine, layer_settings);
|
||||||
|
/* Prevent user from overwriting library or triggering additional conversion */
|
||||||
|
self->button_state_data.rendering_active = TRUE;
|
||||||
|
process_button_state_changes(self);
|
||||||
|
|
||||||
|
g_signal_connect(render_engine, "async-finished", G_CALLBACK(async_rendering_finished_callback),
|
||||||
|
self);
|
||||||
|
|
||||||
|
activity_bar_set_busy(self->activity_status_bar, "Rendering cell...");
|
||||||
/* TODO: Replace this with asynchronous rendering. However, this fixes issue #19 */
|
/* TODO: Replace this with asynchronous rendering. However, this fixes issue #19 */
|
||||||
gds_output_renderer_render_output(render_engine, cell_to_render, sett->scale);
|
|
||||||
|
|
||||||
g_object_unref(render_engine);
|
g_signal_connect(render_engine, "progress-changed",
|
||||||
|
G_CALLBACK(async_rendering_status_update_callback), self);
|
||||||
|
gds_output_renderer_render_output_async(render_engine, cell_to_render, sett->scale);
|
||||||
|
|
||||||
|
|
||||||
|
//self->button_state_data.rendering_active = FALSE;
|
||||||
|
|
||||||
|
//g_object_unref(render_engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(file_name);
|
g_free(file_name);
|
||||||
@ -407,7 +477,6 @@ static void cell_tree_view_activated(gpointer tree_view, GtkTreePath *path,
|
|||||||
on_convert_clicked(NULL, user);
|
on_convert_clicked(NULL, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback for cell-selection change event
|
* @brief Callback for cell-selection change event
|
||||||
*
|
*
|
||||||
@ -423,10 +492,12 @@ static void cell_selection_changed(GtkTreeSelection *sel, GdsRenderGui *self)
|
|||||||
|
|
||||||
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
||||||
/* Node selected. Show button */
|
/* Node selected. Show button */
|
||||||
gtk_widget_set_sensitive(self->convert_button, TRUE);
|
self->button_state_data.valid_cell_selected = TRUE;
|
||||||
} else {
|
} else {
|
||||||
gtk_widget_set_sensitive(self->convert_button, FALSE);
|
self->button_state_data.valid_cell_selected = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_button_state_changes(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sort_up_callback(GtkWidget *widget, gpointer user)
|
static void sort_up_callback(GtkWidget *widget, gpointer user)
|
||||||
@ -466,6 +537,9 @@ static void gds_render_gui_dispose(GObject *gobject)
|
|||||||
g_clear_object(&self->cell_search_entry);
|
g_clear_object(&self->cell_search_entry);
|
||||||
g_clear_object(&self->activity_status_bar);
|
g_clear_object(&self->activity_status_bar);
|
||||||
g_clear_object(&self->palette);
|
g_clear_object(&self->palette);
|
||||||
|
g_clear_object(&self->load_layer_button);
|
||||||
|
g_clear_object(&self->save_layer_button);
|
||||||
|
g_clear_object(&self->open_button);
|
||||||
|
|
||||||
if (self->main_window) {
|
if (self->main_window) {
|
||||||
g_signal_handlers_destroy(self->main_window);
|
g_signal_handlers_destroy(self->main_window);
|
||||||
@ -521,7 +595,8 @@ static void gds_render_gui_init(GdsRenderGui *self)
|
|||||||
self->cell_tree_store = cell_selector_stores->base_store;
|
self->cell_tree_store = cell_selector_stores->base_store;
|
||||||
|
|
||||||
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
|
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
|
||||||
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
|
self->open_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds"));
|
||||||
|
g_signal_connect(self->open_button,
|
||||||
"clicked", G_CALLBACK(on_load_gds), (gpointer)self);
|
"clicked", G_CALLBACK(on_load_gds), (gpointer)self);
|
||||||
|
|
||||||
self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
|
self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
|
||||||
@ -550,11 +625,10 @@ static void gds_render_gui_init(GdsRenderGui *self)
|
|||||||
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
|
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
|
||||||
|
|
||||||
/* Set buttons for loading and saving */
|
/* Set buttons for loading and saving */
|
||||||
layer_selector_set_load_mapping_button(self->layer_selector,
|
self->load_layer_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping"));
|
||||||
GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
|
self->save_layer_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping"));
|
||||||
self->main_window);
|
layer_selector_set_load_mapping_button(self->layer_selector, self->load_layer_button, self->main_window);
|
||||||
layer_selector_set_save_mapping_button(self->layer_selector, GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
|
layer_selector_set_save_mapping_button(self->layer_selector, self->save_layer_button, self->main_window);
|
||||||
self->main_window);
|
|
||||||
|
|
||||||
/* Connect delete-event */
|
/* Connect delete-event */
|
||||||
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
|
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
|
||||||
@ -579,6 +653,10 @@ static void gds_render_gui_init(GdsRenderGui *self)
|
|||||||
|
|
||||||
g_object_unref(main_builder);
|
g_object_unref(main_builder);
|
||||||
|
|
||||||
|
/* Setup default button sensibility data */
|
||||||
|
self->button_state_data.rendering_active = FALSE;
|
||||||
|
self->button_state_data.valid_cell_selected = FALSE;
|
||||||
|
|
||||||
/* Reference all objects referenced by this object */
|
/* Reference all objects referenced by this object */
|
||||||
g_object_ref(self->activity_status_bar);
|
g_object_ref(self->activity_status_bar);
|
||||||
g_object_ref(self->main_window);
|
g_object_ref(self->main_window);
|
||||||
@ -588,6 +666,9 @@ static void gds_render_gui_init(GdsRenderGui *self)
|
|||||||
g_object_ref(self->cell_tree_store);
|
g_object_ref(self->cell_tree_store);
|
||||||
g_object_ref(self->cell_search_entry);
|
g_object_ref(self->cell_search_entry);
|
||||||
g_object_ref(self->palette);
|
g_object_ref(self->palette);
|
||||||
|
g_object_ref(self->open_button);
|
||||||
|
g_object_ref(self->load_layer_button);
|
||||||
|
g_object_ref(self->save_layer_button);
|
||||||
}
|
}
|
||||||
|
|
||||||
GdsRenderGui *gds_render_gui_new()
|
GdsRenderGui *gds_render_gui_new()
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include <gds-render/geometric/vector-operations.h>
|
#include <gds-render/geometric/vector-operations.h>
|
||||||
|
|
||||||
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
|
#define ABS_DBL(a) ((a) < 0.0 ? -(a) : (a))
|
||||||
|
|
||||||
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b)
|
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b)
|
||||||
{
|
{
|
||||||
|
@ -58,7 +58,7 @@ enum graphics_type
|
|||||||
enum path_type {PATH_FLUSH = 0, PATH_ROUNDED = 1, PATH_SQUARED = 2}; /**< Path line caps */
|
enum path_type {PATH_FLUSH = 0, PATH_ROUNDED = 1, PATH_SQUARED = 2}; /**< Path line caps */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A point in the 2D plane. Sometimes references as vertex
|
* @brief A point in the 2D plane. Sometimes reffered to as vertex
|
||||||
*/
|
*/
|
||||||
struct gds_point {
|
struct gds_point {
|
||||||
int x;
|
int x;
|
||||||
|
@ -144,6 +144,16 @@ void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSe
|
|||||||
*/
|
*/
|
||||||
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale);
|
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function emits the 'progress-changed' in the thread/context that triggered an asynchronous rendering
|
||||||
|
*
|
||||||
|
* If the rendering is not asynchronous, this function has no effect.
|
||||||
|
*
|
||||||
|
* @param renderer GdsOutputrenderer object
|
||||||
|
* @param status Status to supply to signal emission
|
||||||
|
*/
|
||||||
|
void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _GDS_OUTPUT_RENDERER_H_ */
|
#endif /* _GDS_OUTPUT_RENDERER_H_ */
|
||||||
|
@ -53,6 +53,14 @@ ActivityBar *activity_bar_new();
|
|||||||
*/
|
*/
|
||||||
void activity_bar_set_ready(ActivityBar *bar);
|
void activity_bar_set_ready(ActivityBar *bar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable spinner and set \p text. If text is NULL, 'Working...' is displayed
|
||||||
|
* @param bar Activity bar object
|
||||||
|
* @param text Text to display, may be NULL
|
||||||
|
|
||||||
|
*/
|
||||||
|
void activity_bar_set_busy(ActivityBar *bar, const char *text);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __LAYER_ELEMENT_H__ */
|
#endif /* __LAYER_ELEMENT_H__ */
|
||||||
|
@ -39,9 +39,36 @@ static void layer_settings_init(LayerSettings *self)
|
|||||||
self->layer_infos = NULL;
|
self->layer_infos = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void layer_info_delete_with_name(struct layer_info *const info)
|
||||||
|
{
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (info->name)
|
||||||
|
free(info->name);
|
||||||
|
free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_settings_dispose(GObject *obj)
|
||||||
|
{
|
||||||
|
LayerSettings *self;
|
||||||
|
|
||||||
|
self = GDS_RENDER_LAYER_SETTINGS(obj);
|
||||||
|
|
||||||
|
if (self->layer_infos) {
|
||||||
|
g_list_free_full(self->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
|
||||||
|
self->layer_infos = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(layer_settings_parent_class)->dispose(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static void layer_settings_class_init(LayerSettingsClass *klass)
|
static void layer_settings_class_init(LayerSettingsClass *klass)
|
||||||
{
|
{
|
||||||
(void)klass;
|
GObjectClass *oclass;
|
||||||
|
|
||||||
|
oclass = G_OBJECT_CLASS(klass);
|
||||||
|
oclass->dispose = layer_settings_dispose;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -76,16 +103,6 @@ static struct layer_info *layer_info_copy(const struct layer_info * const info)
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void layer_info_delete_with_name(struct layer_info *const info)
|
|
||||||
{
|
|
||||||
if (!info)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (info->name)
|
|
||||||
free(info->name);
|
|
||||||
free(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerSettings *layer_settings_new()
|
LayerSettings *layer_settings_new()
|
||||||
{
|
{
|
||||||
return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
|
return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
|
||||||
|
@ -400,6 +400,7 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
|
|||||||
else
|
else
|
||||||
pdf_file = output_file;
|
pdf_file = output_file;
|
||||||
|
|
||||||
|
gds_output_renderer_update_gui_status_from_async(renderer, "Rendering Cairo Output...");
|
||||||
ret = cairo_renderer_render_cell_to_vector_file(cell, layer_infos, pdf_file, svg_file, scale);
|
ret = cairo_renderer_render_cell_to_vector_file(cell, layer_infos, pdf_file, svg_file, scale);
|
||||||
|
|
||||||
if (settings)
|
if (settings)
|
||||||
|
@ -50,6 +50,7 @@ G_DEFINE_TYPE(ExternalRenderer, external_renderer, GDS_RENDER_TYPE_OUTPUT_RENDER
|
|||||||
* @param toplevel_cell Cell to render
|
* @param toplevel_cell Cell to render
|
||||||
* @param layer_info_list Layer information (Color etc.)
|
* @param layer_info_list Layer information (Color etc.)
|
||||||
* @param output_file Destination file
|
* @param output_file Destination file
|
||||||
|
* @param scale the scaling value to scale the output cell down by.
|
||||||
* @param so_path Path to shared object
|
* @param so_path Path to shared object
|
||||||
* @return 0 if successful
|
* @return 0 if successful
|
||||||
*/
|
*/
|
||||||
|
@ -20,9 +20,6 @@
|
|||||||
/**
|
/**
|
||||||
* @file gds-output-renderer.c
|
* @file gds-output-renderer.c
|
||||||
* @brief Base GObject class for output renderers
|
* @brief Base GObject class for output renderers
|
||||||
*
|
|
||||||
* All output renderers are derived from this class
|
|
||||||
*
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,13 +35,20 @@ struct renderer_params {
|
|||||||
double scale;
|
double scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct idle_function_params {
|
||||||
|
GMutex message_lock;
|
||||||
|
char *status_message;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gchar *output_file;
|
gchar *output_file;
|
||||||
LayerSettings *layer_settings;
|
LayerSettings *layer_settings;
|
||||||
GMutex settings_lock;
|
GMutex settings_lock;
|
||||||
gboolean mutex_init_status;
|
gboolean mutex_init_status;
|
||||||
GTask *task;
|
GTask *task;
|
||||||
|
GMainContext *main_context;
|
||||||
struct renderer_params async_params;
|
struct renderer_params async_params;
|
||||||
|
struct idle_function_params idle_function_parameters;
|
||||||
gpointer padding[11];
|
gpointer padding[11];
|
||||||
} GdsOutputRendererPrivate;
|
} GdsOutputRendererPrivate;
|
||||||
|
|
||||||
@ -56,7 +60,7 @@ enum {
|
|||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT)
|
G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT)
|
||||||
|
|
||||||
enum gds_output_renderer_signal_ids {ASYNC_FINISHED = 0, ASYNC_PROGRESS_UPDATE, GDS_OUTPUT_RENDERER_SIGNAL_COUNT};
|
enum gds_output_renderer_signal_ids {ASYNC_FINISHED = 0, ASYNC_PROGRESS_CHANGED, GDS_OUTPUT_RENDERER_SIGNAL_COUNT};
|
||||||
static guint gds_output_renderer_signals[GDS_OUTPUT_RENDERER_SIGNAL_COUNT];
|
static guint gds_output_renderer_signals[GDS_OUTPUT_RENDERER_SIGNAL_COUNT];
|
||||||
|
|
||||||
static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer,
|
static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer,
|
||||||
@ -83,6 +87,11 @@ static void gds_output_renderer_dispose(GObject *self_obj)
|
|||||||
g_mutex_lock(&priv->settings_lock);
|
g_mutex_lock(&priv->settings_lock);
|
||||||
g_mutex_unlock(&priv->settings_lock);
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
g_mutex_clear(&priv->settings_lock);
|
g_mutex_clear(&priv->settings_lock);
|
||||||
|
|
||||||
|
g_mutex_lock(&priv->idle_function_parameters.message_lock);
|
||||||
|
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
|
||||||
|
g_mutex_clear(&priv->idle_function_parameters.message_lock);
|
||||||
|
|
||||||
priv->mutex_init_status = FALSE;
|
priv->mutex_init_status = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +159,7 @@ static GParamSpec *gds_output_renderer_properties[N_PROPERTIES] = {NULL};
|
|||||||
static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
|
static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
|
GType progress_changed_param_types[1] = {G_TYPE_POINTER};
|
||||||
|
|
||||||
klass->render_output = gds_output_renderer_render_dummy;
|
klass->render_output = gds_output_renderer_render_dummy;
|
||||||
|
|
||||||
@ -178,16 +188,16 @@ static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
|
|||||||
G_TYPE_NONE,
|
G_TYPE_NONE,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
gds_output_renderer_signals[ASYNC_PROGRESS_UPDATE] =
|
gds_output_renderer_signals[ASYNC_PROGRESS_CHANGED] =
|
||||||
g_signal_newv("progress-update", GDS_RENDER_TYPE_OUTPUT_RENDERER,
|
g_signal_newv("progress-changed", GDS_RENDER_TYPE_OUTPUT_RENDERER,
|
||||||
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
|
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
G_TYPE_NONE,
|
G_TYPE_NONE,
|
||||||
0,
|
1,
|
||||||
NULL);
|
progress_changed_param_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gds_output_renderer_init(GdsOutputRenderer *self)
|
void gds_output_renderer_init(GdsOutputRenderer *self)
|
||||||
@ -200,7 +210,10 @@ void gds_output_renderer_init(GdsOutputRenderer *self)
|
|||||||
priv->output_file = NULL;
|
priv->output_file = NULL;
|
||||||
priv->task = NULL;
|
priv->task = NULL;
|
||||||
priv->mutex_init_status = TRUE;
|
priv->mutex_init_status = TRUE;
|
||||||
|
priv->main_context = NULL;
|
||||||
|
priv->idle_function_parameters.status_message = NULL;
|
||||||
g_mutex_init(&priv->settings_lock);
|
g_mutex_init(&priv->settings_lock);
|
||||||
|
g_mutex_init(&priv->idle_function_parameters.message_lock);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -321,9 +334,7 @@ static void gds_output_renderer_async_wrapper(GTask *task,
|
|||||||
goto ret_from_task;
|
goto ret_from_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_lock(&priv->settings_lock);
|
|
||||||
ret = gds_output_renderer_render_output(renderer, priv->async_params.cell, priv->async_params.scale);
|
ret = gds_output_renderer_render_output(renderer, priv->async_params.cell, priv->async_params.scale);
|
||||||
g_mutex_unlock(&priv->settings_lock);
|
|
||||||
|
|
||||||
ret_from_task:
|
ret_from_task:
|
||||||
g_task_return_int(task, ret);
|
g_task_return_int(task, ret);
|
||||||
@ -337,8 +348,13 @@ static void gds_output_renderer_async_finished(GObject *src_obj, GAsyncResult *r
|
|||||||
|
|
||||||
priv = gds_output_renderer_get_instance_private(GDS_RENDER_OUTPUT_RENDERER(src_obj));
|
priv = gds_output_renderer_get_instance_private(GDS_RENDER_OUTPUT_RENDERER(src_obj));
|
||||||
|
|
||||||
|
priv->main_context = NULL;
|
||||||
|
|
||||||
g_signal_emit(src_obj, gds_output_renderer_signals[ASYNC_FINISHED], 0);
|
g_signal_emit(src_obj, gds_output_renderer_signals[ASYNC_FINISHED], 0);
|
||||||
g_clear_object(&priv->task);
|
g_clear_object(&priv->task);
|
||||||
|
|
||||||
|
/* Clear reference set in gds_output_renderer_render_output_async() */
|
||||||
|
g_object_unref(src_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
|
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
|
||||||
@ -353,14 +369,82 @@ int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
priv->task = g_task_new(renderer, NULL, gds_output_renderer_async_finished, NULL);
|
priv->task = g_task_new(renderer, NULL, gds_output_renderer_async_finished, NULL);
|
||||||
|
g_task_set_name(priv->task, "Rendering Thread");
|
||||||
|
|
||||||
g_mutex_lock(&priv->settings_lock);
|
g_mutex_lock(&priv->settings_lock);
|
||||||
priv->async_params.cell = cell;
|
priv->async_params.cell = cell;
|
||||||
priv->async_params.scale = scale;
|
priv->async_params.scale = scale;
|
||||||
|
priv->main_context = g_main_context_default();
|
||||||
g_mutex_unlock(&priv->settings_lock);
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
|
||||||
|
/* Self reference. This could end up being nasty... */
|
||||||
|
g_object_ref(renderer);
|
||||||
|
|
||||||
|
/* Do the magic */
|
||||||
g_task_run_in_thread(priv->task, gds_output_renderer_async_wrapper);
|
g_task_run_in_thread(priv->task, gds_output_renderer_async_wrapper);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean idle_event_processor_callback(gpointer user_data)
|
||||||
|
{
|
||||||
|
GdsOutputRenderer *renderer;
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
char *status_message;
|
||||||
|
|
||||||
|
/* If the rendering is finished before the mainloop gets to this point
|
||||||
|
* the renderer is already disposed. Catch this!
|
||||||
|
*/
|
||||||
|
if (!GDS_RENDER_IS_OUTPUT_RENDERER(user_data))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
renderer = GDS_RENDER_OUTPUT_RENDERER(user_data);
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
if (g_mutex_trylock(&priv->idle_function_parameters.message_lock)) {
|
||||||
|
status_message = priv->idle_function_parameters.status_message;
|
||||||
|
g_signal_emit(renderer, gds_output_renderer_signals[ASYNC_PROGRESS_CHANGED], 0, status_message);
|
||||||
|
g_free(priv->idle_function_parameters.status_message);
|
||||||
|
priv->idle_function_parameters.status_message = NULL;
|
||||||
|
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
|
||||||
|
} else {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status)
|
||||||
|
{
|
||||||
|
GSource *idle_event_processor;
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
gboolean skip_source = FALSE;
|
||||||
|
|
||||||
|
g_return_if_fail(GDS_RENDER_IS_OUTPUT_RENDERER(renderer));
|
||||||
|
if (!status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
/* If rendering is not async */
|
||||||
|
if (!priv->main_context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_mutex_lock(&priv->idle_function_parameters.message_lock);
|
||||||
|
if (priv->idle_function_parameters.status_message) {
|
||||||
|
g_free(priv->idle_function_parameters.status_message);
|
||||||
|
|
||||||
|
/* Skip adding new idle source because there's already an active one */
|
||||||
|
skip_source = TRUE;
|
||||||
|
}
|
||||||
|
priv->idle_function_parameters.status_message = g_strdup(status);
|
||||||
|
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
|
||||||
|
|
||||||
|
if (!skip_source) {
|
||||||
|
idle_event_processor = g_idle_source_new();
|
||||||
|
g_source_set_callback(idle_event_processor, idle_event_processor_callback, (gpointer)renderer, NULL);
|
||||||
|
g_source_attach(idle_event_processor, priv->main_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -29,10 +29,15 @@
|
|||||||
#include <gdk/gdk.h>
|
#include <gdk/gdk.h>
|
||||||
#include <gds-render/layer/layer-info.h>
|
#include <gds-render/layer/layer-info.h>
|
||||||
/**
|
/**
|
||||||
* @addtogroup LatexRenderer
|
* @addtogroup LaTeX-Renderer
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct representing the LaTeX-Renderer object.
|
||||||
|
*
|
||||||
|
* This struct holds the LaTeX renderer internal data. It is only used inside the @ref LatexRenderer class.
|
||||||
|
*/
|
||||||
struct _LatexRenderer {
|
struct _LatexRenderer {
|
||||||
GdsOutputRenderer parent;
|
GdsOutputRenderer parent;
|
||||||
gboolean tex_standalone;
|
gboolean tex_standalone;
|
||||||
@ -226,13 +231,20 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
|
|||||||
* @param tex_file File to write to
|
* @param tex_file File to write to
|
||||||
* @param buffer Working buffer
|
* @param buffer Working buffer
|
||||||
* @param scale Scale output down by this value
|
* @param scale Scale output down by this value
|
||||||
|
* @param renderer The current renderer as GdsOutputRenderer. This is used to emit the status updates to the GUI
|
||||||
*/
|
*/
|
||||||
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale)
|
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale,
|
||||||
|
GdsOutputRenderer *renderer)
|
||||||
{
|
{
|
||||||
|
GString *status;
|
||||||
GList *list_child;
|
GList *list_child;
|
||||||
struct gds_cell_instance *inst;
|
struct gds_cell_instance *inst;
|
||||||
|
|
||||||
|
status = g_string_new(NULL);
|
||||||
|
g_string_printf(status, "Generating cell %s", cell->name);
|
||||||
|
gds_output_renderer_update_gui_status_from_async(renderer, status->str);
|
||||||
|
g_string_free(status, TRUE);
|
||||||
|
|
||||||
/* Draw polygons of current cell */
|
/* Draw polygons of current cell */
|
||||||
generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
|
generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
|
||||||
|
|
||||||
@ -256,7 +268,7 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
|
|||||||
inst->magnification);
|
inst->magnification);
|
||||||
WRITEOUT_BUFFER(buffer);
|
WRITEOUT_BUFFER(buffer);
|
||||||
|
|
||||||
render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale);
|
render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale, renderer);
|
||||||
|
|
||||||
g_string_printf(buffer, "\\end{scope}\n");
|
g_string_printf(buffer, "\\end{scope}\n");
|
||||||
WRITEOUT_BUFFER(buffer);
|
WRITEOUT_BUFFER(buffer);
|
||||||
@ -271,7 +283,7 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
|
static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
|
||||||
gboolean create_pdf_layers, gboolean standalone_document)
|
gboolean create_pdf_layers, gboolean standalone_document, GdsOutputRenderer *renderer)
|
||||||
{
|
{
|
||||||
GString *working_line;
|
GString *working_line;
|
||||||
|
|
||||||
@ -304,7 +316,7 @@ static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos,
|
|||||||
WRITEOUT_BUFFER(working_line);
|
WRITEOUT_BUFFER(working_line);
|
||||||
|
|
||||||
/* Generate graphics output */
|
/* Generate graphics output */
|
||||||
render_cell(cell, layer_infos, tex_file, working_line, scale);
|
render_cell(cell, layer_infos, tex_file, working_line, scale, renderer);
|
||||||
|
|
||||||
|
|
||||||
g_string_printf(working_line, "\\end{tikzpicture}\n");
|
g_string_printf(working_line, "\\end{tikzpicture}\n");
|
||||||
@ -344,7 +356,7 @@ static int latex_renderer_render_output(GdsOutputRenderer *renderer,
|
|||||||
tex_file = fopen(output_file, "w");
|
tex_file = fopen(output_file, "w");
|
||||||
if (tex_file) {
|
if (tex_file) {
|
||||||
ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
|
ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
|
||||||
l_renderer->pdf_layers, l_renderer->tex_standalone);
|
l_renderer->pdf_layers, l_renderer->tex_standalone, renderer);
|
||||||
fclose(tex_file);
|
fclose(tex_file);
|
||||||
} else {
|
} else {
|
||||||
g_error("Could not open LaTeX output file");
|
g_error("Could not open LaTeX output file");
|
||||||
|
@ -105,5 +105,11 @@ void activity_bar_set_ready(ActivityBar *bar)
|
|||||||
gtk_spinner_stop(GTK_SPINNER(bar->spinner));
|
gtk_spinner_stop(GTK_SPINNER(bar->spinner));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void activity_bar_set_busy(ActivityBar *bar, const char *text)
|
||||||
|
{
|
||||||
|
gtk_label_set_text(GTK_LABEL(bar->label), (text ? text : "Working..."));
|
||||||
|
gtk_spinner_start(GTK_SPINNER(bar->spinner));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
Loading…
Reference in New Issue
Block a user