astrognome/src/astrognome.c

632 lines
16 KiB
C
Raw Normal View History

2014-09-26 13:01:19 +00:00
/* astrognome.c - Utility functions and main() for Astrognome
*
* Copyright (C) 2014 Polonkai Gergely
*
* Astrognome is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* Astrognome 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 this software; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <glib.h>
#include <gtk/gtk.h>
2013-09-07 21:17:59 +00:00
#include <glib/gi18n.h>
2013-09-17 16:33:16 +00:00
#include <libxml/xmlversion.h>
#include <libxml/parser.h>
#include <libxslt/xslt.h>
2013-09-20 07:58:31 +00:00
#include <libxslt/transform.h>
#include <libexslt/exslt.h>
#include <libxml/xmlreader.h>
#include <swe-glib.h>
#include "config.h"
#include "ag-app.h"
#include "ag-window.h"
#ifndef LIBXML_READER_ENABLED
#error "You need to have libxml2 with XmlReader enabled"
#endif
GtkBuilder *builder;
GtkFileFilter *filter_all = NULL;
GtkFileFilter *filter_chart = NULL;
2014-08-07 22:41:43 +00:00
GtkFileFilter *filter_hor = NULL;
GtkFileFilter *filter_svg = NULL;
2014-09-17 09:22:49 +00:00
GtkFileFilter *filter_jpg = NULL;
2014-10-05 17:36:44 +00:00
GtkFileFilter *filter_png = NULL;
GtkTreeModel *country_list = NULL;
GtkTreeModel *city_list = NULL;
GHashTable *xinclude_positions;
gsize used_planets_count;
const char *moonStateName[] = {
2013-07-26 14:53:08 +00:00
"New Moon",
"Waxing Crescent Moon",
"Waxing Half Moon",
"Waxing Gibbous Moon",
"Full Moon",
"Waning Gibbous Moon",
"Waning Half Moon",
"Waning Crescent Moon",
"Dark Moon"
};
const GswePlanet used_planets[] = {
GSWE_PLANET_MC,
GSWE_PLANET_ASCENDANT,
GSWE_PLANET_VERTEX,
GSWE_PLANET_SUN,
GSWE_PLANET_MOON,
GSWE_PLANET_MERCURY,
GSWE_PLANET_VENUS,
GSWE_PLANET_MARS,
GSWE_PLANET_JUPITER,
GSWE_PLANET_SATURN,
GSWE_PLANET_URANUS,
GSWE_PLANET_NEPTUNE,
GSWE_PLANET_PLUTO,
GSWE_PLANET_MOON_NODE,
GSWE_PLANET_MOON_APOGEE,
GSWE_PLANET_CHIRON,
GSWE_PLANET_PHOLUS,
GSWE_PLANET_NESSUS,
GSWE_PLANET_CERES,
GSWE_PLANET_PALLAS,
GSWE_PLANET_JUNO,
GSWE_PLANET_VESTA,
GSWE_PLANET_CHARIKLO,
GSWE_PLANET_ASBOLUS
};
2013-09-17 12:42:45 +00:00
void
init_filters(void)
{
filter_all = gtk_file_filter_new();
gtk_file_filter_set_name(filter_all, _("All files"));
gtk_file_filter_add_pattern(filter_all, "*");
g_object_ref_sink(filter_all);
filter_chart = gtk_file_filter_new();
gtk_file_filter_set_name(filter_chart, _("Astrognome charts"));
gtk_file_filter_add_pattern(filter_chart, "*.agc");
g_object_ref_sink(filter_chart);
2014-08-07 22:41:43 +00:00
filter_hor = gtk_file_filter_new();
gtk_file_filter_set_name(filter_hor, _("Placidus charts"));
gtk_file_filter_add_pattern(filter_hor, "*.hor");
g_object_ref_sink(filter_hor);
filter_svg = gtk_file_filter_new();
gtk_file_filter_set_name(filter_svg, _("SVG image"));
gtk_file_filter_add_pattern(filter_svg, "*.svg");
g_object_ref_sink(filter_svg);
2014-09-17 09:22:49 +00:00
filter_jpg = gtk_file_filter_new();
gtk_file_filter_set_name(filter_jpg, _("JPEG image"));
gtk_file_filter_add_pattern(filter_jpg, "*.jpg");
gtk_file_filter_add_pattern(filter_jpg, "*.jpe");
gtk_file_filter_add_pattern(filter_jpg, "*.jpeg");
g_object_ref_sink(filter_jpg);
2014-10-05 17:36:44 +00:00
filter_png = gtk_file_filter_new();
gtk_file_filter_set_name(filter_png, _("PNG image"));
gtk_file_filter_add_pattern(filter_png, "*.png");
g_object_ref_sink(filter_png);
2013-09-17 12:42:45 +00:00
}
static int
xml_match_gresource(const char *uri)
{
if ((uri != NULL) && (!strncmp("gres://", uri, 7))) {
g_debug("Matched gres:// type link.");
return 1;
} else {
return 0;
}
}
static void *
xml_open_gresource(const gchar *uri)
{
gchar *path;
GBytes *res_location;
gsize *position;
if ((uri == NULL) || (strncmp("gres://", uri, 7))) {
return NULL;
}
path = g_strdup_printf("/eu/polonkai/gergely/Astrognome/%s", uri + 7);
g_debug("Opening gresource %s", path);
res_location = g_resources_lookup_data(
path,
G_RESOURCE_LOOKUP_FLAGS_NONE,
NULL
);
g_free(path);
if ((position = g_hash_table_lookup(
xinclude_positions,
res_location
)) == NULL) {
g_hash_table_insert(xinclude_positions, res_location, g_new0(gsize, 1));
} else {
g_warning("Reopening gres:// link?");
*position = 0;
}
return res_location;
}
static int
xml_close_gresource(void *context)
{
if (context == NULL) {
return -1;
}
g_debug("Closing gres:// link");
g_hash_table_remove(xinclude_positions, context);
g_bytes_unref((GBytes *)context);
return 0;
}
static int
xml_read_gresource(void *context, char *buffer, int len)
{
const gchar *data;
gsize max_length;
GBytes *data_holder = (GBytes *)context;
gsize *position;
if ((context == NULL) || (buffer == NULL) || (len < 0)) {
return -1;
}
data = g_bytes_get_data(data_holder, &max_length);
position = g_hash_table_lookup(xinclude_positions, data_holder);
if (position == NULL) {
g_warning("Trying to read non-opened gres:// link!");
return -1;
}
if (*position >= max_length) {
return 0;
}
if (len > max_length - *position) {
len = max_length - *position;
}
memcpy(buffer, data + *position, len);
g_debug("Read %d bytes", len);
*position += len;
return len;
}
const gchar *
ag_house_system_id_to_nick(GsweHouseSystem house_system)
{
GEnumClass *house_system_class;
GEnumValue *enum_value;
house_system_class = g_type_class_ref(GSWE_TYPE_HOUSE_SYSTEM);
enum_value = g_enum_get_value(house_system_class, house_system);
if (enum_value) {
return enum_value->value_nick;
}
return NULL;
}
GsweHouseSystem
ag_house_system_nick_to_id(const gchar *nick)
{
GEnumClass *house_system_class;
GEnumValue *enum_value;
house_system_class = g_type_class_ref(GSWE_TYPE_HOUSE_SYSTEM);
enum_value = g_enum_get_value_by_nick(house_system_class, nick);
if (enum_value) {
return enum_value->value;
}
return GSWE_HOUSE_SYSTEM_NONE;
}
const gchar *
ag_planet_id_to_nick(GswePlanet planet)
{
GEnumClass *planet_class;
GEnumValue *enum_value;
planet_class = g_type_class_ref(GSWE_TYPE_PLANET);
enum_value = g_enum_get_value(planet_class, planet);
if (enum_value) {
return enum_value->value_nick;
}
return NULL;
}
GswePlanet
ag_planet_nick_to_id(const gchar *nick)
{
GEnumClass *planet_class;
GEnumValue *enum_value;
planet_class = g_type_class_ref(GSWE_TYPE_PLANET);
enum_value = g_enum_get_value_by_nick(planet_class, nick);
if (enum_value) {
return enum_value->value;
}
return GSWE_PLANET_NONE;
}
const gchar *
ag_aspect_id_to_nick(GsweAspect aspect)
{
GEnumClass *aspect_class;
GEnumValue *enum_value;
aspect_class = g_type_class_ref(GSWE_TYPE_ASPECT);
enum_value = g_enum_get_value(aspect_class, aspect);
if (enum_value) {
return enum_value->value_nick;
}
return NULL;
}
GsweAspect
ag_aspect_nick_to_id(const gchar *nick)
{
GEnumClass *aspect_class;
GEnumValue *enum_value;
aspect_class = g_type_class_ref(GSWE_TYPE_ASPECT);
enum_value = g_enum_get_value_by_nick(aspect_class, nick);
if (enum_value) {
return enum_value->value;
}
return GSWE_ASPECT_NONE;
}
const gchar *
ag_antiscion_axis_id_to_nick(GsweAntiscionAxis antiscion_axis)
{
GEnumClass *antiscion_axis_class;
GEnumValue *enum_value;
antiscion_axis_class = g_type_class_ref(GSWE_TYPE_ANTISCION_AXIS);
enum_value = g_enum_get_value(antiscion_axis_class, antiscion_axis);
if (enum_value) {
return enum_value->value_nick;
}
return NULL;
}
GsweAntiscionAxis
ag_antiscion_axis_nick_to_id(const gchar *nick)
{
GEnumClass *antiscion_axis_class;
GEnumValue *enum_value;
antiscion_axis_class = g_type_class_ref(GSWE_TYPE_ANTISCION_AXIS);
enum_value = g_enum_get_value_by_nick(antiscion_axis_class, nick);
if (enum_value) {
return enum_value->value;
}
return GSWE_ANTISCION_AXIS_NONE;
}
/**
* ag_get_user_data_dir:
*
* Creates the astrognome data directory (~/.local/share/astrognome on XDG
* compatible systems) if necessary, and returns a GFile handle to it.
*
* Returns: (transfer full): a #GFile handle to the application data directory
* that must be freed with g_object_unref().
*/
GFile *
ag_get_user_data_dir(void)
{
GFile *user_data_dir = g_file_new_for_path(g_get_user_data_dir()),
*ag_data_dir = g_file_get_child(user_data_dir, "astrognome");
g_clear_object(&user_data_dir);
g_assert(ag_data_dir);
if (!g_file_query_exists(ag_data_dir, NULL)) {
gchar *path = g_file_get_path(ag_data_dir);
if (g_mkdir_with_parents(path, 0700) != 0) {
g_error(
"Data directory %s does not exist and cannot be created.",
path
);
}
g_free(path);
}
return ag_data_dir;
}
2013-09-07 21:17:59 +00:00
int
main(int argc, char *argv[])
{
gint status;
AgApp *app;
xmlTextReaderPtr reader;
AstrognomeOptions options;
GError *err = NULL;
GOptionEntry option_entries[] = {
{
"new-window", 'n',
0, G_OPTION_ARG_NONE,
&(options.new_window),
N_("Opens a new Astrognome window"),
NULL
},
{
"version", 'v',
0, G_OPTION_ARG_NONE,
&(options.version),
N_("Display version and exit"),
NULL
},
{
"quit", 'q',
0, G_OPTION_ARG_NONE,
&(options.quit),
N_("Quit any running Astrognome"),
NULL
},
{ NULL }
};
2013-09-17 07:32:16 +00:00
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
2013-09-17 07:32:16 +00:00
#endif
2013-09-07 21:17:59 +00:00
used_planets_count = sizeof(used_planets) / sizeof(GswePlanet);
2013-09-17 16:33:16 +00:00
LIBXML_TEST_VERSION;
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
xmlRegisterInputCallbacks(
xml_match_gresource,
xml_open_gresource,
xml_read_gresource,
xml_close_gresource
);
xsltInit();
2013-09-20 07:58:31 +00:00
xsltSetXIncludeDefault(1);
exsltRegisterAll();
2013-09-07 21:17:59 +00:00
gswe_init();
xinclude_positions = g_hash_table_new_full(
g_bytes_hash,
g_bytes_equal,
(GDestroyNotify)g_bytes_unref,
(GDestroyNotify)g_free
);
2013-09-07 21:17:59 +00:00
memset(&options, 0, sizeof(AstrognomeOptions));
if (!gtk_init_with_args(
&argc, &argv,
_("[FILE…]"
), option_entries, GETTEXT_PACKAGE, &err)) {
g_printerr("%s\n", err->message);
return EXIT_FAILURE;
}
if (options.version) {
g_print("%s\n", PACKAGE_STRING);
return EXIT_SUCCESS;
}
2013-09-17 12:42:45 +00:00
init_filters();
app = ag_app_new();
g_application_set_default(G_APPLICATION(app));
if (!g_application_register(G_APPLICATION(app), NULL, &err)) {
g_printerr(
"Couldn't register Astrognome instance: '%s'\n",
(err) ? err->message : ""
);
g_object_unref(app);
return EXIT_FAILURE;
}
if (g_application_get_is_remote(G_APPLICATION(app))) {
ag_app_run_action(app, TRUE, (const AstrognomeOptions *)&options);
g_object_unref(app);
return EXIT_SUCCESS;
}
2013-09-07 21:17:59 +00:00
country_list = GTK_TREE_MODEL(gtk_list_store_new(
AG_COUNTRY_COLCOUNT,
G_TYPE_STRING,
G_TYPE_STRING
));
city_list = GTK_TREE_MODEL(gtk_list_store_new(
AG_CITY_COLCOUNT,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE,
G_TYPE_DOUBLE
));
reader = xmlReaderForFile(PKGDATADIR "/geodata.xml", NULL, 0);
if (reader != NULL) {
int ret;
while ((ret = xmlTextReaderRead(reader)) == 1) {
gchar *name;
GtkTreeIter iter;
name = (gchar *)xmlTextReaderConstName(reader);
if (strcmp(name, "p") == 0) {
gchar *aname,
*acode,
*alat,
*alon,
*aalt,
*atzo,
*atzd,
*endptr;
gdouble lat,
lon,
alt,
tzo,
tzd;
aname = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "n"
);
acode = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "c"
);
alat = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "lat"
);
alon = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "lon"
);
aalt = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "alt"
);
atzo = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "tzo"
);
atzd = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "tzd"
);
lat = g_ascii_strtod(alat, &endptr);
lon = g_ascii_strtod(alon, &endptr);
if (*aalt == '\0') {
alt = DEFAULT_ALTITUDE;
} else {
alt = g_ascii_strtod(aalt, &endptr);
}
tzo = g_ascii_strtod(atzo, &endptr);
tzd = g_ascii_strtod(atzd, &endptr);
gtk_list_store_append(GTK_LIST_STORE(city_list), &iter);
gtk_list_store_set(
GTK_LIST_STORE(city_list), &iter,
AG_CITY_COUNTRY, acode,
AG_CITY_NAME, aname,
AG_CITY_LAT, lat,
AG_CITY_LONG, lon,
AG_CITY_ALT, alt,
AG_CITY_TZO, tzo,
AG_CITY_TZD, tzd,
-1
);
g_free(aname);
g_free(acode);
g_free(alat);
g_free(alon);
g_free(aalt);
g_free(atzo);
g_free(atzd);
} else if (strcmp(name, "c") == 0) {
gchar *aname,
*acode;
aname = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "n"
);
acode = (gchar *)xmlTextReaderGetAttribute(
reader,
BAD_CAST "c"
);
gtk_list_store_append(GTK_LIST_STORE(country_list), &iter);
gtk_list_store_set(
GTK_LIST_STORE(country_list), &iter,
AG_COUNTRY_CODE, acode,
AG_COUNTRY_NAME, aname,
-1
);
g_free(aname);
g_free(acode);
}
}
xmlFreeTextReader(reader);
if (ret != 0) {
g_error("Parse error in geodata.xml!");
}
} else {
g_error("Unable to open geodata.xml!");
}
2013-09-07 21:17:59 +00:00
status = g_application_run(G_APPLICATION(app), argc, argv);
g_hash_table_destroy(xinclude_positions);
2013-09-07 21:17:59 +00:00
g_object_unref(app);
2013-09-07 21:17:59 +00:00
return status;
}