Adding upstream version 0.4.1.
[debian/lxdm.git] / src / config.c
1 /*
2 * lxdm.c - main entry of lxdm
3 *
4 * Copyright 2009 dgod <dgod.osa@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <pwd.h>
31 #include <unistd.h>
32
33 #define CONFIG_UI_FILE LXDM_DATA_DIR"/config.ui"
34 //#define CONFIG_UI_FILE "../data/config.ui"
35 #define FACES_DIR "/usr/share/pixmaps/faces"
36
37 #define ROW_SPAN 6
38
39 GtkBuilder *builder;
40 GKeyFile *config;
41 int dirty;
42 char *user_name;
43 struct passwd *user;
44 gboolean root;
45 char *theme_name;
46 char *theme_dir;
47 char *ui_nobody;
48 GtkWidget *photo_popup;
49
50 void prepare_user(void)
51 {
52 root=getuid()==0;
53 if(!user_name)
54 {
55 if(!root)
56 user_name=getenv("USER");
57 if(!user_name)
58 user_name=getenv("SUDO_USER");
59 if(!user_name)
60 user_name=getenv("USER");
61 if(!user_name)
62 exit(1);
63 }
64 user=getpwnam(user_name);
65 if(!user)
66 {
67 exit(1);
68 }
69 }
70
71 void prepare_config(void)
72 {
73 config=g_key_file_new();
74 g_key_file_load_from_file(config,CONFIG_FILE,G_KEY_FILE_KEEP_COMMENTS,NULL);
75 theme_name=g_key_file_get_string(config,"display", "theme", NULL);
76 theme_dir=g_build_filename(LXDM_DATA_DIR "/themes", theme_name, NULL);
77
78 ui_nobody = g_build_filename(theme_dir, "nobody.png", NULL);
79 if( !g_file_test(ui_nobody, G_FILE_TEST_EXISTS) )
80 {
81 g_free(ui_nobody);
82 ui_nobody = NULL;
83 }
84 }
85
86 void popup_menu_below_button (GtkMenu *menu,
87 gint *x,
88 gint *y,
89 gboolean *push_in,
90 GtkWidget *button)
91 {
92 GtkRequisition menu_req;
93 GtkTextDirection direction;
94 GtkAllocation allocation;
95
96 #if GTK_CHECK_VERSION(3,0,0)
97 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req);
98 #else
99 gtk_widget_size_request(GTK_WIDGET(menu),&menu_req);
100 #endif
101
102 direction = gtk_widget_get_direction (button);
103
104 gdk_window_get_origin (gtk_widget_get_window (button), x, y);
105 gtk_widget_get_allocation (button, &allocation);
106 *x += allocation.x;
107 *y += allocation.y + allocation.height;
108
109 if (direction == GTK_TEXT_DIR_LTR)
110 *x += MAX (allocation.width - menu_req.width, 0);
111 else if (menu_req.width > allocation.width)
112 *x -= menu_req.width - allocation.width;
113
114 *push_in = TRUE;
115 }
116
117 static gboolean image_file_valid(const char *filename)
118 {
119 GdkPixbuf *pixbuf;
120 pixbuf=gdk_pixbuf_new_from_file(filename,NULL);
121 if(pixbuf) g_object_unref(pixbuf);
122 return pixbuf?TRUE:FALSE;
123 }
124
125 static void update_face_image(GtkWidget *w)
126 {
127 GdkPixbuf *pixbuf;
128 char *path;
129 path=g_build_filename(user->pw_dir,".face",NULL);
130 if(access(path,R_OK))
131 {
132 g_free(path);
133 if(ui_nobody)
134 pixbuf=gdk_pixbuf_new_from_file_at_scale(ui_nobody,48,48,FALSE,NULL);
135 if(!pixbuf)
136 pixbuf=gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
137 "avatar-default", 48,GTK_ICON_LOOKUP_FORCE_SIZE,NULL);
138 }
139 else
140 {
141 pixbuf=gdk_pixbuf_new_from_file_at_scale(path,48,48,FALSE,NULL);
142 g_free(path);
143 }
144 gtk_image_set_from_pixbuf(GTK_IMAGE(w),pixbuf);
145 g_object_unref(pixbuf);
146 }
147
148 static void set_face_file(const char *filename)
149 {
150 GtkWidget *w;
151 if(filename)
152 {
153 gchar *contents;
154 gsize length;
155 GdkPixbuf *pixbuf;
156 pixbuf=gdk_pixbuf_new_from_file(filename,NULL);
157 if(!pixbuf) return;
158 g_object_unref(pixbuf);
159 if(g_file_get_contents(filename,&contents,&length,NULL))
160 {
161 gchar *path=g_build_filename(user->pw_dir,".face",NULL);
162 g_file_set_contents(path,contents,length,NULL);
163 chown(path,user->pw_uid,user->pw_gid);
164 g_free(path);
165 }
166 }
167 else
168 {
169 gchar *path=g_build_filename(user->pw_dir,".face",NULL);
170 unlink(path);
171 g_free(path);
172 }
173 w=(GtkWidget*)gtk_builder_get_object(builder,"user-icon-image");
174 update_face_image(w);
175 }
176
177 static void stock_icon_selected (GtkMenuItem *menuitem)
178 {
179 const char *filename;
180 filename = g_object_get_data (G_OBJECT (menuitem), "filename");
181 set_face_file(filename);
182 }
183
184 static GtkWidget *menu_item_for_filename(const char *filename)
185 {
186 GtkWidget *image, *menuitem;
187 GFile *file;
188 GIcon *icon;
189
190 file = g_file_new_for_path (filename);
191 icon = g_file_icon_new (file);
192 g_object_unref (file);
193 image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
194 g_object_unref (icon);
195
196 menuitem = gtk_menu_item_new ();
197 gtk_container_add (GTK_CONTAINER (menuitem), image);
198 gtk_widget_show_all (menuitem);
199
200 g_object_set_data_full (G_OBJECT (menuitem), "filename",
201 g_strdup (filename), (GDestroyNotify) g_free);
202 g_signal_connect (G_OBJECT (menuitem), "activate",
203 G_CALLBACK (stock_icon_selected), NULL);
204
205 return menuitem;
206 }
207
208 static void
209 on_photo_popup_unmap (GtkWidget *popup_menu,
210 GtkWidget *popup_button)
211 {
212 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (popup_button), FALSE);
213 }
214
215 static void
216 update_preview (GtkFileChooser *chooser)
217 {
218 gchar *uri;
219
220 uri = gtk_file_chooser_get_preview_filename(chooser);
221
222 if (uri)
223 {
224 GdkPixbuf *pixbuf = NULL;
225 GtkWidget *preview;
226
227 preview = gtk_file_chooser_get_preview_widget (chooser);
228
229 pixbuf=gdk_pixbuf_new_from_file_at_scale(uri,96,96,TRUE,NULL);
230
231 gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser),
232 GTK_RESPONSE_ACCEPT,
233 (pixbuf != NULL));
234
235 if (pixbuf != NULL) {
236 gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
237 g_object_unref (pixbuf);
238 }
239 else {
240 gtk_image_set_from_stock (GTK_IMAGE (preview),
241 GTK_STOCK_DIALOG_QUESTION,
242 GTK_ICON_SIZE_DIALOG);
243 }
244
245 g_free (uri);
246 }
247
248 gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
249 }
250
251 static void file_icon_selected (GtkMenuItem *menuitem)
252 {
253 gint res;
254 GtkWidget *w;
255 const gchar *folder;
256 folder = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
257 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-image-chooser");
258 if(folder)
259 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(w),folder);
260 g_signal_connect(w,"update-preview",G_CALLBACK(update_preview),NULL);
261 res=gtk_dialog_run(GTK_DIALOG(w));
262 if(res==GTK_RESPONSE_ACCEPT)
263 {
264 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w));
265 set_face_file(filename);
266 g_free(filename);
267 }
268 gtk_widget_hide(GTK_WIDGET(w));
269 }
270
271 void on_user_icon_toggled(GtkToggleButton *togglebutton,gpointer user_data)
272 {
273 if(!photo_popup)
274 {
275 gboolean added_faces=TRUE;
276 GtkWidget *menu,*menuitem;
277 int x=0,y=0;
278 GDir *dir;
279 const char *face;
280 menu=gtk_menu_new();
281
282 dir=g_dir_open(FACES_DIR,0,NULL);
283 if(dir) while((face=g_dir_read_name(dir))!=NULL)
284 {
285 char *path=g_build_filename(FACES_DIR,face,NULL);
286 menuitem=menu_item_for_filename(path);
287 g_free(path);
288 gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
289 x, x + 1, y, y + 1);
290 gtk_widget_show (menuitem);
291 x++;
292 if (x >= ROW_SPAN - 1)
293 {
294 y++;
295 x = 0;
296 }
297 added_faces = TRUE;
298 }
299 if(added_faces)
300 {
301 GtkWidget *image = gtk_image_new_from_icon_name("avatar-default", GTK_ICON_SIZE_DIALOG);
302 menuitem = gtk_menu_item_new ();
303 gtk_container_add (GTK_CONTAINER (menuitem), image);
304 gtk_widget_show_all (menuitem);
305 gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
306 x, x + 1, y, y + 1);
307 g_signal_connect (G_OBJECT (menuitem), "activate",
308 G_CALLBACK (stock_icon_selected), NULL);
309 gtk_widget_show (menuitem);
310 y++;
311
312 menuitem = gtk_separator_menu_item_new ();
313 gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
314 0, ROW_SPAN - 1, y, y + 1);
315 gtk_widget_show (menuitem);
316 y++;
317 }
318 menuitem=gtk_menu_item_new_with_label(_("Browse for more pictures..."));
319 gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
320 0, ROW_SPAN - 1, y, y + 1);
321 g_signal_connect (G_OBJECT (menuitem), "activate",
322 G_CALLBACK (file_icon_selected), NULL);
323 gtk_widget_show (menuitem);
324 photo_popup=menu;
325
326 g_signal_connect (menu, "unmap",G_CALLBACK (on_photo_popup_unmap), togglebutton);
327 }
328 if(gtk_toggle_button_get_active(togglebutton))
329 {
330 gtk_menu_popup(GTK_MENU(photo_popup),NULL,NULL,
331 (GtkMenuPositionFunc) popup_menu_below_button,
332 GTK_WIDGET(togglebutton),
333 0, gtk_get_current_event_time ());
334 }
335 else
336 {
337 gtk_menu_popdown(GTK_MENU(photo_popup));
338 }
339 }
340
341 static gboolean
342 on_popup_button_button_pressed (GtkToggleButton *button,
343 GdkEventButton *event)
344 {
345 if (event->button == 1) {
346 if (!gtk_widget_get_visible (photo_popup)) {
347 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
348 } else {
349 gtk_menu_popdown (GTK_MENU (photo_popup));
350 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
351 }
352
353 return TRUE;
354 }
355
356 return FALSE;
357 }
358
359 void prepare_user_icon(GtkBuilder *builder)
360 {
361 GtkWidget *w;
362 w=(GtkWidget*)gtk_builder_get_object(builder,"user-icon-image");
363 update_face_image(w);
364 w=(GtkWidget*)gtk_builder_get_object(builder,"user-icon-button");
365 g_signal_connect(w,"toggled",G_CALLBACK(on_user_icon_toggled),NULL);
366 }
367
368 void prepare_user_name(GtkBuilder *builder)
369 {
370 GtkWidget *w;
371 w=(GtkWidget*)gtk_builder_get_object(builder,"user-name");
372 gtk_label_set_text(GTK_LABEL(w),user_name);
373 }
374
375 void on_user_autologin_toggled(GtkToggleButton *togglebutton,gpointer user_data)
376 {
377 if(gtk_toggle_button_get_active(togglebutton))
378 g_key_file_set_string(config,"base","autologin",user_name);
379 else
380 g_key_file_remove_key(config,"base","autologin",NULL);
381 dirty++;
382 }
383
384 void prepare_user_autologin(GtkBuilder *builder)
385 {
386 char *name;
387 GtkWidget *w;
388 w=(GtkWidget*)gtk_builder_get_object(builder,"user-autologin");
389 if(!root) gtk_widget_set_sensitive(w,FALSE);
390 g_signal_connect(w,"toggled",G_CALLBACK(on_user_autologin_toggled),NULL);
391 name=g_key_file_get_string(config,"base","autologin",NULL);
392 if(!name) return;
393 if(!strcmp(name,user_name))
394 {
395 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE);
396 }
397 g_free(name);
398 }
399
400 static void on_bg_type_toggled(void)
401 {
402 GtkWidget *w;
403 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-image-button");
404 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
405 {
406 char *s;
407 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-file");
408 s=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w));
409 if(s)
410 {
411 if(!image_file_valid(s))
412 {
413 g_free(s);
414 s=g_key_file_get_string(config,"display","bg",NULL);
415 if(s)
416 {
417 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w),s);
418 g_free(s);
419 }
420 return;
421 }
422 g_key_file_set_string(config,"display","bg",s);
423 g_free(s);
424 }
425 }
426 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,"lxdm-bg-color-button"))))
427 {
428 gchar *s;
429 GdkColor color;
430 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-color");
431 gtk_color_button_get_color(GTK_COLOR_BUTTON(w),&color);
432 s=gdk_color_to_string(&color);
433 g_key_file_set_string(config,"display","bg",s);
434 g_free(s);
435 }
436 else
437 {
438 g_key_file_remove_key(config,"display","bg",NULL);
439 }
440 dirty++;
441 }
442
443 void prepare_bg(GtkBuilder *builder)
444 {
445 char *s;
446 GtkWidget *w;
447 s=g_key_file_get_string(config,"display","bg",NULL);
448 if(!s)
449 {
450 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-default");
451 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE);
452 }
453 else if(s[0]=='#')
454 {
455 GdkColor color;
456 gdk_color_parse(s,&color);
457 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-color");
458 gtk_color_button_set_color(GTK_COLOR_BUTTON(w),&color);
459 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-color-button");
460 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE);
461 }
462 else
463 {
464 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-file");
465 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w),s);
466 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-image-button");
467 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE);
468 }
469 g_free(s);
470 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-image-button");
471 if(!root) gtk_widget_set_sensitive(w,FALSE);
472 g_signal_connect(w,"toggled",on_bg_type_toggled,NULL);
473 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-color-button");
474 if(!root) gtk_widget_set_sensitive(w,FALSE);
475 g_signal_connect(w,"toggled",on_bg_type_toggled,NULL);
476 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-file");
477 if(!root) gtk_widget_set_sensitive(w,FALSE);
478 g_signal_connect(w,"file-set",G_CALLBACK(on_bg_type_toggled),NULL);
479 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-color");
480 if(!root) gtk_widget_set_sensitive(w,FALSE);
481 g_signal_connect(w,"color-set",G_CALLBACK(on_bg_type_toggled),NULL);
482 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-bg-default");
483 if(!root) gtk_widget_set_sensitive(w,FALSE);
484 g_signal_connect(w,"toggled",on_bg_type_toggled,NULL);
485 }
486
487 static void on_show_lang_toggled(GtkToggleButton *button)
488 {
489 int val;
490 val=gtk_toggle_button_get_active(button);
491 g_key_file_set_integer(config,"display","lang",val);
492 dirty++;
493 }
494
495 static void prepare_show_lang(GtkBuilder *builder)
496 {
497 gint val;
498 GtkWidget *w;
499 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-show-lang");
500 val=g_key_file_get_integer(config,"display","lang",NULL);
501 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),val?TRUE:FALSE);
502 if(!root) gtk_widget_set_sensitive(w,FALSE);
503 g_signal_connect(w,"toggled",G_CALLBACK(on_show_lang_toggled),NULL);
504 }
505
506 static void on_show_keyboard_toggled(GtkToggleButton *button)
507 {
508 int val;
509 val=gtk_toggle_button_get_active(button);
510 g_key_file_set_integer(config,"display","keyboard",val);
511 dirty++;
512 }
513
514 static void prepare_show_keyboard(GtkBuilder *builder)
515 {
516 gint val;
517 GtkWidget *w;
518 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-show-keyboard");
519 val=g_key_file_get_integer(config,"display","keyboard",NULL);
520 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),val?TRUE:FALSE);
521 if(!root) gtk_widget_set_sensitive(w,FALSE);
522 g_signal_connect(w,"toggled",G_CALLBACK(on_show_keyboard_toggled),NULL);
523 }
524
525 static void on_show_userlist_toggled(GtkToggleButton *button)
526 {
527 int val;
528 val=gtk_toggle_button_get_active(button);
529 g_key_file_set_integer(config,"userlist","disable",!val);
530 dirty++;
531 }
532
533 static void prepare_show_userlist(GtkBuilder *builder)
534 {
535 gint val;
536 GtkWidget *w;
537 w=(GtkWidget*)gtk_builder_get_object(builder,"lxdm-user-list");
538 val=g_key_file_get_integer(config,"userlist","disable",NULL);
539 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),val?FALSE:TRUE);
540 if(!root) gtk_widget_set_sensitive(w,FALSE);
541 g_signal_connect(w,"toggled",G_CALLBACK(on_show_userlist_toggled),NULL);
542 }
543
544 GtkDialog *dialog_create(void)
545 {
546 GtkDialog *dlg;
547
548 builder=gtk_builder_new();
549 gtk_builder_add_from_file(builder,CONFIG_UI_FILE,NULL);
550 dlg=(GtkDialog*)gtk_builder_get_object(builder,"lxdm-config-dlg");
551 if(!dlg) return NULL;
552 prepare_user_icon(builder);
553 prepare_user_name(builder);
554 prepare_user_autologin(builder);
555 prepare_bg(builder);
556 prepare_show_lang(builder);
557 prepare_show_keyboard(builder);
558 prepare_show_userlist(builder);
559
560 return dlg;
561 }
562
563 static GOptionEntry entries[] =
564 {
565 { "user", 0, 0, G_OPTION_ARG_STRING, &user_name, "user name", NULL },
566 { NULL }
567 };
568
569 int main(int arc,char *arg[])
570 {
571 GError *error = NULL;
572 GOptionContext *context;
573 GtkDialog *dlg;
574
575 context = g_option_context_new ("- lxdm config");
576 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
577 g_option_context_add_group (context, gtk_get_option_group (TRUE));
578 if (!g_option_context_parse (context, &arc, &arg, &error))
579 {
580 g_print ("option parsing failed: %s\n", error->message);
581 exit (1);
582 }
583 prepare_user();
584
585 #if !GTK_CHECK_VERSION(3,0,0)
586 gtk_set_locale();
587 #endif
588 bindtextdomain("lxdm", "/usr/share/locale");
589 textdomain("lxdm");
590
591 gtk_init(&arc,&arg);
592 prepare_config();
593 dlg=dialog_create();
594 if(!dlg) exit(-1);
595 gtk_dialog_run(dlg);
596
597 if(dirty)
598 {
599 gsize length;
600 gchar *s=g_key_file_to_data(config,&length,NULL);
601 g_file_set_contents(CONFIG_FILE,s,length,NULL);
602 }
603
604 return 0;
605 }