diff --git a/gtk/compose/compose-parse.c b/gtk/compose/compose-parse.c index 55e9331f3e..e80b270453 100644 --- a/gtk/compose/compose-parse.c +++ b/gtk/compose/compose-parse.c @@ -26,7 +26,7 @@ main (int argc, char *argv[]) exit (1); } - table = gtk_compose_table_parse (argv[1]); + table = gtk_compose_table_parse (argv[1], NULL); if (!table) g_error ("Failed to parse %s", argv[1]); diff --git a/gtk/gtkcomposetable.c b/gtk/gtkcomposetable.c index 39ca2e3e92..c95b153e6f 100644 --- a/gtk/gtkcomposetable.c +++ b/gtk/gtkcomposetable.c @@ -83,6 +83,7 @@ typedef struct { GHashTable *sequences; GList *files; const char *compose_file; + gboolean found_include; } GtkComposeParser; static GtkComposeParser * @@ -95,6 +96,7 @@ parser_new (void) parser->sequences = g_hash_table_new_full (sequence_hash, sequence_equal, g_free, g_free); parser->files = NULL; parser->compose_file = NULL; + parser->found_include = FALSE; return parser; } @@ -357,6 +359,8 @@ parser_handle_include (GtkComposeParser *parser, const char *start, *end; char *path; + parser->found_include = TRUE; + p = line + strlen ("include "); while (g_ascii_isspace (*p)) @@ -719,7 +723,8 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table, } static GtkComposeTable * -gtk_compose_table_load_cache (const char *compose_file) +gtk_compose_table_load_cache (const char *compose_file, + gboolean *found_old_cache) { guint32 hash; char *path = NULL; @@ -740,6 +745,8 @@ gtk_compose_table_load_cache (const char *compose_file) char *char_data = NULL; GtkComposeTable *retval; + *found_old_cache = FALSE; + hash = g_str_hash (compose_file); if ((path = gtk_compose_hash_get_cache_path (hash)) == NULL) return NULL; @@ -780,8 +787,8 @@ gtk_compose_table_load_cache (const char *compose_file) GET_GUINT16 (version); if (version != GTK_COMPOSE_TABLE_VERSION) { - g_warning ("cache version is different %u != %u", - version, GTK_COMPOSE_TABLE_VERSION); + if (version < GTK_COMPOSE_TABLE_VERSION) + *found_old_cache = TRUE; goto out_load_cache; } @@ -993,15 +1000,15 @@ parser_get_compose_table (GtkComposeParser *parser) } static char * -canonicalize_filename (GtkComposeParser *parser, - const char *path) +canonicalize_filename (const char *parent_path, + const char *path) { GFile *file; char *retval; - if (path[0] != '/' && parser->compose_file) + if (path[0] != '/' && parent_path) { - GFile *orig = g_file_new_for_path (parser->compose_file); + GFile *orig = g_file_new_for_path (parent_path); GFile *parent = g_file_get_parent (orig); file = g_file_resolve_relative_path (parent, path); g_object_unref (parent); @@ -1029,7 +1036,7 @@ parser_parse_file (GtkComposeParser *parser, if (parser->compose_file == NULL) parser->compose_file = compose_file; - path = canonicalize_filename (parser, compose_file); + path = canonicalize_filename (parser->compose_file, compose_file); if (g_list_find_custom (parser->files, path, (GCompareFunc)strcmp)) { @@ -1046,7 +1053,8 @@ parser_parse_file (GtkComposeParser *parser, } GtkComposeTable * -gtk_compose_table_parse (const char *compose_file) +gtk_compose_table_parse (const char *compose_file, + gboolean *found_include) { GtkComposeParser *parser; GtkComposeTable *compose_table; @@ -1054,23 +1062,115 @@ gtk_compose_table_parse (const char *compose_file) parser = parser_new (); parser_parse_file (parser, compose_file); compose_table = parser_get_compose_table (parser); + if (found_include) + *found_include = parser->found_include; parser_free (parser); return compose_table; } +static const char *prefix = + "# GTK has rewritten this file to add the line:\n" + "\n" + "include \"%L\"\n" + "\n" + "# This is necessary to add your own Compose sequences\n" + "# in addition to the builtin sequences of GTK. If this\n" + "# is not what you want, just remove that line.\n" + "#\n" + "# A backup of the previous file contents has been made.\n" + "\n" + "\n"; + +static gboolean +rewrite_compose_file (const char *compose_file) +{ + char *path = NULL; + char *content = NULL; + gsize content_len; + GFile *file = NULL; + GOutputStream *stream = NULL; + gboolean ret = FALSE; + + path = canonicalize_filename (NULL, compose_file); + + if (!g_file_get_contents (path, &content, &content_len, NULL)) + goto out; + + file = g_file_new_for_path (path); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, TRUE, 0, NULL, NULL)); + + if (stream == NULL) + goto out; + + if (!g_output_stream_write (stream, prefix, strlen (prefix), NULL, NULL)) + goto out; + + if (!g_output_stream_write (stream, content, content_len, NULL, NULL)) + goto out; + + if (!g_output_stream_close (stream, NULL, NULL)) + goto out; + + ret = TRUE; + +out: + g_clear_object (&stream); + g_clear_object (&file); + g_clear_pointer (&path, g_free); + g_clear_pointer (&content, g_free); + + return ret; +} + GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file) { GtkComposeTable *compose_table; + gboolean found_old_cache = FALSE; + gboolean found_include = FALSE; g_assert (compose_file != NULL); - compose_table = gtk_compose_table_load_cache (compose_file); + compose_table = gtk_compose_table_load_cache (compose_file, &found_old_cache); if (compose_table != NULL) return compose_table; - compose_table = gtk_compose_table_parse (compose_file); +parse: + compose_table = gtk_compose_table_parse (compose_file, &found_include); + + /* This is where we apply heuristics to avoid breaking users existing configurations + * with the change to not always add the default sequences. + * + * If we find a cache that was generated before 4.4, and the Compose file + * does not have an include, and doesn't contain so many sequences that it + * is probably a copy of the system one, we take steps to keep things working, + * and thell the user about it. + */ + if (found_old_cache && !found_include && compose_table->n_sequences < 100) + { + if (rewrite_compose_file (compose_file)) + { + g_warning ("\nSince GTK 4.4, Compose files replace the builtin\n" + "compose sequences. To keep them and add your own\n" + "sequences on top, the line:\n" + "\n" + " include \"%%L\"\n" + "\n" + "has been added to the Compose file\n%s.\n", compose_file); + goto parse; + } + else + { + g_warning ("\nSince GTK 4.4, Compose files replace the builtin\n" + "compose sequences. To keep them and add your own\n" + "sequences on top, you need to add the line:\n" + "\n" + " include \"%%L\"\n" + "\n" + "to the Compose file\n%s.\n", compose_file); + } + } if (compose_table != NULL) gtk_compose_table_save_cache (compose_table); diff --git a/gtk/gtkcomposetable.h b/gtk/gtkcomposetable.h index 7a4c952f33..1398559a66 100644 --- a/gtk/gtkcomposetable.h +++ b/gtk/gtkcomposetable.h @@ -58,7 +58,8 @@ struct _GtkComposeTable }; GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file); -GtkComposeTable * gtk_compose_table_parse (const char *compose_file); +GtkComposeTable * gtk_compose_table_parse (const char *compose_file, + gboolean *found_include); GtkComposeTable * gtk_compose_table_new_with_data (const guint16 *data, int max_seq_len, int n_seqs); diff --git a/testsuite/gtk/composetable.c b/testsuite/gtk/composetable.c index 9c3a4a6142..1a77e5bc93 100644 --- a/testsuite/gtk/composetable.c +++ b/testsuite/gtk/composetable.c @@ -84,7 +84,7 @@ generate_output (const char *file) GtkComposeTable *table; char *output; - table = gtk_compose_table_parse (file); + table = gtk_compose_table_parse (file, NULL); output = gtk_compose_table_print (table); g_print ("%s", output); @@ -104,7 +104,7 @@ compose_table_compare (gconstpointer data) file = g_test_build_filename (G_TEST_DIST, "compose", basename, NULL); expected = g_strconcat (file, ".expected", NULL); - table = gtk_compose_table_parse (file); + table = gtk_compose_table_parse (file, NULL); output = gtk_compose_table_print (table); diff = diff_with_file (expected, output, -1, &error); @@ -131,7 +131,7 @@ compose_table_cycle (void) file = g_test_build_filename (G_TEST_DIST, "compose", "cycle", NULL); - table = gtk_compose_table_parse (file); + table = gtk_compose_table_parse (file, NULL); g_assert_nonnull (table); g_free (file); @@ -153,7 +153,7 @@ compose_table_nofile (void) file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "nofile", NULL); - table = gtk_compose_table_parse (file); + table = gtk_compose_table_parse (file, NULL); g_assert_nonnull (table); g_free (file); @@ -179,7 +179,7 @@ compose_table_match (void) file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "match", NULL); - table = gtk_compose_table_parse (file); + table = gtk_compose_table_parse (file, NULL); buffer[0] = GDK_KEY_Multi_key; buffer[1] = 0;