Adding upstream version 0.4.1.
[debian/lxdm.git] / src / greeter-gdk.c
1 /*
2 * greeter-gdk.c - basic ui 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
23 #define XLIB_ILLEGAL_ACCESS
24
25 #include <gdk/gdk.h>
26 #include <gdk/gdkx.h>
27 #include <gdk/gdkkeysyms.h>
28 #ifdef ENABLE_GTK3
29 #include <gdk/gdkkeysyms-compat.h>
30 #endif
31 #include <X11/Xlib.h>
32
33 #include <string.h>
34 #include <poll.h>
35 #include <grp.h>
36 #include <unistd.h>
37 #include <ctype.h>
38 #include <signal.h>
39
40 #include <sys/wait.h>
41
42 #include "greeter-utils.h"
43
44 #define MAX_INPUT_CHARS 32
45 #define MAX_VISIBLE_CHARS 14
46
47 static Display *dpy;
48 static GdkWindow *root, *win;
49 static PangoLayout *layout;
50 static char user[MAX_INPUT_CHARS];
51 static char pass[MAX_INPUT_CHARS];
52 static int stage;
53 static GdkRectangle rc;
54 static GdkColor bg, border, hint, text, msg;
55
56 static char *message;
57
58 GKeyFile *config;
59 static GIOChannel *greeter_io;
60
61 static GMainLoop *greeter_loop;
62
63 static int get_text_layout(char *s, int *w, int *h)
64 {
65 pango_layout_set_text(layout, s, -1);
66 pango_layout_get_pixel_size(layout, w, h);
67 return 0;
68 }
69
70 static void draw_text(cairo_t *cr, double x, double y, char *text, GdkColor *color)
71 {
72 pango_layout_set_text(layout, text, -1);
73 cairo_move_to(cr, x, y);
74 gdk_cairo_set_source_color(cr, color);
75 pango_cairo_show_layout(cr, layout);
76 }
77
78 static void on_ui_expose(void)
79 {
80 cairo_t *cr = gdk_cairo_create(win);
81 char *p = (stage == 0) ? user : pass;
82 int len = strlen(p);
83 GdkColor *color=&text;
84
85 if(stage==2)
86 {
87 return;
88 }
89
90 gdk_cairo_set_source_color(cr, &bg);
91 cairo_rectangle(cr, rc.x, rc.y, rc.width, rc.height);
92 cairo_fill(cr);
93 gdk_cairo_set_source_color(cr, &border);
94 cairo_set_line_width(cr, 1.0);
95 cairo_stroke(cr);
96 cairo_rectangle(cr, rc.x, rc.y, rc.width, rc.height);
97
98 if( message )
99 {
100 color = &msg;
101 p = message;
102 }
103 else if( stage == 0 )
104 {
105 if( len < MAX_VISIBLE_CHARS )
106 p = user;
107 else
108 p = user + len - MAX_VISIBLE_CHARS;
109 if( len == 0 )
110 {
111 p = "Username";
112 color = &hint;
113 }
114 }
115 else if( stage >= 1 )
116 {
117 char spy[MAX_VISIBLE_CHARS + 1];
118 p = spy;
119 if( len < MAX_VISIBLE_CHARS )
120 {
121 memset(spy, '*', len);
122 p[len] = 0;
123 }
124 else
125 {
126 memset(spy, '*', MAX_VISIBLE_CHARS);
127 p[MAX_VISIBLE_CHARS] = 0;
128 }
129 if( len == 0 )
130 {
131 p = "Password";
132 color = &hint;
133 }
134 }
135 draw_text(cr, rc.x+3, rc.y+3, p, color);
136 cairo_destroy(cr);
137 }
138
139 static int ui_do_login(void)
140 {
141 if( stage != 2 )
142 return -1;
143
144 if( !strcmp(user, "reboot") )
145 printf("reboot\n");
146 else if(!strcmp(user, "shutdown"))
147 printf("shutdown\n");
148 else
149 {
150 char *temp;
151 temp=(char*)g_base64_encode((guchar*)pass,strlen(pass)+1);
152 printf("login user=%s pass=%s\n",user, temp);
153 g_free(temp);
154 }
155 return 0;
156 }
157
158 static void on_ui_key(GdkEventKey *event)
159 {
160 char *p;
161 int len;
162 int key;
163
164 if( stage != 0 && stage != 1 )
165 return;
166 message = 0;
167 key = event->keyval;
168 p = (stage == 0) ? user : pass;
169 len = strlen(p);
170 if( key == GDK_Escape )
171 {
172 user[0] = 0;
173 pass[0] = 0;
174 stage = 0;
175 }
176 else if( key == GDK_BackSpace )
177 {
178 if( len > 0 )
179 p[--len] = 0;
180 }
181 else if( key == GDK_Return )
182 {
183 if( stage == 0 && len == 0 )
184 return;
185 stage++;
186 if( stage == 1 )
187 if( !strcmp(user, "reboot") || !strcmp(user, "shutdown") )
188 stage = 2;
189 }
190 else if( key >= 0x20 && key <= 0x7e )
191 if( len < MAX_INPUT_CHARS - 1 )
192 {
193 p[len++] = key;
194 p[len] = 0;
195 }
196 if(stage==2)
197 {
198 #ifndef ENABLE_GTK3
199 gdk_window_clear(win);
200 #else
201 cairo_t *cr=gdk_cairo_create(win);
202 cairo_pattern_t *pattern=gdk_window_get_background_pattern(win);
203 cairo_set_source(cr,pattern);
204 cairo_paint(cr);
205 cairo_destroy(cr);
206 #endif
207 }
208 else
209 {
210 on_ui_expose();
211 }
212 if( stage == 2 )
213 {
214 ui_do_login();
215 if( stage != 2 )
216 on_ui_expose();
217 }
218 }
219
220 void ui_event_cb(GdkEvent *event, gpointer data)
221 {
222 if(stage == 2)
223 return;
224 if(event->type == GDK_KEY_PRESS)
225 {
226 on_ui_key((GdkEventKey*)event);
227 }
228 else if(event->type == GDK_EXPOSE)
229 {
230 on_ui_expose();
231 }
232 }
233
234 static void on_screen_size_changed(GdkScreen *screen,GdkWindow *window)
235 {
236 GdkRectangle dest;
237 gdk_window_hide(window);
238 ui_get_geometry(window,&dest);
239 rc.x = dest.x + (dest.width - rc.width) / 2;
240 rc.y = dest.y + (dest.height - rc.height) / 2;
241 gdk_window_move_resize(window,dest.x,dest.y,dest.width,dest.height);
242 ui_set_bg(window,config);
243 gdk_window_show(window);
244 }
245
246 void ui_prepare(void)
247 {
248 cairo_t *cr;
249 PangoFontDescription *desc;
250 char *p;
251 int w, h;
252
253 /* get current display */
254 dpy = gdk_x11_get_default_xdisplay();
255 root = gdk_get_default_root_window();
256
257 user[0] = pass[0] = 0;
258 stage = 0;
259
260 p = g_key_file_get_string(config, "input", "border", 0);
261 if( !p )
262 p = g_strdup("#CBCAE6");
263 gdk_color_parse(p, &border);
264 g_free(p);
265
266 p = g_key_file_get_string(config, "input", "bg", 0);
267 if( !p )
268 p = g_strdup("#ffffff");
269 gdk_color_parse(p, &bg);
270 g_free(p);
271
272 p = g_key_file_get_string(config, "input", "hint", 0);
273 if( !p )
274 p = g_strdup("#CBCAE6");
275 gdk_color_parse(p, &hint);
276 g_free(p);
277
278 p = g_key_file_get_string(config, "input", "text", 0);
279 if( !p )
280 p = g_strdup("#000000");
281 gdk_color_parse(p, &text);
282 g_free(p);
283
284 p = g_key_file_get_string(config, "input", "msg", 0);
285 if( !p )
286 p = g_strdup("#ff0000");
287 gdk_color_parse(p, &msg);
288 g_free(p);
289
290 /* create the window */
291 if( !win )
292 {
293 GdkScreen *scr;
294 GdkWindowAttr attr;
295 int mask = 0;
296 memset( &attr, 0, sizeof(attr) );
297 attr.window_type = GDK_WINDOW_TOPLEVEL;
298 attr.event_mask = GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK;
299 attr.wclass = GDK_INPUT_OUTPUT;
300 win = gdk_window_new(root, &attr, mask);
301 gdk_window_set_decorations(win,0);
302 gdk_window_set_title(win,"lxdm-greter-gdk");
303
304 scr=gdk_screen_get_default();
305 g_signal_connect(scr, "size-changed", G_CALLBACK(on_screen_size_changed), win);
306 }
307
308 /* create the font */
309 if( layout )
310 {
311 g_object_unref(layout);
312 layout = NULL;
313 }
314 cr = gdk_cairo_create(win);
315 layout = pango_cairo_create_layout(cr);
316 cairo_destroy(cr);
317 p = g_key_file_get_string(config, "input", "font", 0);
318 if( !p ) p = g_strdup("Sans 14");
319 desc = pango_font_description_from_string(p);
320 pango_layout_set_font_description(layout, desc);
321 pango_font_description_free(desc);
322 g_free(p);
323
324 /* set window size */
325 if( layout )
326 {
327 char temp[MAX_VISIBLE_CHARS + 1 + 1];
328 GdkRectangle dest;
329 ui_get_geometry(win,&dest);
330 memset( temp, 'A', sizeof(temp) );
331 temp[sizeof(temp) - 1] = 0;
332 get_text_layout(temp, &w, &h);
333 rc.width = w + 6; rc.height = h + 6;
334 rc.x = dest.x + (dest.width - rc.width) / 2;
335 rc.y = dest.y + (dest.height - rc.height) / 2;
336 gdk_window_move_resize(win, dest.x, dest.y, dest.width, dest.height);
337 }
338
339 /* connect event */
340 gdk_window_set_events(win, GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK);
341
342 /* draw the first time */
343 ui_set_bg(win,config);
344 gdk_window_show(win);
345 ui_set_focus(win);
346 }
347
348 static gboolean on_lxdm_command(GIOChannel *source, GIOCondition condition, gpointer data)
349 {
350 GIOStatus ret;
351 char *str;
352
353 if( !(G_IO_IN & condition) )
354 return FALSE;
355 ret = g_io_channel_read_line(source, &str, NULL, NULL, NULL);
356 if( ret != G_IO_STATUS_NORMAL )
357 return FALSE;
358
359 if( !strncmp(str, "quit", 4) || !strncmp(str, "exit",4))
360 g_main_loop_quit(greeter_loop);
361 else if( !strncmp(str, "reset", 5) )
362 {
363 user[0] = pass[0] = 0;
364 stage = 0;
365 on_ui_expose();
366 }
367 g_free(str);
368 return TRUE;
369 }
370
371 int main(void)
372 {
373 greeter_loop = g_main_loop_new(NULL, 0);
374
375 config = g_key_file_new();
376 g_key_file_load_from_file(config, CONFIG_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL);
377
378 greeter_io = g_io_channel_unix_new(0);
379 g_io_add_watch(greeter_io, G_IO_IN, on_lxdm_command, NULL);
380
381 setvbuf(stdout, NULL, _IOLBF, 0 );
382
383 gdk_init(NULL,NULL);
384
385 ui_prepare();
386 ui_add_cursor();
387 gdk_event_handler_set(ui_event_cb, 0, 0);
388 g_main_loop_run(greeter_loop);
389 return 0;
390 }