1 /* dzl-shortcut-theme-save.c
2  *
3  * Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #define G_LOG_DOMAIN "dzl-shortcut-theme-save"
20 
21 #include "config.h"
22 
23 #include "shortcuts/dzl-shortcut-theme.h"
24 #include "shortcuts/dzl-shortcut-private.h"
25 
26 gboolean
dzl_shortcut_theme_save_to_stream(DzlShortcutTheme * self,GOutputStream * stream,GCancellable * cancellable,GError ** error)27 dzl_shortcut_theme_save_to_stream (DzlShortcutTheme  *self,
28                                    GOutputStream     *stream,
29                                    GCancellable      *cancellable,
30                                    GError           **error)
31 {
32   g_autoptr(GString) str = NULL;
33   DzlShortcutContext *context;
34   GHashTable *contexts;
35   GHashTableIter iter;
36   const gchar *name;
37   const gchar *parent;
38   const gchar *title;
39   const gchar *subtitle;
40 
41   g_return_val_if_fail (DZL_IS_SHORTCUT_THEME (self), FALSE);
42   g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
43   g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
44 
45   contexts = _dzl_shortcut_theme_get_contexts (self);
46 
47   str = g_string_new ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
48 
49   name = dzl_shortcut_theme_get_name (self);
50   parent = dzl_shortcut_theme_get_parent_name (self);
51   title = dzl_shortcut_theme_get_title (self);
52   subtitle = dzl_shortcut_theme_get_subtitle (self);
53 
54   if (parent != NULL && !g_str_equal (parent, "internal"))
55     g_string_append_printf (str, "<keytheme name=\"%s\" parent=\"%s\">\n", name, parent);
56   else
57     g_string_append_printf (str, "<keytheme name=\"%s\">\n", name);
58 
59   g_string_append_printf (str, "  <property name=\"title\" translatable=\"yes\">%s</property>\n", title ? title : "");
60   g_string_append_printf (str, "  <property name=\"subtitle\" translatable=\"yes\">%s</property>\n", subtitle ? subtitle : "");
61 
62   g_hash_table_iter_init (&iter, contexts);
63 
64   while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&context))
65     {
66       DzlShortcutChordTable *table;
67       DzlShortcutChordTableIter citer;
68       gboolean use_binding_sets = FALSE;
69       const DzlShortcutChord *chord = NULL;
70       DzlShortcutClosureChain *chain = NULL;
71 
72       table = _dzl_shortcut_context_get_table (context);
73       name = dzl_shortcut_context_get_name (context);
74       g_object_get (context, "use-binding-sets", &use_binding_sets, NULL);
75 
76       g_string_append_printf (str, "  <context name=\"%s\">\n", name);
77 
78       if (!use_binding_sets)
79         g_string_append (str, "    <property name=\"use-binding-sets\">false</property>\n");
80 
81       _dzl_shortcut_chord_table_iter_init (&citer, table);
82 
83       while (_dzl_shortcut_chord_table_iter_next (&citer, &chord, (gpointer *)&chain))
84         {
85           g_autofree gchar *accel = dzl_shortcut_chord_to_string (chord);
86 
87           if (chain == NULL || accel == NULL)
88             continue;
89 
90           g_string_append_printf (str, "    <shortcut accelerator=\"%s\">\n", accel);
91 
92           for (const GSList *node = &chain->node; node != NULL; node = node->next)
93             {
94               chain = node->data;
95 
96               if (chain->type == DZL_SHORTCUT_CLOSURE_ACTION)
97                 {
98                   if (chain->action.params == NULL)
99                     {
100                       g_string_append_printf (str, "      <action name=\"%s.%s\"/>\n",
101                                               chain->action.group, chain->action.name);
102                     }
103                   else
104                     {
105                       g_autofree gchar *fmt = g_variant_print (chain->action.params, FALSE);
106                       g_string_append_printf (str, "      <action name=\"%s.%s::%s\"/>\n",
107                                               chain->action.group, chain->action.name, fmt);
108                     }
109                 }
110               else if (chain->type == DZL_SHORTCUT_CLOSURE_SIGNAL)
111                 {
112                   if (chain->signal.detail)
113                     g_string_append_printf (str, "      <signal name=\"%s::%s\"",
114                                             chain->signal.name,
115                                             g_quark_to_string (chain->signal.detail));
116                   else
117                     g_string_append_printf (str, "      <signal name=\"%s\"",
118                                             chain->signal.name);
119 
120                   if (chain->signal.params == NULL || chain->signal.params->len == 0)
121                     {
122                       g_string_append (str, "/>\n");
123                       continue;
124                     }
125 
126                   g_string_append (str, ">\n");
127 
128                   for (guint j = 0; j < chain->signal.params->len; j++)
129                     {
130                       GValue *value = &g_array_index (chain->signal.params, GValue, j);
131 
132                       if (G_VALUE_HOLDS_STRING (value))
133                         {
134                           g_autofree gchar *escape = g_markup_escape_text (g_value_get_string (value), -1);
135 
136                           g_string_append_printf (str, "        <param>\"%s\"</param>\n", escape);
137                         }
138                       else
139                         {
140                           g_auto(GValue) translated = G_VALUE_INIT;
141 
142                           g_value_init (&translated, G_TYPE_STRING);
143                           g_value_transform (value, &translated);
144                           g_string_append_printf (str, "        <param>%s</param>\n", g_value_get_string (&translated));
145                         }
146                     }
147 
148                   g_string_append (str, "      </signal>\n");
149 
150                 }
151             }
152 
153           g_string_append (str, "    </shortcut>\n");
154         }
155 
156       g_string_append (str, "  </context>\n");
157     }
158 
159   g_string_append (str, "</keytheme>\n");
160 
161   return g_output_stream_write_all (stream, str->str, str->len, NULL, cancellable, error);
162 }
163 
164 gboolean
dzl_shortcut_theme_save_to_file(DzlShortcutTheme * self,GFile * file,GCancellable * cancellable,GError ** error)165 dzl_shortcut_theme_save_to_file (DzlShortcutTheme  *self,
166                                  GFile             *file,
167                                  GCancellable      *cancellable,
168                                  GError           **error)
169 {
170   g_autoptr(GFileOutputStream) stream = NULL;
171 
172   g_return_val_if_fail (DZL_IS_SHORTCUT_THEME (self), FALSE);
173   g_return_val_if_fail (G_IS_FILE (file), FALSE);
174   g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
175 
176   stream = g_file_replace (file,
177                            NULL,
178                            FALSE,
179                            G_FILE_CREATE_REPLACE_DESTINATION,
180                            cancellable,
181                            error);
182 
183   if (stream == NULL)
184     return FALSE;
185 
186   return dzl_shortcut_theme_save_to_stream (self, G_OUTPUT_STREAM (stream), cancellable, error);
187 }
188 
189 gboolean
dzl_shortcut_theme_save_to_path(DzlShortcutTheme * self,const gchar * path,GCancellable * cancellable,GError ** error)190 dzl_shortcut_theme_save_to_path (DzlShortcutTheme  *self,
191                                  const gchar       *path,
192                                  GCancellable      *cancellable,
193                                  GError           **error)
194 {
195   g_autoptr(GFile) file = NULL;
196 
197   g_return_val_if_fail (DZL_IS_SHORTCUT_THEME (self), FALSE);
198   g_return_val_if_fail (path != NULL, FALSE);
199   g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
200 
201   file = g_file_new_for_path (path);
202 
203   return dzl_shortcut_theme_save_to_file (self, file, cancellable, error);
204 }
205