2018-05-10 01:43:14 +02:00
/*
2018-05-15 22:54:10 +02:00
* GDSII - Converter
2018-05-10 01:43:14 +02:00
* Copyright ( C ) 2018 Mario Hüttel < mario . huettel @ gmx . net >
*
* This file is part of GDSII - Converter .
*
* GDSII - Converter is free software : you can redistribute it and / or modify
2018-05-16 16:29:34 +02:00
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
2018-05-10 01:43:14 +02:00
*
2018-05-15 22:54:10 +02:00
* GDSII - Converter is distributed in the hope that it will be useful ,
2018-05-10 01:43:14 +02:00
* 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 < http : //www.gnu.org/licenses/>.
*/
2019-03-30 19:51:56 +01:00
/**
* @ file main . c
* @ brief main . c
* @ author Mario Hüttel < mario . huettel @ gmx . net >
*/
2019-10-18 19:29:55 +02:00
2018-05-07 13:27:50 +02:00
# include <stdio.h>
2018-05-08 15:00:37 +02:00
# include <gtk/gtk.h>
2018-07-23 17:00:37 +02:00
# include <glib.h>
2019-10-18 19:29:55 +02:00
# include <glib/gi18n.h>
# include <locale.h>
2019-03-26 19:57:19 +01:00
# include <gds-render/gds-render-gui.h>
# include <gds-render/command-line.h>
2019-06-17 21:50:49 +02:00
# include <gds-render/output-renderers/external-renderer.h>
2019-03-26 19:57:19 +01:00
# include <gds-render/version.h>
2018-05-08 16:50:30 +02:00
2019-03-30 19:51:56 +01:00
/**
* @ brief Structure containing The GtkApplication and a list containing the GdsRenderGui objects .
*/
2018-07-23 15:10:40 +02:00
struct application_data {
2019-03-13 22:54:52 +01:00
GtkApplication * app ;
2019-03-15 20:02:03 +01:00
GList * gui_list ;
2018-07-23 15:10:40 +02:00
} ;
2019-03-30 19:51:56 +01:00
/**
* @ brief Callback for the menu entry ' Quit '
*
* Destroys all GUIs contained in the application_data structure
* provided by \ p user_data .
*
* The complete suspension of all main windows leads to the termination of the
* GApplication .
*
* @ param action unused
* @ param parameter unused
* @ param user_data application_data structure
*/
2018-07-23 15:10:40 +02:00
static void app_quit ( GSimpleAction * action , GVariant * parameter , gpointer user_data )
{
2019-03-15 20:36:23 +01:00
struct application_data * const appdata = ( struct application_data * ) user_data ;
2018-12-15 00:03:40 +01:00
( void ) action ;
( void ) parameter ;
2019-03-15 20:02:03 +01:00
GList * list_iter ;
GdsRenderGui * gui ;
2018-12-11 00:06:27 +01:00
2019-03-15 23:16:39 +01:00
/* Dispose all GUIs */
2019-03-15 20:02:03 +01:00
for ( list_iter = appdata - > gui_list ; list_iter ! = NULL ; list_iter = g_list_next ( list_iter ) ) {
gui = RENDERER_GUI ( list_iter - > data ) ;
g_object_unref ( gui ) ;
}
g_list_free ( appdata - > gui_list ) ;
2019-03-15 20:36:23 +01:00
appdata - > gui_list = NULL ;
2018-07-23 15:10:40 +02:00
}
2019-03-30 19:51:56 +01:00
/**
* @ brief Callback for the ' About ' menu entry
*
* This function shows the about dialog .
*
* @ param action GSimpleAction , unused
* @ param parameter Unused .
* @ param user_data Unused
*/
2018-07-23 15:10:40 +02:00
static void app_about ( GSimpleAction * action , GVariant * parameter , gpointer user_data )
{
GtkBuilder * builder ;
GtkDialog * dialog ;
2019-03-21 22:22:35 +01:00
GdkPixbuf * logo_buf ;
GError * error = NULL ;
2019-03-16 16:24:39 +01:00
( void ) user_data ;
2018-12-15 00:03:40 +01:00
( void ) action ;
( void ) parameter ;
2019-08-26 00:05:45 +02:00
GString * comment_text ;
2019-10-18 19:29:55 +02:00
comment_text = g_string_new ( _ ( " gds-render is a free tool for rendering GDS2 layout files into vector graphics. " ) ) ;
g_string_append_printf ( comment_text , _ ( " \n \n Full git commit: %s " ) , _app_git_commit ) ;
2018-07-23 15:10:40 +02:00
2019-05-20 19:18:01 +02:00
builder = gtk_builder_new_from_resource ( " /gui/about.glade " ) ;
2018-07-23 15:10:40 +02:00
dialog = GTK_DIALOG ( gtk_builder_get_object ( builder , " about-dialog " ) ) ;
2019-03-15 20:02:03 +01:00
gtk_window_set_transient_for ( GTK_WINDOW ( dialog ) , NULL ) ;
2019-03-14 21:01:16 +01:00
gtk_about_dialog_set_version ( GTK_ABOUT_DIALOG ( dialog ) , _app_version_string ) ;
2019-08-26 00:05:45 +02:00
gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG ( dialog ) , comment_text - > str ) ;
g_string_free ( comment_text , TRUE ) ;
2019-03-21 22:22:35 +01:00
/* Load icon from resource */
2019-05-20 19:18:01 +02:00
logo_buf = gdk_pixbuf_new_from_resource_at_scale ( " /images/logo.svg " , 100 , 100 , TRUE , & error ) ;
2019-03-21 22:22:35 +01:00
if ( logo_buf ) {
/* Set logo */
gtk_about_dialog_set_logo ( GTK_ABOUT_DIALOG ( dialog ) , logo_buf ) ;
/* Pixbuf is now owned by about dialog. Unref */
g_object_unref ( logo_buf ) ;
} else if ( error ) {
2019-10-18 19:29:55 +02:00
fprintf ( stderr , _ ( " Logo could not be displayed: %s \n " ) , error - > message ) ;
2019-03-21 22:22:35 +01:00
g_error_free ( error ) ;
}
2018-07-23 15:10:40 +02:00
gtk_dialog_run ( dialog ) ;
2018-07-23 17:00:37 +02:00
gtk_widget_destroy ( GTK_WIDGET ( dialog ) ) ;
2018-07-23 15:10:40 +02:00
g_object_unref ( builder ) ;
}
2019-03-30 19:51:56 +01:00
/**
* @ brief Contains the application menu entries
*/
2019-08-25 21:51:35 +02:00
static const GActionEntry app_actions [ ] = {
2019-03-14 19:10:06 +01:00
{ " quit " , app_quit , NULL , NULL , NULL , { 0 } } ,
{ " about " , app_about , NULL , NULL , NULL , { 0 } }
2018-07-23 15:10:40 +02:00
} ;
2018-05-08 15:00:37 +02:00
2019-03-30 19:51:56 +01:00
/**
* @ brief Called when a GUI main window is closed
*
* The GdsRenderGui object associated with the closed main window
2019-10-03 11:57:16 +02:00
* is removed from the list of open GUIs ( \ p user_data ) and dereferenced .
2019-03-30 19:51:56 +01:00
*
* @ param gui The GUI instance the closed main window belongs to
* @ param user_data List of GUIs
*/
2019-03-16 16:09:29 +01:00
static void gui_window_closed_callback ( GdsRenderGui * gui , gpointer user_data )
{
GList * * gui_list = ( GList * * ) user_data ;
/* Dispose of Gui element */
* gui_list = g_list_remove ( * gui_list , gui ) ;
g_object_unref ( gui ) ;
}
2019-03-30 19:51:56 +01:00
/**
* @ brief Activation of the GUI
* @ param app The GApplication reference
* @ param user_data Used to store the individual GUI instances .
*/
2018-07-23 13:10:34 +02:00
static void gapp_activate ( GApplication * app , gpointer user_data )
2018-05-08 15:00:37 +02:00
{
2018-07-23 13:10:34 +02:00
GtkWindow * main_window ;
2019-03-15 20:02:03 +01:00
GdsRenderGui * gui ;
2019-03-07 20:14:44 +01:00
struct application_data * const appdata = ( struct application_data * ) user_data ;
2018-05-22 16:17:14 +02:00
2019-03-15 20:02:03 +01:00
gui = gds_render_gui_new ( ) ;
appdata - > gui_list = g_list_append ( appdata - > gui_list , gui ) ;
2019-03-16 16:09:29 +01:00
g_signal_connect ( gui , " window-closed " , G_CALLBACK ( gui_window_closed_callback ) , & appdata - > gui_list ) ;
2019-03-15 20:02:03 +01:00
main_window = gds_render_gui_get_main_window ( gui ) ;
2019-03-14 19:02:17 +01:00
gtk_application_add_window ( GTK_APPLICATION ( app ) , main_window ) ;
gtk_widget_show ( GTK_WIDGET ( main_window ) ) ;
2018-05-22 16:17:14 +02:00
}
2018-05-08 16:02:44 +02:00
2019-03-30 19:51:56 +01:00
/**
* @ brief Start the graphical interface .
*
* This function starts the GUI . If there ' s already a
* running instance of this program , a second window will be
* created in that instance and the second one is terminated .
*
* @ param argc
* @ param argv
* @ return
*/
2018-07-23 17:00:37 +02:00
static int start_gui ( int argc , char * * argv )
2018-05-08 15:00:37 +02:00
{
2018-07-23 13:10:34 +02:00
GtkApplication * gapp ;
2019-10-03 11:57:53 +02:00
GString * application_domain ;
2018-07-23 13:10:34 +02:00
int app_status ;
2019-03-26 19:57:19 +01:00
static struct application_data appdata = {
. gui_list = NULL
} ;
2018-07-23 15:10:40 +02:00
GMenu * menu ;
GMenu * m_quit ;
GMenu * m_about ;
2018-05-15 16:57:08 +02:00
2019-10-18 19:29:55 +02:00
bindtextdomain ( GETTEXT_PACKAGE , LOCALEDATADIR " /locale " ) ;
bind_textdomain_codeset ( GETTEXT_PACKAGE , " UTF-8 " ) ;
textdomain ( GETTEXT_PACKAGE ) ;
2019-10-03 11:57:53 +02:00
/*
* 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 ) ;
2018-07-23 15:10:40 +02:00
g_application_register ( G_APPLICATION ( gapp ) , NULL , NULL ) ;
2018-12-11 00:06:27 +01:00
g_signal_connect ( gapp , " activate " , G_CALLBACK ( gapp_activate ) , & appdata ) ;
2018-07-23 15:10:40 +02:00
2019-03-15 20:36:23 +01:00
if ( g_application_get_is_remote ( G_APPLICATION ( gapp ) ) = = TRUE ) {
g_application_activate ( G_APPLICATION ( gapp ) ) ;
2019-10-18 19:29:55 +02:00
printf ( _ ( " There is already an open instance. Will open second window in that instance. \n " ) ) ;
2019-03-15 20:36:23 +01:00
return 0 ;
}
2018-07-23 15:10:40 +02:00
menu = g_menu_new ( ) ;
m_quit = g_menu_new ( ) ;
m_about = g_menu_new ( ) ;
g_menu_append ( m_quit , " Quit " , " app.quit " ) ;
g_menu_append ( m_about , " About " , " app.about " ) ;
g_menu_append_section ( menu , NULL , G_MENU_MODEL ( m_about ) ) ;
g_menu_append_section ( menu , NULL , G_MENU_MODEL ( m_quit ) ) ;
2018-12-11 00:06:27 +01:00
g_action_map_add_action_entries ( G_ACTION_MAP ( gapp ) , app_actions ,
G_N_ELEMENTS ( app_actions ) , & appdata ) ;
2018-07-23 15:10:40 +02:00
gtk_application_set_app_menu ( GTK_APPLICATION ( gapp ) , G_MENU_MODEL ( menu ) ) ;
g_object_unref ( m_quit ) ;
g_object_unref ( m_about ) ;
g_object_unref ( menu ) ;
2018-05-17 21:46:14 +02:00
2018-12-11 00:06:27 +01:00
app_status = g_application_run ( G_APPLICATION ( gapp ) , argc , argv ) ;
g_object_unref ( gapp ) ;
2018-05-07 13:27:50 +02:00
2019-03-15 20:02:03 +01:00
g_list_free ( appdata . gui_list ) ;
2018-07-23 17:00:37 +02:00
return app_status ;
}
2019-03-30 19:51:56 +01:00
/**
* @ brief Print the application version string to stdout
*/
static void print_version ( void )
2019-03-11 10:36:02 +01:00
{
printf ( " This is gds-render, version: %s \n \n For a list of supported commands execute with --help option. \n " ,
2019-03-13 22:54:52 +01:00
_app_version_string ) ;
2019-03-11 10:36:02 +01:00
}
2019-03-30 19:51:56 +01:00
/**
* @ brief The " entry point " of the application
* @ param argc Number of command line parameters
* @ param argv Command line parameters
* @ return Execution status of the application
*/
2018-07-23 17:00:37 +02:00
int main ( int argc , char * * argv )
{
2019-03-15 17:57:59 +01:00
int i ;
2018-07-23 17:00:37 +02:00
GError * error = NULL ;
GOptionContext * context ;
2018-07-23 21:12:25 +02:00
gchar * gds_name ;
2019-06-21 21:41:31 +02:00
gchar * * output_paths = NULL ;
gchar * mappingname = NULL ;
gchar * cellname = NULL ;
gchar * * renderer_args = NULL ;
2019-06-19 20:47:19 +02:00
gboolean version = FALSE , pdf_standalone = FALSE , pdf_layers = FALSE ;
2018-12-15 00:05:34 +01:00
gchar * custom_library_path = NULL ;
2018-07-23 17:00:37 +02:00
int scale = 1000 ;
2019-03-11 10:36:02 +01:00
int app_status = 0 ;
2018-07-23 17:00:37 +02:00
2018-12-11 00:06:27 +01:00
GOptionEntry entries [ ] = {
2019-03-13 22:54:52 +01:00
{ " version " , ' v ' , 0 , G_OPTION_ARG_NONE , & version , " Print version " , NULL } ,
2019-06-21 21:41:31 +02:00
{ " renderer " , ' r ' , 0 , G_OPTION_ARG_STRING_ARRAY , & renderer_args , " Renderer to use. Can be used multiple times. " , " pdf|svg|tikz|ext " } ,
2019-03-13 22:54:52 +01:00
{ " scale " , ' s ' , 0 , G_OPTION_ARG_INT , & scale , " Divide output coordinates by <SCALE> " , " <SCALE> " } ,
2019-06-21 21:41:31 +02:00
{ " output-file " , ' o ' , 0 , G_OPTION_ARG_FILENAME_ARRAY , & output_paths , " Output file path. Can be used multiple times. " , " PATH " } ,
2019-03-13 22:54:52 +01:00
{ " mapping " , ' m ' , 0 , G_OPTION_ARG_FILENAME , & mappingname , " Path for Layer Mapping File " , " PATH " } ,
{ " cell " , ' c ' , 0 , G_OPTION_ARG_STRING , & cellname , " Cell to render " , " NAME " } ,
{ " tex-standalone " , ' a ' , 0 , G_OPTION_ARG_NONE , & pdf_standalone , " Create standalone PDF " , NULL } ,
{ " tex-layers " , ' l ' , 0 , G_OPTION_ARG_NONE , & pdf_layers , " Create PDF Layers (OCG) " , NULL } ,
{ " custom-render-lib " , ' P ' , 0 , G_OPTION_ARG_FILENAME , & custom_library_path , " Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function " , " PATH " } ,
{ NULL }
2018-07-23 17:00:37 +02:00
} ;
context = g_option_context_new ( " FILE - Convert GDS file <FILE> to graphic " ) ;
g_option_context_add_main_entries ( context , entries , NULL ) ;
g_option_context_add_group ( context , gtk_get_option_group ( TRUE ) ) ;
2018-12-11 00:06:27 +01:00
if ( ! g_option_context_parse ( context , & argc , & argv , & error ) ) {
g_print ( " Option parsing failed: %s \n " , error - > message ) ;
exit ( 1 ) ;
}
2018-07-23 17:00:37 +02:00
2019-03-11 10:36:02 +01:00
if ( version ) {
print_version ( ) ;
2019-03-13 22:54:52 +01:00
goto ret_status ;
2019-03-11 10:36:02 +01:00
}
2018-07-23 17:00:37 +02:00
if ( argc > = 2 ) {
2018-07-23 21:12:25 +02:00
if ( scale < 1 ) {
printf ( " Scale < 1 not allowed. Setting to 1 \n " ) ;
scale = 1 ;
}
/* Get gds name */
gds_name = argv [ 1 ] ;
2019-03-15 17:57:59 +01:00
/* Print out additional arguments as ignored */
for ( i = 2 ; i < argc ; i + + ) {
printf ( " Ignored argument: %s " , argv [ i ] ) ;
}
2019-06-22 01:21:26 +02:00
app_status =
command_line_convert_gds ( gds_name , cellname , renderer_args , output_paths , mappingname ,
custom_library_path , pdf_standalone , pdf_layers , scale ) ;
2018-07-23 21:12:25 +02:00
2018-07-23 17:00:37 +02:00
} else {
app_status = start_gui ( argc , argv ) ;
}
2019-03-11 10:36:02 +01:00
ret_status :
2019-06-21 21:41:31 +02:00
/* If necessary, free command line parameters */
if ( output_paths )
g_strfreev ( output_paths ) ;
if ( renderer_args )
g_strfreev ( renderer_args ) ;
if ( mappingname )
g_free ( mappingname ) ;
if ( cellname )
free ( cellname ) ;
2019-06-22 01:21:26 +02:00
if ( custom_library_path )
2019-06-21 21:41:31 +02:00
free ( custom_library_path ) ;
2018-07-23 13:10:34 +02:00
return app_status ;
2018-05-07 13:27:50 +02:00
}