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