]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/layout.c
simplify the patch based on Robert's feedback
[sojka/lightdm.git] / liblightdm-gobject / layout.c
1 /* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
2  *
3  * Copyright (C) 2010 Robert Ancell.
4  * Author: Robert Ancell <robert.ancell@canonical.com>
5  * 
6  * This library is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by the Free
8  * Software Foundation; either version 2 or version 3 of the License.
9  * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
10  */
11
12 #include <libxklavier/xklavier.h>
13
14 #include "lightdm/layout.h"
15
16 enum {
17     PROP_0,
18     PROP_NAME,
19     PROP_SHORT_DESCRIPTION,
20     PROP_DESCRIPTION
21 };
22
23 typedef struct
24 {
25     gchar *name;
26     gchar *short_description;
27     gchar *description;
28 } LightDMLayoutPrivate;
29
30 G_DEFINE_TYPE (LightDMLayout, lightdm_layout, G_TYPE_OBJECT);
31
32 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LAYOUT, LightDMLayoutPrivate)
33
34 static gboolean have_layouts = FALSE;
35 static Display *display = NULL;
36 static XklEngine *xkl_engine = NULL;
37 static XklConfigRec *xkl_config = NULL;
38 static GList *layouts = NULL;
39 static LightDMLayout *default_layout = NULL;
40
41 static gchar *
42 make_layout_string (const gchar *layout, const gchar *variant)
43 {
44     if (!layout || layout[0] == 0)
45         return NULL;
46     else if (!variant || variant[0] == 0)
47         return g_strdup (layout);
48     else
49         return g_strdup_printf ("%s\t%s", layout, variant);
50 }
51
52 static void
53 parse_layout_string (const gchar *name, gchar **layout, gchar **variant)
54 {
55     gchar **split;
56
57     *layout = NULL;
58     *variant = NULL;
59
60     if (!name)
61         return;
62
63     split = g_strsplit (name, "\t", 2);
64     if (split[0])
65     {
66         *layout = g_strdup (split[0]);
67         if (split[1])
68             *variant = g_strdup (split[1]);
69     }
70     g_strfreev (split);
71 }
72
73 static void
74 variant_cb (XklConfigRegistry *config,
75            const XklConfigItem *item,
76            gpointer data)
77 {
78     LightDMLayout *layout;
79     gchar *full_name;
80
81     full_name = make_layout_string (data, item->name);
82
83     layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", full_name, "short-description", item->short_description, "description", item->description, NULL);
84     layouts = g_list_append (layouts, layout);
85
86     g_free (full_name);
87 }
88
89 static void
90 layout_cb (XklConfigRegistry *config,
91            const XklConfigItem *item,
92            gpointer data)
93 {
94     LightDMLayout *layout;
95
96     layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", item->name, "short-description", item->short_description, "description", item->description, NULL);
97     layouts = g_list_append (layouts, layout);
98
99     xkl_config_registry_foreach_layout_variant (config, item->name, variant_cb, (gpointer) item->name);
100 }
101
102 /**
103  * lightdm_get_layouts:
104  *
105  * Get a list of keyboard layouts to present to the user.
106  *
107  * Return value: (element-type LightDMLayout) (transfer none): A list of #LightDMLayout that should be presented to the user.
108  **/
109 GList *
110 lightdm_get_layouts (void)
111 {
112     XklConfigRegistry *registry;
113
114     if (have_layouts)
115         return layouts;
116
117     display = XOpenDisplay (NULL);
118     if (display == NULL)
119         return NULL;
120     
121     xkl_engine = xkl_engine_get_instance (display);
122     xkl_config = xkl_config_rec_new ();
123     if (!xkl_config_rec_get_from_server (xkl_config, xkl_engine))
124         g_warning ("Failed to get Xkl configuration from server");
125
126     registry = xkl_config_registry_get_instance (xkl_engine);
127     xkl_config_registry_load (registry, FALSE);
128     xkl_config_registry_foreach_layout (registry, layout_cb, NULL);
129     g_object_unref (registry);
130
131     have_layouts = TRUE;
132
133     return layouts;
134 }
135
136 /**
137  * lightdm_set_layout:
138  * @layout: The layout to use
139  *
140  * Set the layout for this session.
141  **/
142 void
143 lightdm_set_layout (LightDMLayout *dmlayout)
144 {
145     XklConfigRec *config;
146     gchar *layout, *variant;
147
148     g_return_if_fail (dmlayout != NULL);
149
150     g_debug ("Setting keyboard layout to '%s'", lightdm_layout_get_name (dmlayout));
151
152     parse_layout_string (lightdm_layout_get_name (dmlayout), &layout, &variant);
153
154     config = xkl_config_rec_new ();
155     config->layouts = g_malloc (sizeof (gchar *) * 2);
156     config->variants = g_malloc (sizeof (gchar *) * 2);
157     config->model = g_strdup (xkl_config->model);
158     config->layouts[0] = layout;
159     config->layouts[1] = NULL;
160     config->variants[0] = variant;
161     config->variants[1] = NULL;
162     if (!xkl_config_rec_activate (config, xkl_engine))
163         g_warning ("Failed to activate XKL config");
164     g_object_unref (config);
165 }
166
167 /**
168  * lightdm_get_layout:
169  *
170  * Get the current keyboard layout.
171  *
172  * Return value: (transfer none): The currently active layout for this user.
173  **/
174 LightDMLayout *
175 lightdm_get_layout (void)
176 {
177     lightdm_get_layouts ();
178
179     if (layouts && xkl_config && !default_layout)
180     {
181         gchar *full_name;
182         GList *item;
183
184         full_name = make_layout_string (xkl_config->layouts ? xkl_config->layouts[0] : NULL,
185                                         xkl_config->variants ? xkl_config->variants[0] : NULL);
186
187         for (item = layouts; item; item = item->next)
188         {
189             LightDMLayout *iter_layout = (LightDMLayout *) item->data;
190             if (g_strcmp0 (lightdm_layout_get_name (iter_layout), full_name) == 0)
191             {
192                 default_layout = iter_layout;
193                 break;
194             }
195         }
196
197         g_free (full_name);
198     }
199
200     return default_layout;
201 }
202
203 /**
204  * lightdm_layout_get_name:
205  * @layout: A #LightDMLayout
206  * 
207  * Get the name of a layout.
208  * 
209  * Return value: The name of the layout
210  **/
211 const gchar *
212 lightdm_layout_get_name (LightDMLayout *layout)
213 {
214     g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
215     return GET_PRIVATE (layout)->name;
216 }
217
218 /**
219  * lightdm_layout_get_short_description:
220  * @layout: A #LightDMLayout
221  * 
222  * Get the short description of a layout.
223  *
224  * Return value: A short description of the layout
225  **/
226 const gchar *
227 lightdm_layout_get_short_description (LightDMLayout *layout)
228 {
229     g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
230     return GET_PRIVATE (layout)->short_description;
231 }
232
233 /**
234  * lightdm_layout_get_description:
235  * @layout: A #LightDMLayout
236  * 
237  * Get the long description of a layout.
238  * 
239  * Return value: A long description of the layout
240  **/
241 const gchar *
242 lightdm_layout_get_description (LightDMLayout *layout)
243 {
244     g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
245     return GET_PRIVATE (layout)->description;
246 }
247
248 static void
249 lightdm_layout_init (LightDMLayout *layout)
250 {
251 }
252
253 static void
254 lightdm_layout_set_property (GObject      *object,
255                          guint         prop_id,
256                          const GValue *value,
257                          GParamSpec   *pspec)
258 {
259     LightDMLayout *self = LIGHTDM_LAYOUT (object);
260     LightDMLayoutPrivate *priv = GET_PRIVATE (self);
261
262     switch (prop_id) {
263     case PROP_NAME:
264         g_free (priv->name);
265         priv->name = g_strdup (g_value_get_string (value));
266         break;
267     case PROP_SHORT_DESCRIPTION:
268         g_free (priv->short_description);
269         priv->short_description = g_strdup (g_value_get_string (value));
270         break;
271     case PROP_DESCRIPTION:
272         g_free (priv->description);
273         priv->description = g_strdup (g_value_get_string (value));
274         break;
275     default:
276         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277         break;
278     }
279 }
280
281 static void
282 lightdm_layout_get_property (GObject    *object,
283                          guint       prop_id,
284                          GValue     *value,
285                          GParamSpec *pspec)
286 {
287     LightDMLayout *self;
288
289     self = LIGHTDM_LAYOUT (object);
290
291     switch (prop_id) {
292     case PROP_NAME:
293         g_value_set_string (value, lightdm_layout_get_name (self));
294         break;
295     case PROP_SHORT_DESCRIPTION:
296         g_value_set_string (value, lightdm_layout_get_short_description (self));
297         break;
298     case PROP_DESCRIPTION:
299         g_value_set_string (value, lightdm_layout_get_description (self));
300         break;
301     default:
302         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
303         break;
304     }
305 }
306
307 static void
308 lightdm_layout_class_init (LightDMLayoutClass *klass)
309 {
310     GObjectClass *object_class = G_OBJECT_CLASS (klass);
311   
312     g_type_class_add_private (klass, sizeof (LightDMLayoutPrivate));
313
314     object_class->set_property = lightdm_layout_set_property;
315     object_class->get_property = lightdm_layout_get_property;
316
317     g_object_class_install_property (object_class,
318                                      PROP_NAME,
319                                      g_param_spec_string ("name",
320                                                           "name",
321                                                           "Name of the layout",
322                                                           NULL,
323                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
324     g_object_class_install_property (object_class,
325                                      PROP_SHORT_DESCRIPTION,
326                                      g_param_spec_string ("short-description",
327                                                           "short-description",
328                                                           "Short description of the layout",
329                                                           NULL,
330                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
331     g_object_class_install_property (object_class,
332                                      PROP_DESCRIPTION,
333                                      g_param_spec_string ("description",
334                                                           "description",
335                                                           "Long description of the layout",
336                                                           NULL,
337                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
338 }