From ee99e50656a05274a5ff31ed07146d0761f39a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:36:50 +0200 Subject: [PATCH 01/43] Move compiler flags up in CMAKE, so they apply also for included subprojects --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec81559..5dca072 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ pkg_search_module(GLIB REQUIRED glib-2.0) pkg_check_modules(GTK3 REQUIRED gtk+-3.0) pkg_check_modules(CAIRO REQUIRED cairo) +add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) + add_subdirectory(resources) add_subdirectory(doxygen) add_subdirectory(version) @@ -32,8 +34,6 @@ set(SOURCE ${LAYER_SELECTOR_SOURCES} ) -add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) - add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c) add_dependencies(${PROJECT_NAME} glib-resources) add_dependencies(${PROJECT_NAME} version) From ad5e0ebe1146ceb7f0e4c19293d2a9f88c53c99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:37:51 +0200 Subject: [PATCH 02/43] Remove warning about wrong bounding box calculation. Still wrong but the warning is annoying and problems are negligible. --- geometric/bounding-box.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geometric/bounding-box.c b/geometric/bounding-box.c index 65dc781..0895636 100644 --- a/geometric/bounding-box.c +++ b/geometric/bounding-box.c @@ -151,7 +151,7 @@ void bounding_box_calculate_path_box(GList *vertices, double thickness, GList *vertex_iterator; struct vector_2d pt; - printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n"); + //printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n"); if (!vertices || !box) return; From bea35bf952e101e34e086202a941706ddafd07ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:38:32 +0200 Subject: [PATCH 03/43] Add warning for fallthrough to switch-case --- output-renderers/cairo-renderer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 572e1f4..f7ee9a0 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -177,6 +177,7 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl cairo_stroke(cr); break; case GRAPHIC_BOX: + /* Expected fallthrough */ case GRAPHIC_POLYGON: cairo_set_line_width(cr, 0.1/scale); cairo_close_path(cr); From 4db8593e5b37191c4ccc840515b3e8b8f9b55b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:39:42 +0200 Subject: [PATCH 04/43] Cairo Renderer: Add function that reads a line from a file descriptor (pipe) --- output-renderers/cairo-renderer.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index f7ee9a0..24048a7 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -188,6 +188,36 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl } /* for gfx list */ } +/** + * @brief Read a line from a file descriptor + * + * In case of a broken pipe / closed writing end, it will terminate + * + * @param fd File descriptor to read from + * @param buff Buffer to write data in + * @param buff_size Buffer size + * @return length of read data + */ +static int read_line_from_fd(int fd, char *buff, size_t buff_size) +{ + ssize_t cnt; + char c; + unsigned int buff_cnt = 0; + + while ((cnt = read(fd, &c, 1)) == 1) { + if (buff_cnt < (buff_size-1)) { + buff[buff_cnt++] = c; + if (c == '\n') + break; + } else { + break; + } + } + + buff[buff_cnt] = 0; + return (int)buff_cnt; +} + /** * @brief Render \p cell to a PDF file specified by \p pdf_file * @param cell Toplevel cell to @ref Cairo-Renderer From 8b1d3709b7b68a1589c35690fc70b8c0101d742f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:40:16 +0200 Subject: [PATCH 05/43] Add project entry to libversion CMAKE --- version/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/version/CMakeLists.txt b/version/CMakeLists.txt index e438a16..5bdb64c 100644 --- a/version/CMakeLists.txt +++ b/version/CMakeLists.txt @@ -1,3 +1,4 @@ +project(libversion) add_library(version STATIC "version.c") execute_process(COMMAND bash ./generate-version-string.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} From 5f6dbbed0e6f67d5276c303445759094d6a3e2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 19 Sep 2019 21:42:55 +0200 Subject: [PATCH 06/43] Enable status upgrades from Cairo renderer to activity bar. --- output-renderers/cairo-renderer.c | 52 +++++++++++++++++++------- output-renderers/gds-output-renderer.c | 2 - 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 24048a7..2d2061c 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -227,7 +227,7 @@ static int read_line_from_fd(int fd, char *buff, size_t buff_size) * @param scale Scale the output image down by \p scale * @return Error */ -static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, const char *pdf_file, +static int cairo_renderer_render_cell_to_vector_file(GdsOutputRenderer *renderer, struct gds_cell *cell, GList *layer_infos, const char *pdf_file, const char *svg_file, double scale) { cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL; @@ -240,28 +240,40 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis double rec_x0, rec_y0, rec_width, rec_height; double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN; pid_t process_id; + int comm_pipe[2]; + char receive_message[200]; if (pdf_file == NULL && svg_file == NULL) { /* No output specified */ return -1; } + /* Generate communication pipe for status updates */ + if (pipe(comm_pipe) == -1) + return -2; + /* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't * brick everything. * * And by the way: This now bricks all Windows compatibility. Deal with it. */ - - /* Use fork for production code and -1 as value for debugging */ process_id = fork(); //process_id = -1; if (process_id < 0) { - /* Well... shit... We have to run it in our process. */ + /* This should not happen */ + fprintf(stderr, "Fatal error: Cairo Renderer: Could not spawn child process!"); + exit(-2); } else if (process_id > 0) { /* Woohoo... Successfully dumped the shitty code to an unknowing victim */ goto ret_parent; } + /* Close stdin and (stdout and stderr may live on) */ + close(0); + //close(1); + close(comm_pipe[0]); + + layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer)); /* Clear layers */ @@ -291,7 +303,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis } } - + dprintf(comm_pipe[1], "Rendering layers\n"); render_cell(cell, layers, scale); /* get size of image and top left coordinate */ @@ -309,7 +321,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis /* Print size */ cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0, &rec_width, &rec_height); - printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n", + dprintf(comm_pipe[1], "Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n", linfo->layer, (linfo->name && linfo->name[0] ? " (" : ""), (linfo->name && linfo->name[0] ? linfo->name : ""), @@ -328,7 +340,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis } - printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); + /* printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); */ if (pdf_file) { pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin); @@ -344,6 +356,8 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) { linfo = (struct layer_info *)info_list->data; + dprintf(comm_pipe[1], "Exporting layer %d to file\n", linfo->layer); + if (linfo->layer >= MAX_LAYERS) { printf("Layer outside of Spec.\n"); continue; @@ -387,14 +401,26 @@ ret_clear_layers: printf("Cairo export finished. It might still be buggy!\n"); - /* If forked, suspend process */ - if (process_id == 0) - exit(0); + /* Suspend child process */ + exit(0); - /* Fork didn't work. Just return here */ - return 0; ret_parent: + close(comm_pipe[1]); + + while (read_line_from_fd(comm_pipe[0], receive_message, sizeof(receive_message)) > 0) { + /* Strip \n from string and replace with ' ' */ + for (i = 0; receive_message[i] != '\0'; i++) { + if (receive_message[i] == '\n') + receive_message[i] = ' '; + } + + /* Update asyc progress*/ + gds_output_renderer_update_gui_status_from_async(renderer, receive_message); + } + waitpid(process_id, NULL, 0); + + close(comm_pipe[0]); return 0; } @@ -432,7 +458,7 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer, 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(renderer, cell, layer_infos, pdf_file, svg_file, scale); if (settings) g_object_unref(settings); diff --git a/output-renderers/gds-output-renderer.c b/output-renderers/gds-output-renderer.c index b07011e..8f8ed10 100644 --- a/output-renderers/gds-output-renderer.c +++ b/output-renderers/gds-output-renderer.c @@ -260,8 +260,6 @@ LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer /* This function seems to already reference the LayerSettings object */ g_object_get(renderer, "layer-settings", &ret, NULL); - /* Reference it, so it is not cleared by another thread overwriting the property */ - //g_object_ref(ret); /* It is now safe to clear the lock */ g_mutex_unlock(&priv->settings_lock); From 291ded02777939c3e563f50d6ebd18af3a4c2310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 19 Sep 2019 21:44:30 +0200 Subject: [PATCH 07/43] Refactoring: rename progress update func of output renderer to gds_output_renderer_update_async_progress() --- include/gds-render/output-renderers/gds-output-renderer.h | 2 +- output-renderers/cairo-renderer.c | 4 ++-- output-renderers/gds-output-renderer.c | 2 +- output-renderers/latex-renderer.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/gds-render/output-renderers/gds-output-renderer.h b/include/gds-render/output-renderers/gds-output-renderer.h index 1f045b6..1dd9c85 100644 --- a/include/gds-render/output-renderers/gds-output-renderer.h +++ b/include/gds-render/output-renderers/gds-output-renderer.h @@ -152,7 +152,7 @@ int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct * @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); +void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status); G_END_DECLS diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 2d2061c..ff049aa 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -415,7 +415,7 @@ ret_parent: } /* Update asyc progress*/ - gds_output_renderer_update_gui_status_from_async(renderer, receive_message); + gds_output_renderer_update_async_progress(renderer, receive_message); } waitpid(process_id, NULL, 0); @@ -457,7 +457,7 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer, else pdf_file = output_file; - gds_output_renderer_update_gui_status_from_async(renderer, "Rendering Cairo Output..."); + gds_output_renderer_update_async_progress(renderer, "Rendering Cairo Output..."); ret = cairo_renderer_render_cell_to_vector_file(renderer, cell, layer_infos, pdf_file, svg_file, scale); if (settings) diff --git a/output-renderers/gds-output-renderer.c b/output-renderers/gds-output-renderer.c index 8f8ed10..5d27584 100644 --- a/output-renderers/gds-output-renderer.c +++ b/output-renderers/gds-output-renderer.c @@ -413,7 +413,7 @@ static gboolean idle_event_processor_callback(gpointer user_data) return FALSE; } -void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status) +void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status) { GSource *idle_event_processor; GdsOutputRendererPrivate *priv; diff --git a/output-renderers/latex-renderer.c b/output-renderers/latex-renderer.c index f7f9b97..15ecc76 100644 --- a/output-renderers/latex-renderer.c +++ b/output-renderers/latex-renderer.c @@ -241,7 +241,7 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil 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); + gds_output_renderer_update_async_progress(renderer, status->str); g_string_free(status, TRUE); /* Draw polygons of current cell */ From d90c1b389efa7462b081440388036b6000acf2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:54:26 +0200 Subject: [PATCH 08/43] LayerSettings: Fix layer_settings_load_from_csv() * Add stacked position to layer settings * Check if layer_settings instance is valid --- layer/layer-settings.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/layer/layer-settings.c b/layer/layer-settings.c index 330cde8..722e378 100644 --- a/layer/layer-settings.c +++ b/layer/layer-settings.c @@ -314,10 +314,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path) GInputStream *in_stream; GDataInputStream *data_stream; int parser_ret; + int stacked_pos; struct layer_info linfo; file = g_file_new_for_path(path); in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL)); + + g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -2); + if (!in_stream) { ret = -1; goto ret_destroy_file; @@ -327,11 +331,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path) data_stream = g_data_input_stream_new(in_stream); + stacked_pos = 0; while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) { /* Line broken */ if (parser_ret == 1) continue; + linfo.stacked_position = stacked_pos++; + layer_settings_append_layer_info(settings, &linfo); /* Clear name to prevent memory leak */ if (linfo.name) From 941711129a228322cb8635a64c0b36743b8acc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:55:59 +0200 Subject: [PATCH 09/43] LayerSelector: Make import of layer information from CSV independed from mapping-parser code. Use LayerSettings class instead. --- layer/layer-selector.c | 55 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/layer/layer-selector.c b/layer/layer-selector.c index 1ad0976..b40bead 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -577,6 +577,7 @@ void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs) static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer) { LayerElement *ret = NULL; + for (; el_list != NULL; el_list = el_list->next) { if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) { ret = LAYER_ELEMENT(el_list->data); @@ -597,19 +598,18 @@ static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, i * @param self LayerSelector instance * @param file_name File name to load from */ -static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gchar *file_name) +static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name) { GFile *file; GFileInputStream *stream; GDataInputStream *dstream; LayerElement *le; - char *name; - gboolean export; - int layer; - GdkRGBA color; - int result; GList *rows; GList *temp; + GList *layer_infos; + int status; + LayerSettings *layer_settings; + struct layer_info *linfo; file = g_file_new_for_path(file_name); stream = g_file_read(file, NULL, NULL); @@ -624,31 +624,40 @@ static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gch /* Reference and remove all rows from box */ for (temp = rows; temp != NULL; temp = temp->next) { le = LAYER_ELEMENT(temp->data); - /* Referencing protets the widget from being deleted when removed */ + /* Referencing protects the widget from being deleted when removed */ g_object_ref(G_OBJECT(le)); gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le)); } - while((result = mapping_parser_load_line(dstream, &export, &name, &layer, &color)) >= 0) { - /* skip broken line */ - if (result == 1) + /* Load Layer settings. No need to check pointer, will be checked by load csv func. */ + layer_settings = layer_settings_new(); + + status = layer_settings_load_from_csv(layer_settings, file_name); + if (status) + goto abort_layer_settings; + + layer_infos = layer_settings_get_layer_info_list(layer_settings); + if (!layer_infos) + goto abort_layer_settings; + + /* Loop over all layer infos read from the CSV file */ + for (; layer_infos; layer_infos = g_list_next(layer_infos)) { + linfo = (struct layer_info *)layer_infos->data; + le = layer_selector_find_layer_element_in_list(rows, linfo->layer); + if (!le) continue; - /* Add rows in the same order as in file */ - if ((le = layer_selector_find_layer_element_in_list(rows, layer))) { - gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1); - - layer_element_set_color(le, &color); - layer_element_set_export(le, export); - layer_element_set_name(le, name); - g_free(name); - - /* Dereference and remove from list */ - g_object_unref(G_OBJECT(le)); - rows = g_list_remove(rows, le); - } + layer_element_set_name(le, linfo->name); + layer_element_set_export(le, (linfo->render ? TRUE : FALSE)); + layer_element_set_color(le, &linfo->color); + gtk_container_add(GTK_CONTAINER(self->list_box), GTK_WIDGET(le)); + rows = g_list_remove(rows, le); } +abort_layer_settings: + /* Destroy layer settings. Not needed for adding remaining elements */ + g_object_unref(layer_settings); + /* Add remaining elements */ for (temp = rows; temp != NULL; temp = temp->next) { le = LAYER_ELEMENT(temp->data); From 16b18fc5b307ce09ae853a2a673299be0ffe31e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:59:38 +0200 Subject: [PATCH 10/43] Remove code from mapping parser that implements csv read. Use LayerSettings class instead. --- include/gds-render/layer/mapping-parser.h | 11 ---- layer/mapping-parser.c | 63 ----------------------- 2 files changed, 74 deletions(-) diff --git a/include/gds-render/layer/mapping-parser.h b/include/gds-render/layer/mapping-parser.h index cca1318..2b77fbc 100644 --- a/include/gds-render/layer/mapping-parser.h +++ b/include/gds-render/layer/mapping-parser.h @@ -36,17 +36,6 @@ #include #include -/** - * @brief Load a line from \p stream and parse try to parse it as layer information - * @param stream Input data stream - * @param export Layer shall be exported - * @param name Layer name. Free returned pointer after using. - * @param layer Layer number - * @param color RGBA color. - * @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end - */ -int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color); - /** * @brief Create Line for LayerMapping file with supplied information * @param layer_element information diff --git a/layer/mapping-parser.c b/layer/mapping-parser.c index ad0d1e7..94d854a 100644 --- a/layer/mapping-parser.c +++ b/layer/mapping-parser.c @@ -31,69 +31,6 @@ #include -int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color) -{ - int ret; - gsize len; - gchar *line; - GRegex *regex; - GMatchInfo *mi; - char *match; - - if ((!export) || (!name) || (!layer) || (!color)) { - ret = 1; - goto ret_direct; - } - - regex = g_regex_new("^(?[0-9]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[01]),(?.*)$", 0, 0, NULL); - - line = g_data_input_stream_read_line(stream, &len, NULL, NULL); - if (!line) { - ret = -1; - goto destroy_regex; - } - - /* Match line in CSV */ - g_regex_match(regex, line, 0, &mi); - if (g_match_info_matches(mi)) { - /* Line is valid */ - match = g_match_info_fetch_named(mi, "layer"); - *layer = (int)g_ascii_strtoll(match, NULL, 10); - g_free(match); - match = g_match_info_fetch_named(mi, "r"); - color->red = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "g"); - color->green = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "b"); - color->blue = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "a"); - color->alpha = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "export"); - *export = ((!strcmp(match, "1")) ? TRUE : FALSE); - g_free(match); - match = g_match_info_fetch_named(mi, "name"); - *name = match; - - ret = 0; - } else { - /* Line is malformatted */ - printf("Could not recognize line in CSV as valid entry: %s\n", line); - ret = 1; - } - - g_match_info_free(mi); - g_free(line); -destroy_regex: - g_regex_unref(regex); -ret_direct: - return ret; - -} - void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len) { int i; From e16b7f9d2599d98a0bdb6a0fa6dcad989812e705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:20:03 +0200 Subject: [PATCH 11/43] LayerSettings: Fix bug in CSV export function --- layer/layer-settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layer/layer-settings.c b/layer/layer-settings.c index 722e378..ecc8809 100644 --- a/layer/layer-settings.c +++ b/layer/layer-settings.c @@ -223,7 +223,7 @@ int layer_settings_to_csv(LayerSettings *settings, const char *path) linfo = (struct layer_info *)info_iter->data; layer_settings_gen_csv_line(string, linfo); - g_output_stream_write(w_fstream, string->str, sizeof(gchar), NULL, NULL); + g_output_stream_write(w_fstream, string->str, string->len * sizeof(gchar), NULL, NULL); } /* Delete string */ From a9ccf6533dec4b803f9949a15e7a8d58de4041d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:21:02 +0200 Subject: [PATCH 12/43] LayerSelector: Use Layer Settings for CSV export. This makes the mapping parser unnecessary. It can be removed --- layer/layer-selector.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/layer/layer-selector.c b/layer/layer-selector.c index b40bead..fcda12d 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -711,29 +711,14 @@ static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user */ static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name) { - FILE *file; - char workbuff[512]; - GList *le_list; - GList *temp; + LayerSettings *layer_settings; - /* Overwrite existing file */ - file = fopen((const char *)file_name, "w"); + g_return_if_fail(LAYER_IS_SELECTOR(self)); + g_return_if_fail(file_name); - le_list = gtk_container_get_children(GTK_CONTAINER(self->list_box)); - - /* File format is CSV: ,,,,,,, */ - for (temp = le_list; temp != NULL; temp = temp->next) { - /* To be sure it is a valid string */ - workbuff[0] = 0; - mapping_parser_gen_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff)); - fwrite(workbuff, sizeof(char), strlen(workbuff), file); - } - - g_list_free(le_list); - - /* Save File */ - fflush(file); - fclose(file); + /* Get layer settings. No need to check return value. to_csv func is safe */ + layer_settings = layer_selector_export_rendered_layer_info(self); + (void)layer_settings_to_csv(layer_settings, file_name); } /** From bcc8623382e06d2b48c6fd3f57b35641770881dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:25:12 +0200 Subject: [PATCH 13/43] remove now unneeded mapping parser completely --- command-line.c | 1 - include/gds-render/layer/mapping-parser.h | 49 -------------- layer/layer-selector.c | 1 - layer/mapping-parser.c | 81 ----------------------- 4 files changed, 132 deletions(-) delete mode 100644 include/gds-render/layer/mapping-parser.h delete mode 100644 layer/mapping-parser.c diff --git a/command-line.c b/command-line.c index a27e4d0..4e75ec6 100644 --- a/command-line.c +++ b/command-line.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/include/gds-render/layer/mapping-parser.h b/include/gds-render/layer/mapping-parser.h deleted file mode 100644 index 2b77fbc..0000000 --- a/include/gds-render/layer/mapping-parser.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file mapping-parser.h - * @brief Function to read a mapping file line and parse it. - * @author Mario Hüttel - */ - -#ifndef __MAPPING_PARSER_H__ -#define __MAPPING_PARSER_H__ - -/** - * @addtogroup Mapping-Parser - * @{ - */ - -#include - -#include -#include - -/** - * @brief Create Line for LayerMapping file with supplied information - * @param layer_element information - * @param line_buffer buffer to write to - * @param max_len Maximum length that cna be used in \p line_buffer - */ -void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len); - -/** @} */ - -#endif /* __MAPPING_PARSER_H__ */ diff --git a/layer/layer-selector.c b/layer/layer-selector.c index fcda12d..0f9b342 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -36,7 +36,6 @@ #include #include #include -#include struct _LayerSelector { /* Parent */ diff --git a/layer/mapping-parser.c b/layer/mapping-parser.c deleted file mode 100644 index 94d854a..0000000 --- a/layer/mapping-parser.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file mapping-parser.c - * @brief Function to read a mapping file line and parse it. - * @author Mario Hüttel - */ - -/** - * @addtogroup Mapping-Parser - * @{ - */ - -#include - -void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len) -{ - int i; - GString *string; - gboolean export; - const gchar *name; - int layer; - GdkRGBA color; - - string = g_string_new_len(NULL, max_len-1); - - /* Extract values */ - export = layer_element_get_export(layer_element); - name = (const gchar*)layer_element_get_name(layer_element); - layer = layer_element_get_layer(layer_element); - layer_element_get_color(layer_element, &color); - - /* print values to line */ - g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n", - layer, color.red, color.green, - color.blue, color.alpha, (export == TRUE ? 1 : 0), name); - /* Fix broken locale settings */ - for (i = 0; string->str[i]; i++) { - if (string->str[i] == ',') - string->str[i] = '.'; - } - - for (i = 0; string->str[i]; i++) { - if (string->str[i] == ':') - string->str[i] = ','; - } - - if (string->len > (max_len-1)) { - printf("Layer Definition too long. Please shorten Layer Name!!\n"); - line_buffer[0] = 0x0; - return; - } - - /* copy max_len bytes of string */ - strncpy(line_buffer, (char *)string->str, max_len-1); - line_buffer[max_len-1] = 0; - - /* Completely remove string */ - g_string_free(string, TRUE); -} - -/** @} */ - From 00d7691bdad4c5001999a8ce6c9f07420c3cf55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 20:46:41 +0200 Subject: [PATCH 14/43] Code improvements --- main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.c b/main.c index f13e936..1e7113a 100644 --- a/main.c +++ b/main.c @@ -183,7 +183,6 @@ static void gapp_activate(GApplication *app, gpointer user_data) */ static int start_gui(int argc, char **argv) { - GtkApplication *gapp; int app_status; static struct application_data appdata = { @@ -289,7 +288,6 @@ int main(int argc, char **argv) scale = 1; } - /* Get gds name */ gds_name = argv[1]; From e3e39a80ee03cdaad69c2e4699cb4b2106861fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:36:50 +0200 Subject: [PATCH 15/43] Move compiler flags up in CMAKE, so they apply also for included subprojects --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec81559..5dca072 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ pkg_search_module(GLIB REQUIRED glib-2.0) pkg_check_modules(GTK3 REQUIRED gtk+-3.0) pkg_check_modules(CAIRO REQUIRED cairo) +add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) + add_subdirectory(resources) add_subdirectory(doxygen) add_subdirectory(version) @@ -32,8 +34,6 @@ set(SOURCE ${LAYER_SELECTOR_SOURCES} ) -add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) - add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c) add_dependencies(${PROJECT_NAME} glib-resources) add_dependencies(${PROJECT_NAME} version) From eefe0df984bdde957a68db4232fcceeac723de87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:37:51 +0200 Subject: [PATCH 16/43] Remove warning about wrong bounding box calculation. Still wrong but the warning is annoying and problems are negligible. --- geometric/bounding-box.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geometric/bounding-box.c b/geometric/bounding-box.c index 65dc781..0895636 100644 --- a/geometric/bounding-box.c +++ b/geometric/bounding-box.c @@ -151,7 +151,7 @@ void bounding_box_calculate_path_box(GList *vertices, double thickness, GList *vertex_iterator; struct vector_2d pt; - printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n"); + //printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n"); if (!vertices || !box) return; From 52fb07bea63e45a21bc8c21f453f6e8106824bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:38:32 +0200 Subject: [PATCH 17/43] Add warning for fallthrough to switch-case --- output-renderers/cairo-renderer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 7ee76d9..27ea437 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -177,6 +177,7 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl cairo_stroke(cr); break; case GRAPHIC_BOX: + /* Expected fallthrough */ case GRAPHIC_POLYGON: cairo_set_line_width(cr, 0.1/scale); cairo_close_path(cr); From 5ec7832ac464ec35427ebaf03d879959def436aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:39:42 +0200 Subject: [PATCH 18/43] Cairo Renderer: Add function that reads a line from a file descriptor (pipe) --- output-renderers/cairo-renderer.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 27ea437..79b57ad 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -188,6 +188,36 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl } /* for gfx list */ } +/** + * @brief Read a line from a file descriptor + * + * In case of a broken pipe / closed writing end, it will terminate + * + * @param fd File descriptor to read from + * @param buff Buffer to write data in + * @param buff_size Buffer size + * @return length of read data + */ +static int read_line_from_fd(int fd, char *buff, size_t buff_size) +{ + ssize_t cnt; + char c; + unsigned int buff_cnt = 0; + + while ((cnt = read(fd, &c, 1)) == 1) { + if (buff_cnt < (buff_size-1)) { + buff[buff_cnt++] = c; + if (c == '\n') + break; + } else { + break; + } + } + + buff[buff_cnt] = 0; + return (int)buff_cnt; +} + /** * @brief Render \p cell to a PDF file specified by \p pdf_file * @param cell Toplevel cell to @ref Cairo-Renderer From 0dc91c14de9b7b3dc0330811c446988346694f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 18 Sep 2019 20:40:16 +0200 Subject: [PATCH 19/43] Add project entry to libversion CMAKE --- version/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/version/CMakeLists.txt b/version/CMakeLists.txt index e438a16..5bdb64c 100644 --- a/version/CMakeLists.txt +++ b/version/CMakeLists.txt @@ -1,3 +1,4 @@ +project(libversion) add_library(version STATIC "version.c") execute_process(COMMAND bash ./generate-version-string.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} From 977547d91dcc1f1baed92770964045405393ea42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 19 Sep 2019 21:42:55 +0200 Subject: [PATCH 20/43] Enable status upgrades from Cairo renderer to activity bar. --- output-renderers/cairo-renderer.c | 52 +++++++++++++++++++------- output-renderers/gds-output-renderer.c | 2 - 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 79b57ad..12bb7fa 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -227,7 +227,7 @@ static int read_line_from_fd(int fd, char *buff, size_t buff_size) * @param scale Scale the output image down by \p scale * @return Error */ -static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, const char *pdf_file, +static int cairo_renderer_render_cell_to_vector_file(GdsOutputRenderer *renderer, struct gds_cell *cell, GList *layer_infos, const char *pdf_file, const char *svg_file, double scale) { cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL; @@ -240,28 +240,40 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis double rec_x0, rec_y0, rec_width, rec_height; double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN; pid_t process_id; + int comm_pipe[2]; + char receive_message[200]; if (pdf_file == NULL && svg_file == NULL) { /* No output specified */ return -1; } + /* Generate communication pipe for status updates */ + if (pipe(comm_pipe) == -1) + return -2; + /* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't * brick everything. * * And by the way: This now bricks all Windows compatibility. Deal with it. */ - - /* Use fork for production code and -1 as value for debugging */ process_id = fork(); //process_id = -1; if (process_id < 0) { - /* Well... shit... We have to run it in our process. */ + /* This should not happen */ + fprintf(stderr, "Fatal error: Cairo Renderer: Could not spawn child process!"); + exit(-2); } else if (process_id > 0) { /* Woohoo... Successfully dumped the shitty code to an unknowing victim */ goto ret_parent; } + /* Close stdin and (stdout and stderr may live on) */ + close(0); + //close(1); + close(comm_pipe[0]); + + layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer)); /* Clear layers */ @@ -291,7 +303,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis } } - + dprintf(comm_pipe[1], "Rendering layers\n"); render_cell(cell, layers, scale); /* get size of image and top left coordinate */ @@ -309,7 +321,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis /* Print size */ cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0, &rec_width, &rec_height); - printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n", + dprintf(comm_pipe[1], "Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n", linfo->layer, (linfo->name && linfo->name[0] ? " (" : ""), (linfo->name && linfo->name[0] ? linfo->name : ""), @@ -328,7 +340,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis } - printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); + /* printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); */ if (pdf_file) { pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin); @@ -344,6 +356,8 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) { linfo = (struct layer_info *)info_list->data; + dprintf(comm_pipe[1], "Exporting layer %d to file\n", linfo->layer); + if (linfo->layer >= MAX_LAYERS) { printf("Layer outside of Spec.\n"); continue; @@ -387,14 +401,26 @@ ret_clear_layers: printf("Cairo export finished. It might still be buggy!\n"); - /* If forked, suspend process */ - if (process_id == 0) - exit(0); + /* Suspend child process */ + exit(0); - /* Fork didn't work. Just return here */ - return 0; ret_parent: + close(comm_pipe[1]); + + while (read_line_from_fd(comm_pipe[0], receive_message, sizeof(receive_message)) > 0) { + /* Strip \n from string and replace with ' ' */ + for (i = 0; receive_message[i] != '\0'; i++) { + if (receive_message[i] == '\n') + receive_message[i] = ' '; + } + + /* Update asyc progress*/ + gds_output_renderer_update_gui_status_from_async(renderer, receive_message); + } + waitpid(process_id, NULL, 0); + + close(comm_pipe[0]); return 0; } @@ -432,7 +458,7 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer, 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(renderer, cell, layer_infos, pdf_file, svg_file, scale); if (settings) g_object_unref(settings); diff --git a/output-renderers/gds-output-renderer.c b/output-renderers/gds-output-renderer.c index b07011e..8f8ed10 100644 --- a/output-renderers/gds-output-renderer.c +++ b/output-renderers/gds-output-renderer.c @@ -260,8 +260,6 @@ LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer /* This function seems to already reference the LayerSettings object */ g_object_get(renderer, "layer-settings", &ret, NULL); - /* Reference it, so it is not cleared by another thread overwriting the property */ - //g_object_ref(ret); /* It is now safe to clear the lock */ g_mutex_unlock(&priv->settings_lock); From 94ef879a9405596b6f3e989beac28aef3e0362b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 19 Sep 2019 21:44:30 +0200 Subject: [PATCH 21/43] Refactoring: rename progress update func of output renderer to gds_output_renderer_update_async_progress() --- include/gds-render/output-renderers/gds-output-renderer.h | 2 +- output-renderers/cairo-renderer.c | 4 ++-- output-renderers/gds-output-renderer.c | 2 +- output-renderers/latex-renderer.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/gds-render/output-renderers/gds-output-renderer.h b/include/gds-render/output-renderers/gds-output-renderer.h index 1f045b6..1dd9c85 100644 --- a/include/gds-render/output-renderers/gds-output-renderer.h +++ b/include/gds-render/output-renderers/gds-output-renderer.h @@ -152,7 +152,7 @@ int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct * @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); +void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status); G_END_DECLS diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 12bb7fa..18bb323 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -415,7 +415,7 @@ ret_parent: } /* Update asyc progress*/ - gds_output_renderer_update_gui_status_from_async(renderer, receive_message); + gds_output_renderer_update_async_progress(renderer, receive_message); } waitpid(process_id, NULL, 0); @@ -457,7 +457,7 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer, else pdf_file = output_file; - gds_output_renderer_update_gui_status_from_async(renderer, "Rendering Cairo Output..."); + gds_output_renderer_update_async_progress(renderer, "Rendering Cairo Output..."); ret = cairo_renderer_render_cell_to_vector_file(renderer, cell, layer_infos, pdf_file, svg_file, scale); if (settings) diff --git a/output-renderers/gds-output-renderer.c b/output-renderers/gds-output-renderer.c index 8f8ed10..5d27584 100644 --- a/output-renderers/gds-output-renderer.c +++ b/output-renderers/gds-output-renderer.c @@ -413,7 +413,7 @@ static gboolean idle_event_processor_callback(gpointer user_data) return FALSE; } -void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status) +void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status) { GSource *idle_event_processor; GdsOutputRendererPrivate *priv; diff --git a/output-renderers/latex-renderer.c b/output-renderers/latex-renderer.c index 654a2fb..fe3c5e2 100644 --- a/output-renderers/latex-renderer.c +++ b/output-renderers/latex-renderer.c @@ -241,7 +241,7 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil 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); + gds_output_renderer_update_async_progress(renderer, status->str); g_string_free(status, TRUE); /* Draw polygons of current cell */ From f20826ccf7f8daf909b0a9408dd03288a1401774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:54:26 +0200 Subject: [PATCH 22/43] LayerSettings: Fix layer_settings_load_from_csv() * Add stacked position to layer settings * Check if layer_settings instance is valid --- layer/layer-settings.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/layer/layer-settings.c b/layer/layer-settings.c index c1c3167..66d03de 100644 --- a/layer/layer-settings.c +++ b/layer/layer-settings.c @@ -314,10 +314,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path) GInputStream *in_stream; GDataInputStream *data_stream; int parser_ret; + int stacked_pos; struct layer_info linfo; file = g_file_new_for_path(path); in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL)); + + g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -2); + if (!in_stream) { ret = -1; goto ret_destroy_file; @@ -327,11 +331,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path) data_stream = g_data_input_stream_new(in_stream); + stacked_pos = 0; while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) { /* Line broken */ if (parser_ret == 1) continue; + linfo.stacked_position = stacked_pos++; + layer_settings_append_layer_info(settings, &linfo); /* Clear name to prevent memory leak */ if (linfo.name) From c365c899084422c9e142b9b082c744c52be53a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:55:59 +0200 Subject: [PATCH 23/43] LayerSelector: Make import of layer information from CSV independed from mapping-parser code. Use LayerSettings class instead. --- layer/layer-selector.c | 55 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/layer/layer-selector.c b/layer/layer-selector.c index 1ad0976..b40bead 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -577,6 +577,7 @@ void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs) static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer) { LayerElement *ret = NULL; + for (; el_list != NULL; el_list = el_list->next) { if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) { ret = LAYER_ELEMENT(el_list->data); @@ -597,19 +598,18 @@ static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, i * @param self LayerSelector instance * @param file_name File name to load from */ -static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gchar *file_name) +static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name) { GFile *file; GFileInputStream *stream; GDataInputStream *dstream; LayerElement *le; - char *name; - gboolean export; - int layer; - GdkRGBA color; - int result; GList *rows; GList *temp; + GList *layer_infos; + int status; + LayerSettings *layer_settings; + struct layer_info *linfo; file = g_file_new_for_path(file_name); stream = g_file_read(file, NULL, NULL); @@ -624,31 +624,40 @@ static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gch /* Reference and remove all rows from box */ for (temp = rows; temp != NULL; temp = temp->next) { le = LAYER_ELEMENT(temp->data); - /* Referencing protets the widget from being deleted when removed */ + /* Referencing protects the widget from being deleted when removed */ g_object_ref(G_OBJECT(le)); gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le)); } - while((result = mapping_parser_load_line(dstream, &export, &name, &layer, &color)) >= 0) { - /* skip broken line */ - if (result == 1) + /* Load Layer settings. No need to check pointer, will be checked by load csv func. */ + layer_settings = layer_settings_new(); + + status = layer_settings_load_from_csv(layer_settings, file_name); + if (status) + goto abort_layer_settings; + + layer_infos = layer_settings_get_layer_info_list(layer_settings); + if (!layer_infos) + goto abort_layer_settings; + + /* Loop over all layer infos read from the CSV file */ + for (; layer_infos; layer_infos = g_list_next(layer_infos)) { + linfo = (struct layer_info *)layer_infos->data; + le = layer_selector_find_layer_element_in_list(rows, linfo->layer); + if (!le) continue; - /* Add rows in the same order as in file */ - if ((le = layer_selector_find_layer_element_in_list(rows, layer))) { - gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1); - - layer_element_set_color(le, &color); - layer_element_set_export(le, export); - layer_element_set_name(le, name); - g_free(name); - - /* Dereference and remove from list */ - g_object_unref(G_OBJECT(le)); - rows = g_list_remove(rows, le); - } + layer_element_set_name(le, linfo->name); + layer_element_set_export(le, (linfo->render ? TRUE : FALSE)); + layer_element_set_color(le, &linfo->color); + gtk_container_add(GTK_CONTAINER(self->list_box), GTK_WIDGET(le)); + rows = g_list_remove(rows, le); } +abort_layer_settings: + /* Destroy layer settings. Not needed for adding remaining elements */ + g_object_unref(layer_settings); + /* Add remaining elements */ for (temp = rows; temp != NULL; temp = temp->next) { le = LAYER_ELEMENT(temp->data); From 62388e40539a966d915e377496e82aba45027532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 17:59:38 +0200 Subject: [PATCH 24/43] Remove code from mapping parser that implements csv read. Use LayerSettings class instead. --- include/gds-render/layer/mapping-parser.h | 11 ---- layer/mapping-parser.c | 63 ----------------------- 2 files changed, 74 deletions(-) diff --git a/include/gds-render/layer/mapping-parser.h b/include/gds-render/layer/mapping-parser.h index cca1318..2b77fbc 100644 --- a/include/gds-render/layer/mapping-parser.h +++ b/include/gds-render/layer/mapping-parser.h @@ -36,17 +36,6 @@ #include #include -/** - * @brief Load a line from \p stream and parse try to parse it as layer information - * @param stream Input data stream - * @param export Layer shall be exported - * @param name Layer name. Free returned pointer after using. - * @param layer Layer number - * @param color RGBA color. - * @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end - */ -int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color); - /** * @brief Create Line for LayerMapping file with supplied information * @param layer_element information diff --git a/layer/mapping-parser.c b/layer/mapping-parser.c index ad0d1e7..94d854a 100644 --- a/layer/mapping-parser.c +++ b/layer/mapping-parser.c @@ -31,69 +31,6 @@ #include -int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color) -{ - int ret; - gsize len; - gchar *line; - GRegex *regex; - GMatchInfo *mi; - char *match; - - if ((!export) || (!name) || (!layer) || (!color)) { - ret = 1; - goto ret_direct; - } - - regex = g_regex_new("^(?[0-9]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[01]),(?.*)$", 0, 0, NULL); - - line = g_data_input_stream_read_line(stream, &len, NULL, NULL); - if (!line) { - ret = -1; - goto destroy_regex; - } - - /* Match line in CSV */ - g_regex_match(regex, line, 0, &mi); - if (g_match_info_matches(mi)) { - /* Line is valid */ - match = g_match_info_fetch_named(mi, "layer"); - *layer = (int)g_ascii_strtoll(match, NULL, 10); - g_free(match); - match = g_match_info_fetch_named(mi, "r"); - color->red = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "g"); - color->green = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "b"); - color->blue = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "a"); - color->alpha = g_ascii_strtod(match, NULL); - g_free(match); - match = g_match_info_fetch_named(mi, "export"); - *export = ((!strcmp(match, "1")) ? TRUE : FALSE); - g_free(match); - match = g_match_info_fetch_named(mi, "name"); - *name = match; - - ret = 0; - } else { - /* Line is malformatted */ - printf("Could not recognize line in CSV as valid entry: %s\n", line); - ret = 1; - } - - g_match_info_free(mi); - g_free(line); -destroy_regex: - g_regex_unref(regex); -ret_direct: - return ret; - -} - void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len) { int i; From 0a04f2fed45d391e74dc9c0b0600b6f3180b2bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:20:03 +0200 Subject: [PATCH 25/43] LayerSettings: Fix bug in CSV export function --- layer/layer-settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layer/layer-settings.c b/layer/layer-settings.c index 66d03de..9423dd8 100644 --- a/layer/layer-settings.c +++ b/layer/layer-settings.c @@ -223,7 +223,7 @@ int layer_settings_to_csv(LayerSettings *settings, const char *path) linfo = (struct layer_info *)info_iter->data; layer_settings_gen_csv_line(string, linfo); - g_output_stream_write(w_fstream, string->str, sizeof(gchar), NULL, NULL); + g_output_stream_write(w_fstream, string->str, string->len * sizeof(gchar), NULL, NULL); } /* Delete string */ From 9245d68da10388756aac44fded6c1391275af683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:21:02 +0200 Subject: [PATCH 26/43] LayerSelector: Use Layer Settings for CSV export. This makes the mapping parser unnecessary. It can be removed --- layer/layer-selector.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/layer/layer-selector.c b/layer/layer-selector.c index b40bead..fcda12d 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -711,29 +711,14 @@ static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user */ static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name) { - FILE *file; - char workbuff[512]; - GList *le_list; - GList *temp; + LayerSettings *layer_settings; - /* Overwrite existing file */ - file = fopen((const char *)file_name, "w"); + g_return_if_fail(LAYER_IS_SELECTOR(self)); + g_return_if_fail(file_name); - le_list = gtk_container_get_children(GTK_CONTAINER(self->list_box)); - - /* File format is CSV: ,,,,,,, */ - for (temp = le_list; temp != NULL; temp = temp->next) { - /* To be sure it is a valid string */ - workbuff[0] = 0; - mapping_parser_gen_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff)); - fwrite(workbuff, sizeof(char), strlen(workbuff), file); - } - - g_list_free(le_list); - - /* Save File */ - fflush(file); - fclose(file); + /* Get layer settings. No need to check return value. to_csv func is safe */ + layer_settings = layer_selector_export_rendered_layer_info(self); + (void)layer_settings_to_csv(layer_settings, file_name); } /** From a65295fbebe1244a4b172d547ca77510dc19a529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 25 Sep 2019 18:25:12 +0200 Subject: [PATCH 27/43] remove now unneeded mapping parser completely --- command-line.c | 1 - include/gds-render/layer/mapping-parser.h | 49 -------------- layer/layer-selector.c | 1 - layer/mapping-parser.c | 81 ----------------------- 4 files changed, 132 deletions(-) delete mode 100644 include/gds-render/layer/mapping-parser.h delete mode 100644 layer/mapping-parser.c diff --git a/command-line.c b/command-line.c index a27e4d0..4e75ec6 100644 --- a/command-line.c +++ b/command-line.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include diff --git a/include/gds-render/layer/mapping-parser.h b/include/gds-render/layer/mapping-parser.h deleted file mode 100644 index 2b77fbc..0000000 --- a/include/gds-render/layer/mapping-parser.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file mapping-parser.h - * @brief Function to read a mapping file line and parse it. - * @author Mario Hüttel - */ - -#ifndef __MAPPING_PARSER_H__ -#define __MAPPING_PARSER_H__ - -/** - * @addtogroup Mapping-Parser - * @{ - */ - -#include - -#include -#include - -/** - * @brief Create Line for LayerMapping file with supplied information - * @param layer_element information - * @param line_buffer buffer to write to - * @param max_len Maximum length that cna be used in \p line_buffer - */ -void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len); - -/** @} */ - -#endif /* __MAPPING_PARSER_H__ */ diff --git a/layer/layer-selector.c b/layer/layer-selector.c index fcda12d..0f9b342 100644 --- a/layer/layer-selector.c +++ b/layer/layer-selector.c @@ -36,7 +36,6 @@ #include #include #include -#include struct _LayerSelector { /* Parent */ diff --git a/layer/mapping-parser.c b/layer/mapping-parser.c deleted file mode 100644 index 94d854a..0000000 --- a/layer/mapping-parser.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file mapping-parser.c - * @brief Function to read a mapping file line and parse it. - * @author Mario Hüttel - */ - -/** - * @addtogroup Mapping-Parser - * @{ - */ - -#include - -void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len) -{ - int i; - GString *string; - gboolean export; - const gchar *name; - int layer; - GdkRGBA color; - - string = g_string_new_len(NULL, max_len-1); - - /* Extract values */ - export = layer_element_get_export(layer_element); - name = (const gchar*)layer_element_get_name(layer_element); - layer = layer_element_get_layer(layer_element); - layer_element_get_color(layer_element, &color); - - /* print values to line */ - g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n", - layer, color.red, color.green, - color.blue, color.alpha, (export == TRUE ? 1 : 0), name); - /* Fix broken locale settings */ - for (i = 0; string->str[i]; i++) { - if (string->str[i] == ',') - string->str[i] = '.'; - } - - for (i = 0; string->str[i]; i++) { - if (string->str[i] == ':') - string->str[i] = ','; - } - - if (string->len > (max_len-1)) { - printf("Layer Definition too long. Please shorten Layer Name!!\n"); - line_buffer[0] = 0x0; - return; - } - - /* copy max_len bytes of string */ - strncpy(line_buffer, (char *)string->str, max_len-1); - line_buffer[max_len-1] = 0; - - /* Completely remove string */ - g_string_free(string, TRUE); -} - -/** @} */ - From 23775b079a7442cc51aacd18dbe7771080999250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 20:46:41 +0200 Subject: [PATCH 28/43] Code improvements --- main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.c b/main.c index f13e936..1e7113a 100644 --- a/main.c +++ b/main.c @@ -183,7 +183,6 @@ static void gapp_activate(GApplication *app, gpointer user_data) */ static int start_gui(int argc, char **argv) { - GtkApplication *gapp; int app_status; static struct application_data appdata = { @@ -289,7 +288,6 @@ int main(int argc, char **argv) scale = 1; } - /* Get gds name */ gds_name = argv[1]; From dc30950df5f340e61138e2e790d5fc8b2920dfe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 21:42:49 +0200 Subject: [PATCH 29/43] Tree store for cell selection moved to GUI file --- cell-selector/tree-store.c | 38 ++-- gds-render-gui.c | 165 +++++++++++++++++- include/gds-render/cell-selector/tree-store.h | 9 +- 3 files changed, 180 insertions(+), 32 deletions(-) diff --git a/cell-selector/tree-store.c b/cell-selector/tree-store.c index eec292d..9c6e6b4 100644 --- a/cell-selector/tree-store.c +++ b/cell-selector/tree-store.c @@ -32,6 +32,11 @@ #include #include +struct filter_visible_params { + GtkSearchEntry *search_entry; + GtkTreeView *tree_view; +}; + /** * @brief this function olny allows cells to be selected * @param selection @@ -78,13 +83,13 @@ static gboolean tree_sel_func(GtkTreeSelection *selection, */ static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { - struct tree_stores *stores = (struct tree_stores *)data; + struct filter_visible_params *params = (struct filter_visible_params *)data; struct gds_cell *cell; struct gds_library *lib; gboolean result = FALSE; const char *search_string; - if (!model || !iter || !stores) + if (!model || !iter || !params) goto exit_filter; gtk_tree_model_get(model, iter, CELL_SEL_CELL, &cell, CELL_SEL_LIBRARY, &lib, -1); @@ -97,7 +102,7 @@ static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter if (!cell) goto exit_filter; - search_string = gtk_entry_get_text(stores->search_entry); + search_string = gtk_entry_get_text(GTK_ENTRY(params->search_entry)); /* Show all, if field is empty */ if (!strlen(search_string)) @@ -106,7 +111,7 @@ static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter if (strstr(cell->name, search_string)) result = TRUE; - gtk_tree_view_expand_all(stores->base_tree_view); + gtk_tree_view_expand_all(params->tree_view); exit_filter: return result; @@ -126,29 +131,30 @@ static void change_filter(GtkWidget *entry, gpointer data) * @param search_entry Entry field for search * @return Tree stores for storing data inside the GtkTreeView */ -struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry) +int setup_cell_selector(GtkTreeView *view, GtkEntry *search_entry, GtkTreeStore **base_store, + GtkTreeModelFilter **filter) { static struct tree_stores stores; + GtkTreeStore *base_store; GtkCellRenderer *render_dates; GtkCellRenderer *render_cell; GtkCellRenderer *render_lib; GtkTreeViewColumn *column; - stores.base_tree_view = view; - stores.search_entry = search_entry; - stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); + + *base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, + G_TYPE_POINTER, G_TYPE_UINT, + G_TYPE_STRING, G_TYPE_STRING); /* Searching */ - if (search_entry) { - stores.filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(stores.base_store), NULL)); - gtk_tree_model_filter_set_visible_func (stores.filter, - (GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func, - &stores, NULL); - g_signal_connect(GTK_SEARCH_ENTRY(search_entry), "search-changed", G_CALLBACK(change_filter), &stores); - } + *filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(*base_store), NULL)); + gtk_tree_model_filter_set_visible_func(*filter, + (GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func, + &stores, NULL); + g_signal_connect(GTK_SEARCH_ENTRY(search_entry), "search-changed", G_CALLBACK(change_filter), &stores); - gtk_tree_view_set_model(view, GTK_TREE_MODEL(stores.filter)); + gtk_tree_view_set_model(view, GTK_TREE_MODEL(*filter)); render_dates = gtk_cell_renderer_text_new(); render_cell = lib_cell_renderer_new(); diff --git a/gds-render-gui.c b/gds-render-gui.c index 86561dc..78e36fe 100644 --- a/gds-render-gui.c +++ b/gds-render-gui.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,16 @@ #include #include +/** @brief Columns of selection tree view */ +enum cell_store_columns { + CELL_SEL_LIBRARY = 0, + CELL_SEL_CELL, + CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */ + CELL_SEL_MODDATE, + CELL_SEL_ACCESSDATE, + CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */ +}; + enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT}; static guint gds_render_gui_signals[SIGNAL_COUNT]; @@ -64,6 +73,7 @@ struct _GdsRenderGui { GtkWidget *save_layer_button; GtkWidget *select_all_button; GtkTreeStore *cell_tree_store; + GtkTreeModelFilter *cell_filter; GtkWidget *cell_search_entry; LayerSelector *layer_selector; GtkTreeView *cell_tree_view; @@ -124,6 +134,148 @@ static GString *generate_string_from_date(struct gds_time_field *date) return str; } +/** + * @brief this function olny allows cells to be selected + * @param selection + * @param model + * @param path + * @param path_currently_selected + * @param data + * @return TRUE if element is selectable, FALSE if not + */ +static gboolean tree_sel_func(GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + gpointer data) +{ + GtkTreeIter iter; + struct gds_cell *cell; + unsigned int error_level; + gboolean ret = FALSE; + (void)selection; + (void)path_currently_selected; + (void)data; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1); + + /* Allow only rows with _valid_ cell to be selected */ + if (cell) { + /* Cell available. Check if it passed the critical checks */ + if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR)) + ret = TRUE; + } + + return ret; +} + +static void cell_tree_view_change_filter(GtkWidget *entry, gpointer data) +{ + GdsRenderGui *self = RENDERER_GUI(data); + (void)entry; + + gtk_tree_model_filter_refilter(self->cell_filter); +} + +/** + * @brief cell_store_filter_visible_func Decides whether an element of the tree model @p model is visible. + * @param model Tree model + * @param iter Current element / iter in Model to check + * @param data Data. Set to static stores variable + * @return TRUE if visible, else FALSE + * @note TODO: Maybe implement Damerau-Levenshtein distance matching + */ +static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) +{ + GdsRenderGui *self; + struct gds_cell *cell; + struct gds_library *lib; + gboolean result = FALSE; + const char *search_string; + + self = RENDERER_GUI(data); + g_return_val_if_fail(RENDERER_IS_GUI(self), FALSE); + + if (!model || !iter) + goto exit_filter; + + gtk_tree_model_get(model, iter, CELL_SEL_CELL, &cell, CELL_SEL_LIBRARY, &lib, -1); + + if (lib) { + result = TRUE; + goto exit_filter; + } + + if (!cell) + goto exit_filter; + + search_string = gtk_entry_get_text(GTK_ENTRY(self->cell_search_entry)); + + /* Show all, if field is empty */ + if (!strlen(search_string)) + result = TRUE; + + if (strstr(cell->name, search_string)) + result = TRUE; + + gtk_tree_view_expand_all(self->cell_tree_view); + +exit_filter: + return result; +} + +/** + * @brief Setup a GtkTreeView with the necessary columns + * @param self Current GUI object + */ +int gds_render_gui_setup_cell_selector(GdsRenderGui *self) +{ + GtkTreeStore *base_store; + GtkCellRenderer *render_dates; + GtkCellRenderer *render_cell; + GtkCellRenderer *render_lib; + GtkTreeViewColumn *column; + + self->cell_tree_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, + G_TYPE_POINTER, G_TYPE_UINT, + G_TYPE_STRING, G_TYPE_STRING); + + /* Searching */ + self->cell_filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(base_store), NULL)); + gtk_tree_model_filter_set_visible_func(self->cell_filter, + (GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func, + self, NULL); + g_signal_connect(GTK_SEARCH_ENTRY(self->cell_search_entry), "search-changed", + G_CALLBACK(cell_tree_view_change_filter), self); + + gtk_tree_view_set_model(self->cell_tree_view, GTK_TREE_MODEL(self->cell_filter)); + + /* TODO: check if these are destroyed afterwards */ + render_dates = gtk_cell_renderer_text_new(); + render_cell = lib_cell_renderer_new(); + render_lib = lib_cell_renderer_new(); + + column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL); + gtk_tree_view_append_column(self->cell_tree_view, column); + + column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, + "error-level", CELL_SEL_CELL_ERROR_STATE, NULL); + gtk_tree_view_append_column(self->cell_tree_view, column); + + column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL); + gtk_tree_view_append_column(self->cell_tree_view, column); + + column = gtk_tree_view_column_new_with_attributes("Acc. Date", render_dates, "text", CELL_SEL_ACCESSDATE, NULL); + gtk_tree_view_append_column(self->cell_tree_view, column); + + /* Callback for selection + * This prevents selecting a library */ + gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(self->cell_tree_view), tree_sel_func, NULL, NULL); + + return 0; +} + /** * @brief Callback function of Load GDS button * @param button @@ -536,6 +688,7 @@ static void gds_render_gui_dispose(GObject *gobject) g_clear_object(&self->convert_button); g_clear_object(&self->layer_selector); g_clear_object(&self->cell_tree_store); + g_clear_object(&self->cell_filter); g_clear_object(&self->cell_search_entry); g_clear_object(&self->activity_status_bar); g_clear_object(&self->palette); @@ -624,7 +777,6 @@ static void gds_render_gui_init(GdsRenderGui *self) GtkBuilder *main_builder; GtkWidget *listbox; GtkHeaderBar *header_bar; - struct tree_stores *cell_selector_stores; GtkWidget *sort_up_button; GtkWidget *sort_down_button; GtkWidget *activity_bar_box; @@ -636,9 +788,7 @@ static void gds_render_gui_init(GdsRenderGui *self) self->cell_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree")); self->cell_search_entry = GTK_WIDGET(gtk_builder_get_object(main_builder, "cell-search")); - cell_selector_stores = setup_cell_selector(self->cell_tree_view, GTK_ENTRY(self->cell_search_entry)); - - self->cell_tree_store = cell_selector_stores->base_store; + gds_render_gui_setup_cell_selector(self); self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window")); self->open_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")); @@ -716,10 +866,9 @@ static void gds_render_gui_init(GdsRenderGui *self) g_object_ref(self->main_window); g_object_ref(self->cell_tree_view); g_object_ref(self->convert_button); - g_object_ref(self->layer_selector); - g_object_ref(self->cell_tree_store); + /* g_object_ref(self->layer_selector); <= This is already referenced by the _new() function */ 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); diff --git a/include/gds-render/cell-selector/tree-store.h b/include/gds-render/cell-selector/tree-store.h index 8f0e65e..b6378ab 100644 --- a/include/gds-render/cell-selector/tree-store.h +++ b/include/gds-render/cell-selector/tree-store.h @@ -43,14 +43,7 @@ enum cell_store_columns { CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */ }; -struct tree_stores { - GtkTreeView *base_tree_view; - GtkTreeStore *base_store; - GtkTreeModelFilter *filter; - GtkEntry *search_entry; -}; - -struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry); +int setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry); #endif /* __TREE_STORE_H__ */ From 01e61a79fd84c7c7f16c60d4f1171a9128a1b545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 21:59:24 +0200 Subject: [PATCH 30/43] Integrate cell selector to main gui class --- cell-selector/tree-store.c | 182 ------------------ gds-render-gui.c | 12 +- include/gds-render/cell-selector/tree-store.h | 50 ----- 3 files changed, 8 insertions(+), 236 deletions(-) delete mode 100644 cell-selector/tree-store.c delete mode 100644 include/gds-render/cell-selector/tree-store.h diff --git a/cell-selector/tree-store.c b/cell-selector/tree-store.c deleted file mode 100644 index 9c6e6b4..0000000 --- a/cell-selector/tree-store.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file tree-store.h - * @brief Tree store implementation - * @author Mario Hüttel - */ - -/** - * @addtogroup GUI - * @{ - */ - -#include -#include -#include - -struct filter_visible_params { - GtkSearchEntry *search_entry; - GtkTreeView *tree_view; -}; - -/** - * @brief this function olny allows cells to be selected - * @param selection - * @param model - * @param path - * @param path_currently_selected - * @param data - * @return TRUE if element is selectable, FALSE if not - */ -static gboolean tree_sel_func(GtkTreeSelection *selection, - GtkTreeModel *model, - GtkTreePath *path, - gboolean path_currently_selected, - gpointer data) -{ - GtkTreeIter iter; - struct gds_cell *cell; - unsigned int error_level; - gboolean ret = FALSE; - (void)selection; - (void)path_currently_selected; - (void)data; - - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1); - - /* Allow only rows with _valid_ cell to be selected */ - if (cell) { - /* Cell available. Check if it passed the critical checks */ - if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR)) - ret = TRUE; - } - - return ret; -} - -/** - * @brief cell_store_filter_visible_func Decides whether an element of the tree model @p model is visible. - * @param model Tree model - * @param iter Current element / iter in Model to check - * @param data Data. Set to static stores variable - * @return TRUE if visible, else FALSE - * @note TODO: Maybe implement Damerau-Levenshtein distance matching - */ -static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) -{ - struct filter_visible_params *params = (struct filter_visible_params *)data; - struct gds_cell *cell; - struct gds_library *lib; - gboolean result = FALSE; - const char *search_string; - - if (!model || !iter || !params) - goto exit_filter; - - gtk_tree_model_get(model, iter, CELL_SEL_CELL, &cell, CELL_SEL_LIBRARY, &lib, -1); - - if (lib) { - result = TRUE; - goto exit_filter; - } - - if (!cell) - goto exit_filter; - - search_string = gtk_entry_get_text(GTK_ENTRY(params->search_entry)); - - /* Show all, if field is empty */ - if (!strlen(search_string)) - result = TRUE; - - if (strstr(cell->name, search_string)) - result = TRUE; - - gtk_tree_view_expand_all(params->tree_view); - -exit_filter: - return result; -} - -static void change_filter(GtkWidget *entry, gpointer data) -{ - struct tree_stores *stores = (struct tree_stores *)data; - (void)entry; - - gtk_tree_model_filter_refilter(stores->filter); -} - -/** - * @brief Setup a GtkTreeView with the necessary columns - * @param view Tree view to set up - * @param search_entry Entry field for search - * @return Tree stores for storing data inside the GtkTreeView - */ -int setup_cell_selector(GtkTreeView *view, GtkEntry *search_entry, GtkTreeStore **base_store, - GtkTreeModelFilter **filter) -{ - static struct tree_stores stores; - GtkTreeStore *base_store; - GtkCellRenderer *render_dates; - GtkCellRenderer *render_cell; - GtkCellRenderer *render_lib; - GtkTreeViewColumn *column; - - - - *base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, - G_TYPE_POINTER, G_TYPE_UINT, - G_TYPE_STRING, G_TYPE_STRING); - - /* Searching */ - *filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(*base_store), NULL)); - gtk_tree_model_filter_set_visible_func(*filter, - (GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func, - &stores, NULL); - g_signal_connect(GTK_SEARCH_ENTRY(search_entry), "search-changed", G_CALLBACK(change_filter), &stores); - - gtk_tree_view_set_model(view, GTK_TREE_MODEL(*filter)); - - render_dates = gtk_cell_renderer_text_new(); - render_cell = lib_cell_renderer_new(); - render_lib = lib_cell_renderer_new(); - - column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL); - gtk_tree_view_append_column(view, column); - - column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, - "error-level", CELL_SEL_CELL_ERROR_STATE, NULL); - gtk_tree_view_append_column(view, column); - - column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL); - gtk_tree_view_append_column(view, column); - - column = gtk_tree_view_column_new_with_attributes("Acc. Date", render_dates, "text", CELL_SEL_ACCESSDATE, NULL); - gtk_tree_view_append_column(view, column); - - /* Callback for selection - * This prevents selecting a library */ - gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(view), tree_sel_func, NULL, NULL); - - return &stores; -} -/** @} */ diff --git a/gds-render-gui.c b/gds-render-gui.c index 78e36fe..f18b3c3 100644 --- a/gds-render-gui.c +++ b/gds-render-gui.c @@ -135,7 +135,7 @@ static GString *generate_string_from_date(struct gds_time_field *date) } /** - * @brief this function olny allows cells to be selected + * @brief This function only allows valid cells to be selected * @param selection * @param model * @param path @@ -170,6 +170,11 @@ static gboolean tree_sel_func(GtkTreeSelection *selection, return ret; } +/** + * @brief Trigger refiltering of cell filter + * @param entry Unused widget, that emitted the signal + * @param data GdsrenderGui self instance + */ static void cell_tree_view_change_filter(GtkWidget *entry, gpointer data) { GdsRenderGui *self = RENDERER_GUI(data); @@ -210,7 +215,7 @@ static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter if (!cell) goto exit_filter; - search_string = gtk_entry_get_text(GTK_ENTRY(self->cell_search_entry)); + search_string = gtk_entry_get_text(GTK_ENTRY(self->cell_search_entry )); /* Show all, if field is empty */ if (!strlen(search_string)) @@ -231,7 +236,6 @@ exit_filter: */ int gds_render_gui_setup_cell_selector(GdsRenderGui *self) { - GtkTreeStore *base_store; GtkCellRenderer *render_dates; GtkCellRenderer *render_cell; GtkCellRenderer *render_lib; @@ -242,7 +246,7 @@ int gds_render_gui_setup_cell_selector(GdsRenderGui *self) G_TYPE_STRING, G_TYPE_STRING); /* Searching */ - self->cell_filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(base_store), NULL)); + self->cell_filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(self->cell_tree_store), NULL)); gtk_tree_model_filter_set_visible_func(self->cell_filter, (GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func, self, NULL); diff --git a/include/gds-render/cell-selector/tree-store.h b/include/gds-render/cell-selector/tree-store.h deleted file mode 100644 index b6378ab..0000000 --- a/include/gds-render/cell-selector/tree-store.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * GDSII-Converter - * Copyright (C) 2018 Mario Hüttel - * - * This file is part of GDSII-Converter. - * - * GDSII-Converter is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * GDSII-Converter 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 GDSII-Converter. If not, see . - */ - -/** - * @file tree-store.h - * @brief Header file for Tree store implementation - * @author Mario Hüttel - */ - -/** - * @addtogroup GUI - * @{ - */ - -#ifndef __TREE_STORE_H__ -#define __TREE_STORE_H__ - -#include - -/** @brief Columns of selection tree view */ -enum cell_store_columns { - CELL_SEL_LIBRARY = 0, - CELL_SEL_CELL, - CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */ - CELL_SEL_MODDATE, - CELL_SEL_ACCESSDATE, - CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */ -}; - -int setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry); - -#endif /* __TREE_STORE_H__ */ - -/** @} */ From 1de96f501c60a888f97451a869abf98e86d2ff7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 22:32:01 +0200 Subject: [PATCH 31/43] Checked renderers for memory leaks --- gds-render-gui.c | 1 - 1 file changed, 1 deletion(-) diff --git a/gds-render-gui.c b/gds-render-gui.c index f18b3c3..62bcfc5 100644 --- a/gds-render-gui.c +++ b/gds-render-gui.c @@ -255,7 +255,6 @@ int gds_render_gui_setup_cell_selector(GdsRenderGui *self) gtk_tree_view_set_model(self->cell_tree_view, GTK_TREE_MODEL(self->cell_filter)); - /* TODO: check if these are destroyed afterwards */ render_dates = gtk_cell_renderer_text_new(); render_cell = lib_cell_renderer_new(); render_lib = lib_cell_renderer_new(); From 6eaf86dc1c2cbe17969dd8302a3f64abbb794d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 22:59:51 +0200 Subject: [PATCH 32/43] Fix doxygen configuartion to handle __attribute__ correctly --- doxygen/Doxyconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doxygen/Doxyconfig b/doxygen/Doxyconfig index d417f9b..3f5e4c1 100644 --- a/doxygen/Doxyconfig +++ b/doxygen/Doxyconfig @@ -2119,7 +2119,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2127,7 +2127,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2159,7 +2159,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = __attribute__(x)= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The From 67b8dc24436d014e4a577c861a8fa6a0307156a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 23:01:12 +0200 Subject: [PATCH 33/43] Doxygen fix --- output-renderers/latex-renderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output-renderers/latex-renderer.c b/output-renderers/latex-renderer.c index fe3c5e2..19c7477 100644 --- a/output-renderers/latex-renderer.c +++ b/output-renderers/latex-renderer.c @@ -35,7 +35,7 @@ /** * @brief Struct representing the LaTeX-Renderer object. * - * This struct holds the LaTeX renderer internal data. It is only used inside the @ref LatexRenderer class. + * This struct holds the LaTeX renderer internal data. It is only used inside the @ref LaTeX-Renderer class. */ struct _LatexRenderer { GdsOutputRenderer parent; From 00d67109221ac4f5357b51af884ffdd76c2eac2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 28 Sep 2019 23:12:14 +0200 Subject: [PATCH 34/43] Doxygen error fixes --- doxygen/gds-output-renderer.dox | 2 +- output-renderers/cairo-renderer.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doxygen/gds-output-renderer.dox b/doxygen/gds-output-renderer.dox index a5382d4..2100fef 100644 --- a/doxygen/gds-output-renderer.dox +++ b/doxygen/gds-output-renderer.dox @@ -9,7 +9,7 @@ * @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. + * A allowed function to be called from the async rendering thread is #gds_output_renderer_update_async_progress 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. * diff --git a/output-renderers/cairo-renderer.c b/output-renderers/cairo-renderer.c index 18bb323..36d959b 100644 --- a/output-renderers/cairo-renderer.c +++ b/output-renderers/cairo-renderer.c @@ -220,6 +220,7 @@ static int read_line_from_fd(int fd, char *buff, size_t buff_size) /** * @brief Render \p cell to a PDF file specified by \p pdf_file + * @param renderer The current renderer this function is running from * @param cell Toplevel cell to @ref Cairo-Renderer * @param layer_infos List of layer information. Specifies color and layer stacking * @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated From 13e202424b2e93f022457fac35cad67a2e2b898f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 3 Oct 2019 11:57:16 +0200 Subject: [PATCH 35/43] Text improvements --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 1e7113a..40d7734 100644 --- a/main.c +++ b/main.c @@ -133,7 +133,7 @@ static const GActionEntry app_actions[] = { * @brief Called when a GUI main window is closed * * The GdsRenderGui object associated with the closed main window - * is removed from the list of open GUIs (\p user_data) and unreferenced. + * is removed from the list of open GUIs (\p user_data) and dereferenced. * * @param gui The GUI instance the closed main window belongs to * @param user_data List of GUIs @@ -198,7 +198,7 @@ static int start_gui(int argc, char **argv) if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) { g_application_activate(G_APPLICATION(gapp)); - printf("There is already an open instance. Will open second window in said instance.\n"); + printf("There is already an open instance. Will open second window in that instance.\n"); return 0; } From 1f914d1218125cecdedaf2062c39e8780ce3e72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 3 Oct 2019 11:57:53 +0200 Subject: [PATCH 36/43] Add version dependent application id. Multiple versions of htis program can now run at the same time --- main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 40d7734..b1a333f 100644 --- a/main.c +++ b/main.c @@ -184,6 +184,7 @@ static void gapp_activate(GApplication *app, gpointer user_data) static int start_gui(int argc, char **argv) { GtkApplication *gapp; + GString *application_domain; int app_status; static struct application_data appdata = { .gui_list = NULL @@ -192,7 +193,16 @@ static int start_gui(int argc, char **argv) GMenu *m_quit; GMenu *m_about; - gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE); + /* + * Generate version dependent application id + * This allows running the application in different versions at the same time. + */ + application_domain = g_string_new(NULL); + g_string_printf(application_domain, "de.shimatta.gds_render_%s", _app_git_commit); + + gapp = gtk_application_new(application_domain->str, G_APPLICATION_FLAGS_NONE); + g_string_free(application_domain, TRUE); + g_application_register(G_APPLICATION(gapp), NULL, NULL); g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata); From 7fdd1f6c929f669052abb3d0fada959e4ed52629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 18 Oct 2019 18:12:21 +0200 Subject: [PATCH 37/43] Add tooltips to main window's buttons --- resources/main.glade | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/resources/main.glade b/resources/main.glade index 8ab358f..f5bf72e 100644 --- a/resources/main.glade +++ b/resources/main.glade @@ -20,6 +20,7 @@ True False + Save the current layer configuration to CSV gtk-save-as @@ -54,6 +55,7 @@ True True True + Open GDS2 Database True True