Imported Upstream version 0.1.0
[debian/lxdm.git] / src / greeter.c
1 /*
2 * lxdm-ui.c
3 *
4 * Copyright 2009 PCMan <pcman.tw@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 2 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 <gdk/gdkx.h>
28 #include <glib/gi18n.h>
29
30 #include "lang.h"
31
32 #define XSESSION_DIR "/usr/share/xsessions"
33 #define CONFIG_FILE "/etc/lxdm/lxdm.conf"
34
35 #ifndef LXDM_DATA_DIR
36 #define LXDM_DATA_DIR "/usr/share/lxdm"
37 #endif
38
39 static gboolean config_changed = FALSE;
40 static GKeyFile *config;
41 static GtkWidget* win;
42 static GtkWidget* prompt;
43 static GtkWidget* login_entry;
44 static GtkWidget* prompt;
45
46 static GtkWidget* sessions;
47 static GtkWidget* lang;
48
49 static GtkWidget* exit;
50
51 static GtkWidget* exit_menu;
52
53 static char* user = NULL;
54 static char* pass = NULL;
55 static char* session_exec = NULL;
56 static char* session_desktop_file = NULL;
57
58 static GdkPixbuf *bg_img = NULL;
59 static GdkColor bg_color = {0};
60
61 static GIOChannel *greeter_io;
62
63 static void do_reboot(void)
64 {
65 printf("reboot\n");
66 fflush(stdout);
67 }
68
69 static void do_shutdown(void)
70 {
71 printf("shutdown\n");
72 fflush(stdout);
73 }
74
75 static void on_screen_size_changed(GdkScreen* scr, GtkWindow* win)
76 {
77 gtk_window_resize(win, gdk_screen_get_width(scr), gdk_screen_get_height(scr));
78 }
79
80 static void on_entry_activate(GtkEntry* entry, gpointer user_data)
81 {
82 char* tmp;
83 if(!user)
84 {
85 user = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
86 gtk_entry_set_text(GTK_ENTRY(entry), "");
87 gtk_label_set_text(GTK_LABEL(prompt), _("Password:"));
88 if(strchr(user,' '))
89 {
90 g_free(user);
91 user=NULL;
92 return;
93 }
94 gtk_entry_set_visibility(entry, FALSE);
95 }
96 else
97 {
98 GtkTreeIter it;
99 char *session_lang="";
100
101 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(sessions), &it))
102 {
103 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(sessions));
104 gtk_tree_model_get(model, &it, 1, &session_exec, 2, &session_desktop_file, -1);
105 }
106 else
107 {
108 /* FIXME: fatal error */
109 }
110
111 pass = g_strdup( gtk_entry_get_text(entry));
112 if(strchr(pass,' '))
113 {
114 g_free(user);user=NULL;
115 g_free(pass);pass=NULL;
116 gtk_label_set_text(GTK_LABEL(prompt), _("User:"));
117 gtk_entry_set_text(GTK_ENTRY(entry), "");
118 gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
119 return;
120 }
121
122 if(lang && gtk_combo_box_get_active_iter(GTK_COMBO_BOX(lang), &it))
123 {
124 GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(lang));
125 gtk_tree_model_get(model, &it, 1, &session_lang, -1);
126 }
127
128 tmp = g_key_file_get_string(config, "base", "last_session", NULL);
129 if(g_strcmp0(tmp, session_desktop_file))
130 {
131 g_key_file_set_string(config, "base", "last_session", session_desktop_file);
132 config_changed = TRUE;
133 }
134 g_free(tmp);
135
136 tmp = g_key_file_get_string(config, "base", "last_lang", NULL);
137 if(g_strcmp0(tmp, session_lang))
138 {
139 g_key_file_set_string(config, "base", "last_lang", session_lang);
140 config_changed = TRUE;
141 }
142 g_free(tmp);
143
144 if(config_changed)
145 {
146 gsize len;
147 char* data=g_key_file_to_data(config, &len, NULL);
148 g_file_set_contents(CONFIG_FILE, data, len, NULL);
149 g_free(data);
150 }
151
152 printf("login user=%s pass=%s session=%s lang=%s\n",
153 user,pass,session_exec,session_lang);
154 fflush(stdout);
155
156 /* password check failed */
157 g_free(user);
158 user = NULL;
159 g_free(pass);
160 pass = NULL;
161
162 gtk_widget_hide(prompt);
163 gtk_widget_hide(GTK_WIDGET(entry));
164
165 gtk_label_set_text(GTK_LABEL(prompt), _("User:"));
166 gtk_entry_set_text(GTK_ENTRY(entry), "");
167 gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
168 }
169 }
170
171 static void load_sessions()
172 {
173 GtkListStore* list;
174 GtkTreeIter it, active_it = {0};
175 char* last;
176 char *path, *file_name, *name, *exec;
177 GKeyFile* kf;
178 GDir* dir = g_dir_open(XSESSION_DIR, 0, NULL);
179 if(!dir)
180 return;
181
182 last = g_key_file_get_string(config, "base", "last_session", NULL);
183
184 list = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
185 kf = g_key_file_new();
186 while((file_name = (char*)g_dir_read_name(dir))!=NULL)
187 {
188 path = g_build_filename(XSESSION_DIR, file_name, NULL);
189 if(g_key_file_load_from_file(kf, path, 0, NULL))
190 {
191 name = g_key_file_get_locale_string(kf, "Desktop Entry", "Name", NULL, NULL);
192 exec = g_key_file_get_string(kf, "Desktop Entry", "Exec", NULL);
193 if(!strcmp(name,"LXDE"))
194 gtk_list_store_prepend(list, &it);
195 else
196 gtk_list_store_append(list, &it);
197 gtk_list_store_set(list, &it, 0, name, 1, exec, 2, file_name, -1);
198
199 if(last && g_strcmp0(file_name, last)==0)
200 active_it = it;
201
202 g_free(name);
203 g_free(exec);
204 }
205 g_free(path);
206 }
207 g_dir_close(dir);
208 g_key_file_free(kf);
209
210 gtk_list_store_prepend(list, &it);
211 gtk_list_store_set(list, &it, 0, _("Default"), 1, "", 2, "__default__", -1);
212 if(last && g_strcmp0(file_name, last)==0)
213 active_it = it;
214
215 g_free(last);
216 gtk_combo_box_set_model(GTK_COMBO_BOX(sessions), GTK_TREE_MODEL(list));
217 gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX(sessions), 0);
218 if(active_it.stamp)
219 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(sessions), &active_it);
220 else
221 gtk_combo_box_set_active(GTK_COMBO_BOX(sessions),0);
222
223 g_object_unref(list);
224 }
225
226 static void load_lang_cb(void *arg,char *lang,char *desc)
227 {
228 GtkListStore* list=(GtkListStore*)arg;
229 GtkTreeIter it;
230 gtk_list_store_append(list, &it);
231 gtk_list_store_set(list, &it, 0, _(desc), 1, lang, -1);
232 }
233
234 static void load_langs()
235 {
236 GtkListStore* list;
237 char* lang_str;
238 int active = 0;
239
240 list = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
241 lang_str = g_key_file_get_string(config, "base", "last_lang", NULL);
242 active = lxdm_load_langs(list,load_lang_cb, lang_str);
243 g_free(lang_str);
244 gtk_combo_box_set_model(GTK_COMBO_BOX(lang), GTK_TREE_MODEL(list));
245 gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX(lang), 0);
246 gtk_combo_box_set_active(GTK_COMBO_BOX(lang), active < 0 ? 0 : active);
247 g_object_unref(list);
248 }
249
250 static void on_exit_clicked(GtkButton* exit_btn, gpointer user_data)
251 {
252 gtk_menu_popup(GTK_MENU(exit_menu), NULL, NULL, NULL, NULL,
253 0, gtk_get_current_event_time());
254 }
255
256 static void load_exit()
257 {
258 GtkWidget* item;
259 exit_menu = gtk_menu_new();
260 item = gtk_image_menu_item_new_with_mnemonic(_("_Reboot"));
261 g_signal_connect(item, "activate", G_CALLBACK(do_reboot), NULL);
262 gtk_menu_shell_append(GTK_MENU_SHELL(exit_menu), item);
263
264 item = gtk_image_menu_item_new_with_mnemonic(_("_Shutdown"));
265 g_signal_connect(item, "activate", G_CALLBACK(do_shutdown), NULL);
266 gtk_menu_shell_append(GTK_MENU_SHELL(exit_menu), item);
267
268 gtk_widget_show_all(exit_menu);
269 g_signal_connect(exit, "clicked", G_CALLBACK(on_exit_clicked), NULL);
270 }
271
272 static gboolean on_expose(GtkWidget* widget, GdkEventExpose* evt, gpointer user_data)
273 {
274 cairo_t *cr;
275
276 if(!GTK_WIDGET_REALIZED(widget))
277 return FALSE;
278 cr = gdk_cairo_create(widget->window);
279 if(bg_img)
280 {
281 cairo_matrix_t matrix;
282 double x=-0.5,y=-0.5,sx,sy;
283 cairo_get_matrix(cr,&matrix);
284 sx=(double)gdk_screen_width()/(double)gdk_pixbuf_get_width(bg_img);
285 sy=(double)gdk_screen_height()/(double)gdk_pixbuf_get_height(bg_img);
286 cairo_scale(cr,sx,sy);
287 gdk_cairo_set_source_pixbuf(cr,bg_img,x,y);
288 cairo_paint(cr);
289 cairo_set_matrix(cr,&matrix);
290 }
291 else
292 {
293 gdk_cairo_set_source_color(cr, &bg_color);
294 cairo_rectangle(cr,0,0,gdk_screen_width(),gdk_screen_height());
295 cairo_fill(cr);
296 }
297 cairo_destroy(cr);
298 return FALSE;
299 }
300
301 static gboolean on_combobox_entry_button_release(GtkWidget* w, GdkEventButton* evt, GtkComboBox* combo)
302 {
303 gboolean shown;
304 g_object_get(combo, "popup-shown", &shown, NULL);
305 if(shown)
306 gtk_combo_box_popdown(combo);
307 else
308 gtk_combo_box_popup(combo);
309 return FALSE;
310 }
311
312 static void fix_combobox_entry(GtkWidget* combo)
313 {
314 GtkWidget* edit = gtk_bin_get_child(combo);
315 gtk_editable_set_editable((GtkEditable*)edit, FALSE);
316 GTK_WIDGET_UNSET_FLAGS(edit, GTK_CAN_FOCUS);
317 g_signal_connect(edit, "button-release-event", G_CALLBACK(on_combobox_entry_button_release), combo);
318 }
319
320 static void create_win()
321 {
322 GtkBuilder* builder;
323 GdkScreen* scr;
324 builder = gtk_builder_new();
325 gtk_builder_add_from_file(builder, LXDM_DATA_DIR "/lxdm.glade", NULL);
326 win = (GtkWidget*)gtk_builder_get_object(builder, "lxdm");
327 GTK_WIDGET_SET_FLAGS(win, GTK_APP_PAINTABLE);
328 g_signal_connect(win, "expose-event", G_CALLBACK(on_expose), NULL);
329
330 scr = gtk_widget_get_screen(win);
331 g_signal_connect(scr, "size-changed", G_CALLBACK(on_screen_size_changed), win);
332
333 prompt = (GtkWidget*)gtk_builder_get_object(builder, "prompt");
334 login_entry = (GtkWidget*)gtk_builder_get_object(builder, "login_entry");
335
336 g_signal_connect(login_entry, "activate", G_CALLBACK(on_entry_activate), NULL);
337
338
339 sessions = (GtkWidget*)gtk_builder_get_object(builder, "sessions");
340 gtk_widget_set_name(sessions, "sessions");
341 fix_combobox_entry(sessions);
342 load_sessions();
343
344 if(g_key_file_get_integer(config,"display","bottom_pane",0)==0)
345 {
346 GtkWidget *w;
347 w=(GtkWidget*)gtk_builder_get_object(builder, "bottom_pane");
348 gtk_event_box_set_visible_window(w, FALSE);
349 }
350
351 if(g_key_file_get_integer(config,"display","lang",0)==0)
352 {
353 GtkWidget *w;
354 w=(GtkWidget*)gtk_builder_get_object(builder, "lang");
355 if(w) gtk_widget_hide(w);
356 w=(GtkWidget*)gtk_builder_get_object(builder, "label_lang");
357 if(w) gtk_widget_hide(w);
358 }
359 else
360 {
361 lang = (GtkWidget*)gtk_builder_get_object(builder, "lang");
362 gtk_widget_set_name(lang, "lang");
363 fix_combobox_entry(lang);
364 load_langs();
365 }
366
367 exit = (GtkWidget*)gtk_builder_get_object(builder, "exit");
368 load_exit();
369
370 g_object_unref(builder);
371
372 gtk_window_set_default_size(GTK_WINDOW(win), gdk_screen_get_width(scr), gdk_screen_get_height(scr));
373 gtk_window_present(GTK_WINDOW(win));
374 gtk_widget_realize(login_entry);
375 //gdk_keyboard_grab(login_entry->window,FALSE,GDK_CURRENT_TIME);
376 gtk_widget_grab_focus(login_entry);
377 }
378
379 int ui_set_bg(void)
380 {
381 char *bg;
382 char *style;
383 GdkWindow* root = gdk_get_default_root_window();
384 GdkCursor* cursor = gdk_cursor_new(GDK_LEFT_PTR);
385
386 gdk_window_set_cursor(root, cursor);
387
388 bg=g_key_file_get_string(config,"display","bg",0);
389 if(!bg)
390 bg=g_strdup("#222E45");
391 style=g_key_file_get_string(config,"display","bg_style",0);
392 if(bg && bg[0]!='#')
393 {
394 GdkPixbuf *pb=gdk_pixbuf_new_from_file(bg,0);
395 if(!pb)
396 {
397 g_free(bg);
398 bg=g_strdup("#222E45");
399 }
400 else
401 {
402 bg_img=pb;
403 }
404 }
405 if(bg && bg[0]=='#')
406 {
407 gdk_color_parse(bg,&bg_color);
408 //gdk_window_set_background(win,&screen);
409 }
410 g_free(bg);
411 g_free(style);
412 return 0;
413 }
414
415 static gboolean greeter_input(GIOChannel *source,GIOCondition condition,gpointer data)
416 {
417 GIOStatus ret;
418 char *str;
419
420 if(!(G_IO_IN&condition))
421 return FALSE;
422 ret=g_io_channel_read_line(source,&str,NULL,NULL,NULL);
423 if(ret!=G_IO_STATUS_NORMAL)
424 return FALSE;
425
426 if(!strncmp(str,"quit",4))
427 {
428 gtk_main_quit();
429 }
430 else if(!strncmp(str,"reset",5))
431 {
432 gtk_widget_show(prompt);
433 gtk_widget_show(login_entry);
434 gtk_widget_grab_focus(login_entry);
435 }
436 g_free(str);
437 return TRUE;
438 }
439
440 void listen_stdin(void)
441 {
442 greeter_io=g_io_channel_unix_new(0);
443 g_io_add_watch(greeter_io,G_IO_IN,greeter_input,NULL);
444 }
445
446 void ui_set_root_bg(void)
447 {
448 char *p;
449 GdkWindow *root=gdk_get_default_root_window();
450 GdkColor screen;
451 GdkPixbuf *bg_img=NULL;
452
453 /* get background */
454 p=g_key_file_get_string(config,"display","bg",0);
455 if(!p) p=g_strdup("#222E45");
456 if(p && p[0]!='#')
457 {
458 GdkPixbuf *pb=gdk_pixbuf_new_from_file(p,0);
459 if(!pb)
460 {
461 g_free(p);
462 p=g_strdup("#222E45");
463 }
464 else
465 {
466 bg_img=pb;
467 }
468 }
469 if(p && p[0]=='#')
470 {
471 gdk_color_parse(p,&screen);
472 }
473 g_free(p);
474
475 /* set background */
476 if(!bg_img)
477 {
478 GdkColormap *map = (GdkColormap*)gdk_window_get_colormap(root);
479 gdk_color_alloc(map, &screen);
480 gdk_window_set_background(root,&screen);
481 }
482 else
483 {
484 GdkPixmap *pix=NULL;
485 p=g_key_file_get_string(config,"display","bg_style",0);
486 if(!p || !strcmp(p,"stretch"))
487 {
488 GdkPixbuf *pb=gdk_pixbuf_scale_simple(bg_img,
489 gdk_screen_width(),
490 gdk_screen_height(),
491 GDK_INTERP_HYPER);
492 g_object_unref(bg_img);
493 bg_img=pb;
494 }
495 g_free(p);
496 gdk_pixbuf_render_pixmap_and_mask(bg_img,&pix,NULL,0);
497 g_object_unref(bg_img);
498 /* call x directly, because gdk will ref the pixmap */
499 //gdk_window_set_back_pixmap(root,pix,FALSE);
500 XSetWindowBackgroundPixmap(GDK_WINDOW_XDISPLAY(root),
501 GDK_WINDOW_XID(root), GDK_PIXMAP_XID(pix));
502 g_object_unref(pix);
503 }
504 gdk_window_clear(root);
505 }
506
507 int main(int arc,char *arg[])
508 {
509 gtk_set_locale();
510 bindtextdomain("lxdm","/usr/share/locale");
511 textdomain("lxdm");
512 config=g_key_file_new();
513 g_key_file_load_from_file(config, CONFIG_FILE, G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
514 gtk_init(&arc,&arg);
515 ui_set_bg();
516 ui_set_root_bg();
517
518 /* set gtk+ theme */
519 char* gtk_theme = g_key_file_get_string(config, "display", "gtk_theme", NULL);
520 if(gtk_theme)
521 {
522 GtkSettings* settings = gtk_settings_get_default();
523 g_object_set(settings, "gtk-theme-name", gtk_theme, NULL);
524 g_free(gtk_theme);
525 }
526
527 /* create the login window */
528 create_win();
529 listen_stdin();
530 gtk_main();
531
532 if(config_changed)
533 {
534 gsize len;
535 char* data=g_key_file_to_data(config, &len, NULL);
536 g_file_set_contents(CONFIG_FILE, data, len, NULL);
537 g_free(data);
538 }
539 g_key_file_free(config);
540
541 return 0;
542 }