gdmlogin.c 117 KB
Newer Older
1
/* GDM - The GNOME Display Manager
2
 * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
Martin Peterson's avatar
Martin Peterson committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <config.h>
20

21 22
#include <libgnome/libgnome.h>
#include <libgnomeui/libgnomeui.h>
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
23
#include <math.h>
Martin Peterson's avatar
Martin Peterson committed
24 25 26 27
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
28 29
#include <sys/types.h>
#include <sys/wait.h>
30
#include <fcntl.h>
Martin Peterson's avatar
Martin Peterson committed
31 32 33 34 35
#include <unistd.h>
#include <syslog.h>
#include <ctype.h>
#include <signal.h>
#include <dirent.h>
36
#include <locale.h>
Martin Peterson's avatar
Martin Peterson committed
37
#include <gdk/gdkx.h>
38 39
#include <X11/X.h>
#include <X11/Xlib.h>
40
#include <X11/XKBlib.h>
Martin Peterson's avatar
Martin Peterson committed
41
#include <pwd.h>
42
#include <sys/utsname.h>
43 44

#if HAVE_PAM
45
#include <security/pam_appl.h>
46 47 48 49
#define PW_ENTRY_SIZE PAM_MAX_RESP_SIZE
#else
#define PW_ENTRY_SIZE GDM_MAX_PASS
#endif
50 51 52

#include <viciousui.h>

Martin Peterson's avatar
Martin Peterson committed
53
#include "gdm.h"
54 55
#include "gdmuser.h"
#include "gdmcommon.h"
56
#include "gdmsession.h"
57
#include "gdmwm.h"
58
#include "gdmlanguages.h"
59
#include "gdmcommon.h"
60
#include "misc.h"
Martin Peterson's avatar
Martin Peterson committed
61

62 63 64
/* set the DOING_GDM_DEVELOPMENT env variable if you aren't running
 * within the protocol */
static gboolean DOING_GDM_DEVELOPMENT = FALSE;
65
static char *greeter_DefaultWelcome_key = GDM_KEY_DEFAULT_WELCOME;
66
static char *greeter_Welcome_key = GDM_KEY_WELCOME;
67

George Lebl's avatar
George Lebl committed
68 69
#define LAST_SESSION "Last"
#define LAST_LANGUAGE "Last"
70
#define DEFAULT_LANGUAGE "Default"
George Lebl's avatar
George Lebl committed
71
#define SESSION_NAME "SessionName"
72
#define GTK_KEY "gtk-2.0"
George Lebl's avatar
George Lebl committed
73

74 75 76 77 78 79
enum {
	GREETER_ULIST_ICON_COLUMN = 0,
	GREETER_ULIST_LABEL_COLUMN,
	GREETER_ULIST_LOGIN_COLUMN
};

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
80 81 82 83
static gboolean GdmBrowser;
static gboolean GdmDebug;
static gboolean GdmQuiver;
static gboolean GdmSystemMenu;
84
static gboolean GdmSystemMenuReal;
85 86
static gboolean GdmChooserButton;
static gboolean GdmChooserButtonReal;
87 88 89
static gchar *GdmHalt;
static gchar *GdmReboot;
static gchar *GdmSuspend;
90
static gboolean GdmConfigAvailable;
91
static gboolean GdmConfigAvailableReal;
92
static gchar *GdmConfigurator;
93
static gint GdmXineramaScreen;
94
static gchar *GdmLogo;
95
static gboolean GdmDefaultWelcome;
96
static gchar *GdmWelcome;
97
static gchar *GdmBackgroundProg;
98
static gboolean GdmRunBackgroundProgAlways;
99 100 101
static gint GdmBackgroundProgInitialDelay;
static gboolean GdmRestartBackgroundProgram;
static gint GdmBackgroundProgRestartDelay;
102 103
static gchar *GdmBackgroundImage;
static gchar *GdmBackgroundColor;
104
static gboolean GdmBackgroundScaleToFit;
105
static gboolean GdmBackgroundRemoteOnlyColor;
106 107 108 109 110 111
static int GdmBackgroundType;
enum {
	GDM_BACKGROUND_NONE = 0,
	GDM_BACKGROUND_IMAGE = 1,
	GDM_BACKGROUND_COLOR = 2
};
112 113 114 115 116
static gchar *GdmGtkRC;
static gchar *GdmSessionDir;
static gchar *GdmLocaleFile;
static gchar *GdmGlobalFaceDir;
static gchar *GdmDefaultFace;
117
static gboolean GdmTimedLoginEnable;
118
static gboolean GdmUse24Clock;
119
static gchar *GdmTimedLogin;
120
static gint GdmTimedLoginDelay;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
121 122
static gboolean GdmLockPosition;
static gboolean GdmSetPosition;
123 124
static gint GdmPositionX;
static gint GdmPositionY;
125
static gboolean GdmTitleBar;
126

127 128 129 130
static gboolean GdmAllowGtkThemeChange;
static char *GdmGtkThemesToAllow;
static char *GdmGtkTheme;

131 132
static gboolean GdmShowGnomeFailsafeSession;
static gboolean GdmShowXtermFailsafeSession;
133
static gboolean GdmShowLastSession;
134

135
static gboolean GdmUseCirclesInEntry;
136
static gboolean GdmUseInvisibleInEntry;
137
static gint GdmFlexiReapDelayMinutes;
138

139
/* FIXME: Should move everything to externs and move reading to gdmcommon.c */
140
gchar *GdmDefaultSession;
141 142
gchar *GdmInfoMsgFile;
gchar *GdmInfoMsgFont;
143 144
gboolean GdmSoundOnLoginReady;
gchar *GdmSoundOnLoginReadyFile;
145 146 147 148 149 150 151 152 153
gchar *GdmSoundProgram;
gint  GdmIconMaxHeight;
gint  GdmIconMaxWidth;
int GdmMinimalUID;
gchar *GdmInclude = NULL;
gchar *GdmExclude = NULL;
gboolean GdmIncludeAll;
gboolean GdmAllowRoot;
gboolean GdmAllowRemoteRoot;
154

155
static GtkWidget *login;
156 157 158
static GtkWidget *logo_frame = NULL;
static GtkWidget *logo_image = NULL;
static GtkWidget *table = NULL;
159
static GtkWidget *welcome;
160
static GtkWidget *label;
161 162
static GtkWidget *icon_button = NULL;
static GtkWidget *title_box = NULL;
163
static GtkWidget *clock_label = NULL;
164
static GtkWidget *entry;
165
static GtkWidget *ok_button;
166
static GtkWidget *cancel_button;
167
static GtkWidget *msg;
168
static GtkWidget *auto_timed_msg;
169 170
static GtkWidget *err_box;
static guint err_box_clear_handler = 0;
171
static gboolean require_quarter = FALSE;
172
static GtkWidget *icon_win = NULL;
173 174
static GtkWidget *sessmenu;
static GtkWidget *langmenu;
George Lebl's avatar
George Lebl committed
175
static GtkTooltips *tooltips;
176
GHashTable *sessnames;
177

178
static gboolean login_is_local = FALSE;
179
static gboolean used_defaults = FALSE;
180

181 182
static GtkWidget *browser;
static GtkTreeModel *browser_model;
183
static GdkPixbuf *defface;
Martin Peterson's avatar
Martin Peterson committed
184 185

/* Eew. Loads of global vars. It's hard to be event controlled while maintaining state */
186
static GList *sessions = NULL;
187 188
static GSList *languages = NULL;
static GList *users = NULL;
189
static GList *users_string = NULL;
190
static gint size_of_users = 0;
191 192

static gchar *defsess = NULL;
193 194
static const gchar *cursess = NULL;
static const gchar *curlang = NULL;
195 196 197
static gchar *curuser = NULL;
static gchar *session = NULL;
static gchar *language = NULL;
198 199
static gint curdelay = 0;

200 201
static gint savesess = GTK_RESPONSE_NO;
static gint savelang = GTK_RESPONSE_NO;
202

203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
/* back_prog_timeout_event_id: event of the timer.
 * back_prog_watcher_event_id: event of the background program watcher.
 * back_prog_pid: 	       process ID of the background program.
 * back_prog_has_run:	       true if the background program has run
 *  			       at least once.
 * back_prog_watching_events:  true if we are watching for user events.
 * back_prog_delayed: 	       true if the execution of the program has
 *                             been delayed.
 */
static gint back_prog_timeout_event_id = -1;
static gint back_prog_watcher_event_id = -1;
static gint back_prog_pid = -1;
static gboolean back_prog_has_run = FALSE;
static gboolean back_prog_watching_events = FALSE;
static gboolean back_prog_delayed = FALSE;
218

219
static guint timed_handler_id = 0;
220

221
#if FIXME
222
static char *selected_browser_user = NULL;
223
#endif FIXME
224
static gboolean selecting_user = TRUE;
225

226 227 228 229
/* This is true if session dir doesn't exist or is whacked out
 * in some way or another */
static gboolean session_dir_whacked_out = FALSE;

230
static void login_window_resize (gboolean force);
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475

/* Background program logic */
static void back_prog_on_exit (GPid pid, gint status, gpointer data);
static gboolean back_prog_on_timeout (gpointer data);
static gboolean back_prog_delay_timeout (GSignalInvocationHint *ihint, 
					 guint n_param_values, 
					 const GValue *param_values, 
					 gpointer data);
static void back_prog_watch_events (void);
static gchar * back_prog_get_path (void);
static void back_prog_launch_after_timeout (void);
static void back_prog_run (void);
static void back_prog_stop (void);

/* 
 * This function is called when the background program exits.
 * It will add a timer to restart the program after the
 * restart delay has elapsed, if this is enabled.
 */
static void 
back_prog_on_exit (GPid pid, gint status, gpointer data)
{
	g_assert (back_prog_timeout_event_id == -1);
	
	back_prog_watcher_event_id = -1;
	back_prog_pid = -1;
	
	back_prog_launch_after_timeout ();
}

/* 
 * This function starts the background program (if any) when
 * the background program timer triggers, unless the execution
 * has been delayed.
 */
static gboolean 
back_prog_on_timeout (gpointer data)
{
	g_assert (back_prog_watcher_event_id == -1);
	g_assert (back_prog_pid == -1);
	
	back_prog_timeout_event_id = -1;
	
	if (back_prog_delayed) {
	 	back_prog_launch_after_timeout ();
	} else {
		back_prog_run ();
	}
	
	return FALSE;
}

/*
 * This function is called to delay the execution of the background
 * program when the user is doing something (when we detect an event).
 */
static gboolean
back_prog_delay_timeout (GSignalInvocationHint *ihint,
	       		 guint n_param_values,
	       		 const GValue *param_values,
	       		 gpointer data)
{
	back_prog_delayed = TRUE;
	return TRUE;
}

/*
 * This function creates signal listeners to catch user events.
 * That allows us to avoid spawning the background program
 * when the user is doing something.
 */
static void
back_prog_watch_events (void)
	{
	guint sid;
	
	if (back_prog_watching_events)
		return;
	
	back_prog_watching_events = TRUE;
	
	sid = g_signal_lookup ("activate", GTK_TYPE_MENU_ITEM);
	g_signal_add_emission_hook (sid, 0, back_prog_delay_timeout, 
				    NULL, NULL);

	sid = g_signal_lookup ("key_press_event", GTK_TYPE_WIDGET);
	g_signal_add_emission_hook (sid, 0, back_prog_delay_timeout, 
				    NULL, NULL);

	sid = g_signal_lookup ("button_press_event", GTK_TYPE_WIDGET);
	g_signal_add_emission_hook (sid, 0, back_prog_delay_timeout, 
				    NULL, NULL);
	}

/*
 * This function returns the path of the background program
 * if there is one. Otherwise, NULL is returned.
 */
static gchar *
back_prog_get_path (void)
{
	if ((GdmBackgroundType == GDM_BACKGROUND_NONE ||
	     GdmRunBackgroundProgAlways) &&
	    ! ve_string_empty (GdmBackgroundProg)) {
		return GdmBackgroundProg;
	} else 
		return NULL;
}

/* 
 * This function creates a timer to start the background 
 * program after the requested delay (in seconds) has elapsed.
 */ 
static void 
back_prog_launch_after_timeout ()
{
	g_assert (back_prog_timeout_event_id == -1);
	g_assert (back_prog_watcher_event_id == -1);
	g_assert (back_prog_pid == -1);
	
	int timeout;
	
	/* No program to run. */
	if (! back_prog_get_path ())
		return;
	
	/* First time. */
	if (! back_prog_has_run) {
		timeout = GdmBackgroundProgInitialDelay;
		
	/* Already run, but we are allowed to restart it. */
	} else if (GdmRestartBackgroundProgram) {
		timeout = GdmBackgroundProgRestartDelay;
	
	/* Already run, but we are not allowed to restart it. */
	} else {
		return;
	}
	
	back_prog_delayed = FALSE;
	back_prog_watch_events ();
	back_prog_timeout_event_id = g_timeout_add (timeout * 1000,
						    back_prog_on_timeout,
						    NULL);
}

/* 
 * This function starts the background program (if any).
 */
static void
back_prog_run (void)
{
	GPid pid = -1;
	GError *error = NULL;
	gchar *command = NULL;
	gchar **back_prog_argv = NULL;
	
	g_assert (back_prog_timeout_event_id == -1);
	g_assert (back_prog_watcher_event_id == -1);
	g_assert (back_prog_pid == -1);
	
	command = back_prog_get_path ();
	if (! command)
		return;
	
	/* Focus new windows. We want to give focus to the background program. */
	gdm_wm_focus_new_windows (TRUE);
		
	back_prog_argv = ve_split (command);	
	
	/* Don't reap child automatically: we want to catch the event. */
	if (! g_spawn_async (".", 
			     back_prog_argv, 
			     NULL, 
			     (GSpawnFlags) (G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), 
			     NULL, 
			     NULL, 
			     &pid, 
			     &error)) {
			    
		GtkWidget *dialog;
		dialog = ve_hig_dialog_new (NULL,
					    GTK_DIALOG_MODAL,
					    GTK_MESSAGE_ERROR,
					    GTK_BUTTONS_OK,
					    FALSE,
					    _("Cannot start background program"),
					    _("Cannot start program '%s': %s."),
					    command,
					    error->message);
		gtk_widget_show_all (dialog);
		gdm_wm_center_window (GTK_WINDOW (dialog));

		gtk_dialog_run (GTK_DIALOG (dialog));
		gtk_widget_destroy (dialog);
		g_error_free (error);
		g_strfreev (back_prog_argv);
		
		return;
	}
	
	g_strfreev (back_prog_argv);
	back_prog_watcher_event_id = g_child_watch_add (pid, 
							back_prog_on_exit,
							NULL);
	back_prog_pid = pid;
	back_prog_has_run = TRUE;
}

/*
 * This function stops the background program if it is running,
 * and removes any associated timer or watcher.
 */
static void 
back_prog_stop (void)
{
	if (back_prog_timeout_event_id != -1) {
		GSource *source = g_main_context_find_source_by_id
					(NULL, back_prog_timeout_event_id);
		if (source != NULL)
			g_source_destroy (source);
			
		back_prog_timeout_event_id = -1;
	}
	
	if (back_prog_watcher_event_id != -1) {
		GSource *source = g_main_context_find_source_by_id
					(NULL, back_prog_watcher_event_id);
		if (source != NULL)
			g_source_destroy (source);
			
		back_prog_watcher_event_id = -1;
	}
	
	if (back_prog_pid != -1) {		
		if (kill (back_prog_pid, SIGTERM) == 0) {
			waitpid (back_prog_pid, NULL, 0);
		}

		back_prog_pid = -1;
	}
}


476 477 478 479 480 481 482 483 484 485
/*
 * Timed Login: Timer
 */

static gboolean
gdm_timer (gpointer data)
{
	curdelay --;
	if ( curdelay <= 0 ) {
		/* timed interruption */
486 487
		printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN);
		fflush (stdout);
488 489 490 491 492 493 494 495 496 497 498 499 500
	} else {
		gchar *autologin_msg;

		if (curdelay > 1)
			autologin_msg = g_strdup_printf (
				_("User %s will login in %d seconds"),
				GdmTimedLogin, curdelay);
		else
			autologin_msg = g_strdup_printf (
				_("User %s will login in %d second"),
				GdmTimedLogin, curdelay);
		gtk_label_set_text (GTK_LABEL (auto_timed_msg), autologin_msg);
		gtk_widget_show (GTK_WIDGET (auto_timed_msg));
501
		g_free (autologin_msg);
502
		login_window_resize (FALSE /* force */);
503 504 505 506 507 508 509 510 511 512 513
	}
	return TRUE;
}

/*
 * Timed Login: On GTK events, increase delay to
 * at least 30 seconds. Or the TimedLoginDelay,
 * whichever is higher
 */

static gboolean
514 515 516 517
gdm_timer_up_delay (GSignalInvocationHint *ihint,
		    guint	           n_param_values,
		    const GValue	  *param_values,
		    gpointer		   data)
518 519 520 521 522 523
{
	if (curdelay < 30)
		curdelay = 30;
	if (curdelay < GdmTimedLoginDelay)
		curdelay = GdmTimedLoginDelay;
	return TRUE;
524 525 526 527 528 529 530 531 532 533 534 535 536
}

/* The reaping stuff */
static time_t last_reap_delay = 0;

static gboolean
delay_reaping (GSignalInvocationHint *ihint,
	       guint	           n_param_values,
	       const GValue	  *param_values,
	       gpointer		   data)
{
	last_reap_delay = time (NULL);
	return TRUE;
537 538
}      

539 540 541 542 543 544 545 546 547 548 549 550
static gboolean
reap_flexiserver (gpointer data)
{
	if (GdmFlexiReapDelayMinutes > 0 &&
	    ((time (NULL) - last_reap_delay) / 60) > GdmFlexiReapDelayMinutes) {
		gdm_kill_thingies ();
		_exit (DISPLAY_REMANAGE);
	}
	return TRUE;
}


551
static gboolean
552 553 554 555
gdm_event (GSignalInvocationHint *ihint,
	   guint		n_param_values,
	   const GValue	       *param_values,
	   gpointer		data)
556
{
557 558
	GdkEvent *event;

559 560 561 562
	/* HAAAAAAAAAAAAAAAAACK */
	/* Since the user has not logged in yet and may have left/right
	 * mouse buttons switched, we just translate every right mouse click
	 * to a left mouse click */
563 564 565 566 567
	if (n_param_values != 2 ||
	    !G_VALUE_HOLDS (&param_values[1], GDK_TYPE_EVENT))
	  return FALSE;
	
	event = g_value_get_boxed (&param_values[1]);
568 569 570 571 572 573 574
	if ((event->type == GDK_BUTTON_PRESS ||
	     event->type == GDK_2BUTTON_PRESS ||
	     event->type == GDK_3BUTTON_PRESS ||
	     event->type == GDK_BUTTON_RELEASE)
	    && event->button.button == 3)
		event->button.button = 1;

575 576 577 578 579 580 581 582 583
	/* Support Ctrl-U for blanking the username/password entry */
	if (event->type == GDK_KEY_PRESS &&
	    (event->key.state & GDK_CONTROL_MASK) &&
	    (event->key.keyval == GDK_u ||
	     event->key.keyval == GDK_U)) {

		gtk_entry_set_text (GTK_ENTRY (entry), "");
	}

584 585
	return TRUE;
}      
586

587 588
void
gdm_kill_thingies (void)
589
{
590
	back_prog_stop ();
591 592
}

593

Martin Peterson's avatar
Martin Peterson committed
594
static void
595
gdm_login_done (int sig)
Martin Peterson's avatar
Martin Peterson committed
596
{
597 598
	gdm_kill_thingies ();
	_exit (EXIT_SUCCESS);
Martin Peterson's avatar
Martin Peterson committed
599 600
}

601 602 603
static void
set_screen_pos (GtkWidget *widget, int x, int y)
{
604 605
	int width, height;

606 607 608
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_IS_WIDGET (widget));

609 610
	gtk_window_get_size (GTK_WINDOW (widget), &width, &height);

Pablo Saratxaga's avatar
Pablo Saratxaga committed
611 612
	/* allow negative values, to be like standard X geometry ones */
	if (x < 0)
613
		x = gdm_wm_screen.width + x - width;
Pablo Saratxaga's avatar
Pablo Saratxaga committed
614
	if (y < 0)
615
		y = gdm_wm_screen.height + y - height;
Pablo Saratxaga's avatar
Pablo Saratxaga committed
616

617 618 619 620
	if (x < gdm_wm_screen.x)
		x = gdm_wm_screen.x;
	if (y < gdm_wm_screen.y)
		y = gdm_wm_screen.y;
621 622 623 624
	if (x > gdm_wm_screen.x + gdm_wm_screen.width - width)
		x = gdm_wm_screen.x + gdm_wm_screen.width - width;
	if (y > gdm_wm_screen.y + gdm_wm_screen.height - height)
		y = gdm_wm_screen.y + gdm_wm_screen.height - height;
625

626
	gtk_window_move (GTK_WINDOW (widget), x, y);
627
}
Martin Peterson's avatar
Martin Peterson committed
628

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
static guint set_pos_id = 0;

static gboolean
set_pos_idle (gpointer data)
{
	if (GdmSetPosition) {
		set_screen_pos (login, GdmPositionX, GdmPositionY);
	} else {
		gdm_wm_center_window (GTK_WINDOW (login));
	}
	set_pos_id = 0;
	return FALSE;
}

static void
login_window_resize (gboolean force)
{
	/* allow opt out if we don't really need
	 * a resize */
	if ( ! force) {
		GtkRequisition req;
		int width, height;

		gtk_window_get_size (GTK_WINDOW (login), &width, &height);
		gtk_widget_size_request (login, &req);

		if (req.width <= width && req.height <= height)
			return;
	}

	GTK_WINDOW (login)->need_default_size = TRUE;
	gtk_container_check_resize (GTK_CONTAINER (login));

	if (set_pos_id == 0)
		set_pos_id = g_idle_add (set_pos_idle, NULL);
}


667 668 669 670
typedef struct _CursorOffset {
	int x;
	int y;
} CursorOffset;
Martin Peterson's avatar
Martin Peterson committed
671

672 673 674 675 676 677 678 679 680 681 682 683 684 685
static gboolean
within_rect (GdkRectangle *rect, int x, int y)
{
	return
		x >= rect->x &&
		x <= rect->x + rect->width &&
		y >= rect->y &&
		y <= rect->y + rect->height;
}

/* switch to the xinerama screen where x,y are */
static void
set_screen_to_pos (int x, int y)
{
686
	if ( ! within_rect (&gdm_wm_screen, x, y)) {
687
		int i;
688
		/* If not within gdm_wm_screen boundaries,
689 690
		 * maybe we want to switch xinerama
		 * screen */
691 692 693
		for (i = 0; i < gdm_wm_screens; i++) {
			if (within_rect (&gdm_wm_allscreens[i], x, y)) {
				gdm_wm_set_screen (i);
694 695 696 697 698 699
				break;
			}
		}
	}
}

Martin Peterson's avatar
Martin Peterson committed
700

701
/* I *really* need to rewrite this */
Martin Peterson's avatar
Martin Peterson committed
702
static gchar *
703
gdm_parse_enriched_string (const char *pre, const gchar *s, const char *post)
Martin Peterson's avatar
Martin Peterson committed
704
{
705
    gchar hostbuf[1023] = "";
706
    gchar *hostname, *display;
707
    struct utsname name;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
708
    GString *str;
Martin Peterson's avatar
Martin Peterson committed
709

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
710
    if (s == NULL)
711 712
	return(NULL);

713
    hostbuf[sizeof (hostbuf) - 1] = '\0';
714
    if (gethostname (hostbuf, sizeof (hostbuf) - 1) < 0)
715
	    hostname = g_strdup ("GNOME");
716 717
    else
	    hostname = g_strdup (hostbuf);
718 719 720

    display = g_strdup (g_getenv ("DISPLAY"));

721
    uname (&name);
722

723
    if (strlen (s) > 2048) {
724
	    char *buffer;
725
	    syslog (LOG_ERR, _("%s: String too long!"), "gdm_parse_enriched_string");
726 727
	    g_free (display);
	    buffer = g_strdup_printf (_("%sWelcome to %s%s"),
728
				      pre, name.nodename, post);
729 730
	    g_free (hostname);
	    return buffer;
Martin Peterson's avatar
Martin Peterson committed
731 732
    }

733
    str = g_string_new (pre);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
734

735
    while (s[0] != '\0') {
736 737
	/* Backslash commands */
	if (s[0] == '\\' && s[1] != '\0') {
738
		char cmd = s[1];
739
		s++;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
740
		switch (cmd) {
741 742 743 744 745 746 747 748 749 750
		case 'n':
			g_string_append_c (str, '\n');
			break;
		default:
			g_string_append_c (str, cmd);
		}
	/* Percent commands */
	} else if (s[0] == '%' && s[1] != 0) {
		char cmd = s[1];
		s++;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
751

752
		switch (cmd) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
753 754 755 756 757 758 759
		case 'h': 
			g_string_append (str, hostname);
			break;

		case 'n':
			g_string_append (str, name.nodename);
			break;
Martin Peterson's avatar
Martin Peterson committed
760

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
761
		case 'd': 
762
			g_string_append (str, ve_sure_string (display));
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
			break;

		case 's':
			g_string_append (str, name.sysname);
			break;

		case 'r':
			g_string_append (str, name.release);
			break;

		case 'm':
			g_string_append (str, name.machine);
			break;

		case '%':
			g_string_append_c (str, '%');
			break;

		default:
			break;
		};
	} else {
		g_string_append_c (str, *s);
Martin Peterson's avatar
Martin Peterson committed
786
	}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
787
	s++;
Martin Peterson's avatar
Martin Peterson committed
788 789
    }

790
    g_string_append (str, post);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
791

792
    g_free (display);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
793
    g_free (hostname);
Martin Peterson's avatar
Martin Peterson committed
794

795
    return g_string_free (str, FALSE);
Martin Peterson's avatar
Martin Peterson committed
796 797
}

798 799 800
static void
gdm_run_gdmconfig (GtkWidget *w, gpointer data)
{
801
	/* we should be now fine for focusing new windows */
802
	gdm_wm_focus_new_windows (TRUE);
803

804
	/* configure interruption */
805 806
	printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_CONFIGURE);
	fflush (stdout);
807
}
Martin Peterson's avatar
Martin Peterson committed
808

809
static void
810
gdm_login_reboot_handler (void)
Martin Peterson's avatar
Martin Peterson committed
811
{
812
	if (gdm_common_query (_("Are you sure you want to reboot the machine?"),
813
			     FALSE /* markup */,
814
			     _("_Reboot"), NULL, TRUE) == GTK_RESPONSE_YES) {
815
		closelog();
Martin Peterson's avatar
Martin Peterson committed
816

817
		gdm_kill_thingies ();
818 819
		_exit (DISPLAY_REBOOT);
	}
Martin Peterson's avatar
Martin Peterson committed
820 821 822
}


823
static void
824
gdm_login_halt_handler (void)
Martin Peterson's avatar
Martin Peterson committed
825
{
826
	if (gdm_common_query (_("Are you sure you want to shut down the machine?"),
827
			     FALSE /* markup */,
828
			     _("Shut _Down"), NULL, TRUE) == GTK_RESPONSE_YES) {
829
		closelog();
830

831
		gdm_kill_thingies ();
832 833
		_exit (DISPLAY_HALT);
	}
Martin Peterson's avatar
Martin Peterson committed
834 835
}

836 837 838 839 840
static void
gdm_login_use_chooser_handler (void)
{
	closelog();

841
	gdm_kill_thingies ();
842 843 844
	_exit (DISPLAY_RUN_CHOOSER);
}

845 846 847
static void
gdm_login_suspend_handler (void)
{
848
	if (gdm_common_query (_("Are you sure you want to suspend the machine?"),
849
			     FALSE /* markup */,
850
			     _("_Suspend"), NULL, TRUE) == GTK_RESPONSE_YES) {
851 852 853
		/* suspend interruption */
		printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_SUSPEND);
		fflush (stdout);
854 855
	}
}
Martin Peterson's avatar
Martin Peterson committed
856

857 858 859
static void
gdm_theme_handler (GtkWidget *widget, gpointer data)
{
860
    const char *theme_name = (const char *)data;
861 862 863 864 865

    printf ("%c%c%c%s\n", STX, BEL, GDM_INTERRUPT_THEME, theme_name);
  
    fflush (stdout);

866 867 868 869
    gdm_set_theme (theme_name);

    login_window_resize (FALSE);
    gdm_wm_center_window (GTK_WINDOW (login));
870 871
}

Martin Peterson's avatar
Martin Peterson committed
872
static void 
873
gdm_login_parse_config (void)
Martin Peterson's avatar
Martin Peterson committed
874 875
{
    struct stat unused;
876
    VeConfig *config;
Martin Peterson's avatar
Martin Peterson committed
877
	
878
    if G_UNLIKELY (stat (GDM_CONFIG_FILE, &unused) == -1) {
879 880
	syslog (LOG_ERR, _("%s: No configuration file: %s. Using defaults."), 
		"gdm_login_parse_config", GDM_CONFIG_FILE);
881 882
	used_defaults = TRUE;
    }
Martin Peterson's avatar
Martin Peterson committed
883

884 885
    if (ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) {
	    greeter_Welcome_key = GDM_KEY_REMOTEWELCOME;
886
	    greeter_DefaultWelcome_key = GDM_KEY_DEFAULT_REMOTEWELCOME;
887 888
    } else {
	    greeter_Welcome_key = GDM_KEY_WELCOME;
889
	    greeter_DefaultWelcome_key = GDM_KEY_DEFAULT_WELCOME;
890 891
    }

892 893 894 895 896 897 898
    config = ve_config_get (GDM_CONFIG_FILE);

    GdmAllowRoot = ve_config_get_bool (config, GDM_KEY_ALLOWROOT);
    GdmAllowRemoteRoot = ve_config_get_bool (config, GDM_KEY_ALLOWREMOTEROOT);
    GdmBrowser = ve_config_get_bool (config, GDM_KEY_BROWSER);
    GdmLogo = ve_config_get_string (config, GDM_KEY_LOGO);
    GdmQuiver = ve_config_get_bool (config, GDM_KEY_QUIVER);
899
    GdmSystemMenuReal = GdmSystemMenu = ve_config_get_bool (config, GDM_KEY_SYSMENU);
900
    GdmChooserButtonReal = GdmChooserButton = ve_config_get_bool (config, GDM_KEY_CHOOSER_BUTTON);
901 902 903
    GdmHalt = ve_config_get_string (config, GDM_KEY_HALT);
    GdmReboot = ve_config_get_string (config, GDM_KEY_REBOOT);
    GdmSuspend = ve_config_get_string (config, GDM_KEY_SUSPEND);
904
    GdmConfigAvailableReal = GdmConfigAvailable = ve_config_get_bool (config, GDM_KEY_CONFIG_AVAILABLE);
905
    GdmConfigurator = ve_config_get_string (config, GDM_KEY_CONFIGURATOR);
906 907
    GdmInfoMsgFile = ve_config_get_string (config, GDM_KEY_INFO_MSG_FILE);
    GdmInfoMsgFont = ve_config_get_string (config, GDM_KEY_INFO_MSG_FONT);
908 909 910
    GdmTitleBar = ve_config_get_bool (config, GDM_KEY_TITLE_BAR);
    GdmLocaleFile = ve_config_get_string (config, GDM_KEY_LOCFILE);
    GdmSessionDir = ve_config_get_string (config, GDM_KEY_SESSDIR);
911
    GdmDefaultSession = ve_config_get_string (config, GDM_KEY_DEFAULTSESSION);
912
    GdmWelcome = ve_config_get_translated_string (config, greeter_Welcome_key);
913 914 915 916 917
    GdmDefaultWelcome = ve_config_get_bool (config, greeter_DefaultWelcome_key);

    /* Replace default welcome message with one specified in the config file, if
     * use default is set to no */
    if (GdmDefaultWelcome && strcmp (greeter_Welcome_key, GDM_KEY_WELCOME) == 0) {
918
	    g_free (GdmWelcome);
919 920
	    GdmWelcome = g_strdup (_(GDM_DEFAULT_WELCOME_MSG));
    } else if (GdmDefaultWelcome && strcmp (greeter_Welcome_key, GDM_KEY_REMOTEWELCOME) == 0) {
921
	    g_free (GdmWelcome);
922
	    GdmWelcome = g_strdup (_(GDM_DEFAULT_REMOTEWELCOME_MSG));
923
    }
924

925
    GdmBackgroundProg = ve_config_get_string (config, GDM_KEY_BACKGROUNDPROG);
926
    GdmRunBackgroundProgAlways = ve_config_get_bool (config, GDM_KEY_RUNBACKGROUNDPROGALWAYS);
927 928 929
    GdmBackgroundProgInitialDelay = ve_config_get_int (config, GDM_KEY_BACKGROUNDPROGINITIALDELAY);
    GdmRestartBackgroundProgram = ve_config_get_bool (config, GDM_KEY_RESTARTBACKGROUNDPROG);
    GdmBackgroundProgRestartDelay = ve_config_get_int (config, GDM_KEY_BACKGROUNDPROGRESTARTDELAY);
930 931 932 933 934 935
    GdmBackgroundImage = ve_config_get_string (config, GDM_KEY_BACKGROUNDIMAGE);
    GdmBackgroundColor = ve_config_get_string (config, GDM_KEY_BACKGROUNDCOLOR);
    GdmBackgroundType = ve_config_get_int (config, GDM_KEY_BACKGROUNDTYPE);
    GdmBackgroundScaleToFit = ve_config_get_bool (config, GDM_KEY_BACKGROUNDSCALETOFIT);
    GdmBackgroundRemoteOnlyColor = ve_config_get_bool (config, GDM_KEY_BACKGROUNDREMOTEONLYCOLOR);
    GdmGtkRC = ve_config_get_string (config, GDM_KEY_GTKRC);
936 937
    GdmIncludeAll = ve_config_get_bool (config, GDM_KEY_INCLUDEALL);
    GdmInclude = ve_config_get_string (config, GDM_KEY_INCLUDE);
938 939 940 941 942 943 944 945 946
    GdmExclude = ve_config_get_string (config, GDM_KEY_EXCLUDE);
    GdmMinimalUID = ve_config_get_int (config, GDM_KEY_MINIMALUID);
    GdmGlobalFaceDir = ve_config_get_string (config, GDM_KEY_FACEDIR);
    GdmDefaultFace = ve_config_get_string (config, GDM_KEY_FACE);
    GdmDebug = ve_config_get_bool (config, GDM_KEY_DEBUG);
    GdmIconMaxWidth = ve_config_get_int (config, GDM_KEY_ICONWIDTH);
    GdmIconMaxHeight = ve_config_get_int (config, GDM_KEY_ICONHEIGHT);
    GdmXineramaScreen = ve_config_get_int (config, GDM_KEY_XINERAMASCREEN);
    GdmUseCirclesInEntry = ve_config_get_bool (config, GDM_KEY_ENTRY_CIRCLES);
947
    GdmUseInvisibleInEntry = ve_config_get_bool (config, GDM_KEY_ENTRY_INVISIBLE);
948 949 950 951 952
    GdmLockPosition = ve_config_get_bool (config, GDM_KEY_LOCK_POSITION);
    GdmSetPosition = ve_config_get_bool (config, GDM_KEY_SET_POSITION);
    GdmPositionX = ve_config_get_int (config, GDM_KEY_POSITIONX);
    GdmPositionY = ve_config_get_int (config, GDM_KEY_POSITIONY);

953 954 955 956
    GdmAllowGtkThemeChange = ve_config_get_bool (config, GDM_KEY_ALLOW_GTK_THEME_CHANGE);
    GdmGtkThemesToAllow = ve_config_get_string (config, GDM_KEY_GTK_THEMES_TO_ALLOW);
    GdmGtkTheme = ve_config_get_string (config, GDM_KEY_GTK_THEME);

957 958 959
    GdmShowXtermFailsafeSession = ve_config_get_bool (config, GDM_KEY_SHOW_XTERM_FAILSAFE);
    GdmShowGnomeFailsafeSession = ve_config_get_bool (config, GDM_KEY_SHOW_GNOME_FAILSAFE);
    GdmShowLastSession = ve_config_get_bool (config, GDM_KEY_SHOW_LAST_SESSION);
960
    
961
    GdmTimedLoginEnable = ve_config_get_bool (config, GDM_KEY_TIMED_LOGIN_ENABLE);
962

963 964 965
    /* Note: TimedLogin here is not gotten out of the config
     * but from the daemon since it's been munged on by the daemon a bit
     * already maybe */
966
    if (GdmTimedLoginEnable) {
967
	    GdmTimedLogin = g_strdup (g_getenv("GDM_TIMED_LOGIN_OK"));
968
            if (ve_string_empty (GdmTimedLogin)) {
969 970 971 972
	      g_free (GdmTimedLogin);
	      GdmTimedLogin = NULL;
	    }

973
	    GdmTimedLoginDelay =
974
		    ve_config_get_int (config, GDM_KEY_TIMED_LOGIN_DELAY);
975
	    if (GdmTimedLoginDelay < 5) {
976
		    syslog (LOG_WARNING,
977
			    _("TimedLoginDelay was less than 5.  I'll just use 5."));
978
		    GdmTimedLoginDelay = 5;
979 980 981
	    }
    } else {
	    GdmTimedLogin = NULL;
982
	    GdmTimedLoginDelay = 5;
983
    }
984
  
985
    GdmFlexiReapDelayMinutes = ve_config_get_int (config, GDM_KEY_FLEXI_REAP_DELAY_MINUTES);
986
    GdmUse24Clock = ve_config_get_bool (config, GDM_KEY_USE_24_CLOCK);
987

988 989 990 991
    GdmSoundOnLoginReady = ve_config_get_bool (config,
	                       GDM_KEY_SOUND_ON_LOGIN_READY);
    GdmSoundOnLoginReadyFile = ve_config_get_string (config,
	                           GDM_KEY_SOUND_ON_LOGIN_READY_FILE);
992 993
    GdmSoundProgram = ve_config_get_string (config, GDM_KEY_SOUND_PROGRAM);

994 995 996 997
    if (GdmIconMaxWidth < 0) GdmIconMaxWidth = 128;
    if (GdmIconMaxHeight < 0) GdmIconMaxHeight = 128;
    if (GdmXineramaScreen < 0) GdmXineramaScreen = 0;

Martin Peterson's avatar
Martin Peterson committed
998
    /* Disable System menu on non-local displays */
999
    if (ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) {
1000 1001
	    GdmSystemMenuReal = FALSE;
	    GdmConfigAvailableReal = FALSE;
1002
	    GdmChooserButtonReal = FALSE;
1003 1004 1005 1006
	    if (GdmBackgroundRemoteOnlyColor &&
		GdmBackgroundType == GDM_BACKGROUND_IMAGE)
		    GdmBackgroundType = GDM_BACKGROUND_COLOR;
	    if (GdmBackgroundRemoteOnlyColor &&
1007
		! ve_string_empty (GdmBackgroundProg)) {
1008 1009 1010
		    g_free (GdmBackgroundProg);
		    GdmBackgroundProg = NULL;
	    }
1011 1012 1013
	    login_is_local = FALSE;
    } else {
	    login_is_local = TRUE;
1014
    }
Martin Peterson's avatar
Martin Peterson committed
1015 1016 1017 1018
}


static gboolean 
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1019
gdm_login_list_lookup (GSList *l, const gchar *data)
Martin Peterson's avatar
Martin Peterson committed
1020
{
1021
    GList *list = l;
Martin Peterson's avatar
Martin Peterson committed
1022

1023 1024
    if (list == NULL || data == NULL)
	return FALSE;
Martin Peterson's avatar
Martin Peterson committed
1025

1026 1027 1028 1029 1030 1031 1032
    /* FIXME: Hack, will support these builtin types later */
    if (strcmp (data, GDM_SESSION_DEFAULT ".desktop") == 0 ||
	strcmp (data, GDM_SESSION_CUSTOM ".desktop") == 0 ||
	strcmp (data, GDM_SESSION_FAILSAFE ".desktop") == 0) {
	    return TRUE;
    }

1033
    while (list) {
Martin Peterson's avatar
Martin Peterson committed
1034

1035
	if (strcmp (list->data, data) == 0)
1036
	    return TRUE;
Martin Peterson's avatar
Martin Peterson committed
1037
	
1038
	list = list->next;
Martin Peterson's avatar
Martin Peterson committed
1039 1040
    }

1041
    return FALSE;
Martin Peterson's avatar
Martin Peterson committed
1042 1043 1044
}

static void
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1045
gdm_login_session_lookup (const gchar* savedsess)
Martin Peterson's avatar
Martin Peterson committed
1046
{
0's avatar
0 committed
1047
    /* Don't save session unless told otherwise */
1048
    savesess = GTK_RESPONSE_NO;
1049

1050
    /* Previously saved session not found in ~user/.gnome2/gdm */
1051 1052 1053
    if ( ! (savedsess != NULL &&
	    strcmp ("(null)", savedsess) != 0 &&
	    savedsess[0] != '\0')) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1054 1055 1056
	    /* If "Last" is chosen run Default,
	     * else run user's current selection */
	    g_free (session);
1057
	    if (cursess == NULL || strcmp (cursess, LAST_SESSION) == 0)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1058 1059 1060 1061
		    session = g_strdup (defsess);
	    else
		    session = g_strdup (cursess);

1062
	    savesess = GTK_RESPONSE_YES;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1063
	    return;
Martin Peterson's avatar
Martin Peterson committed
1064 1065
    }

0's avatar
0 committed
1066
    /* If "Last" session is selected */
1067 1068
    if (cursess == NULL ||
	strcmp (cursess, LAST_SESSION) == 0) { 
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1069 1070
	g_free (session);
	session = g_strdup (savedsess);
0's avatar
0 committed
1071 1072 1073 1074

	/* Check if user's saved session exists on this box */
	if (!gdm_login_list_lookup (sessions, session)) {
	    gchar *msg;
Martin Peterson's avatar
Martin Peterson committed
1075

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1076 1077
	    g_free (session);
	    session = g_strdup (defsess);
1078 1079 1080 1081
            msg = g_strdup_printf (_("Your preferred session type %s is not "
				     "installed on this machine.\n"
                                     "Do you wish to make %s the default for "
				     "future sessions?"),
1082 1083
                                   gdm_session_name (savedsess),
                                   gdm_session_name (defsess));	    
1084 1085
	    savesess = gdm_common_query (msg, FALSE /* markup */,
		 _("Make _Default"), _("Just _Log In"), TRUE);
0's avatar
0 committed
1086
	    g_free (msg);
Martin Peterson's avatar
Martin Peterson committed
1087 1088 1089 1090
	}
    }
    /* One of the other available session types is selected */
    else { 
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1091 1092
	g_free (session);
	session = g_strdup (cursess);
Martin Peterson's avatar
Martin Peterson committed
1093

0's avatar
0 committed
1094
	/* User's saved session is not the chosen one */
1095
	if (strcmp (session, GDM_SESSION_FAILSAFE_GNOME) == 0 ||
1096
	    strcmp (session, GDM_SESSION_FAILSAFE_XTERM) == 0 ||
1097 1098
	    g_ascii_strcasecmp (session, GDM_SESSION_FAILSAFE ".desktop") == 0 ||
	    g_ascii_strcasecmp (session, GDM_SESSION_FAILSAFE) == 0) {
1099
		savesess = GTK_RESPONSE_NO;
1100
	} else if (strcmp (savedsess, session) != 0) {
1101 1102 1103 1104 1105 1106 1107 1108
		gchar *msg = NULL;

                if (GdmShowLastSession) {
                        msg = g_strdup_printf (_("You have chosen %s for this "
                                                 "session, but your default "
                                                 "setting is %s.\nDo you wish "
                                                 "to make %s the default for "
                                                 "future sessions?"),
1109 1110 1111
                                               gdm_session_name (session),
                                               gdm_session_name (savedsess),
                                               gdm_session_name (session));
1112 1113
			savesess = gdm_common_query (msg, FALSE /* markup */,
				_("Make _Default"), _("Just For _This Session"), TRUE);
1114 1115
                } else if (strcmp (session, defsess) != 0 &&
			   strcmp (session, savedsess) != 0 &&
1116 1117 1118 1119 1120 1121
                           strcmp (session, LAST_SESSION) != 0) {
                        /* if !GdmShowLastSession then our saved session is
                         * irrelevant, we are in "switchdesk mode"
                         * and the relevant thing is the saved session
                         * in .Xclients
                         */
1122 1123 1124 1125 1126 1127 1128
			if (access ("/usr/bin/switchdesk", F_OK) == 0) {
				msg = g_strdup_printf (_("You have chosen %s for this "
							 "session.\nIf you wish to make %s "
							 "the default for future sessions,\n"
							 "run the 'switchdesk' utility\n"
							 "(System->Desktop Switching Tool from "
							 "the panel menu)."),
1129 1130
						       gdm_session_name (session),
						       gdm_session_name (session));
1131
				gdm_common_message (msg);
1132
			}
1133
			savesess = GTK_RESPONSE_NO;
1134
                }
1135
		g_free (msg);
Martin Peterson's avatar
Martin Peterson committed
1136 1137
	}
    }
0's avatar
0 committed
1138
}
Martin Peterson's avatar
Martin Peterson committed
1139 1140


0's avatar
0 committed
1141
static void
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1142
gdm_login_language_lookup (const gchar* savedlang)
0's avatar
0 committed
1143 1144
{
    /* Don't save language unless told otherwise */
1145
    savelang = GTK_RESPONSE_NO;
0's avatar
0 committed
1146

1147 1148
    if (savedlang == NULL)
	    savedlang = "";
0's avatar
0 committed
1149 1150

    /* If a different language is selected */
1151
    if (curlang != NULL && strcmp (curlang, LAST_LANGUAGE) != 0) {
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1152
        g_free (language);
1153 1154 1155 1156
	if (strcmp (curlang, DEFAULT_LANGUAGE) == 0)
		language = g_strdup ("");
	else
		language = g_strdup (curlang);
Martin Peterson's avatar
Martin Peterson committed
1157

0's avatar
0 committed
1158
	/* User's saved language is not the chosen one */
1159
	if (strcmp (savedlang, language) != 0) {
0's avatar
0 committed
1160
	    gchar *msg;
1161 1162
	    char *curname, *savedname;

1163
	    if (strcmp (curlang, DEFAULT_LANGUAGE) == 0) {
1164
		    curname = g_strdup (_("System Default"));
1165 1166 1167 1168 1169 1170 1171 1172
	    } else {
		    curname = gdm_lang_name (curlang,
					     FALSE /* never_encoding */,
					     TRUE /* no_group */,
					     TRUE /* untranslated */,
					     TRUE /* markup */);
	    }
	    if (strcmp (savedlang, "") == 0) {
1173
		    savedname = g_strdup (_("System Default"));
1174 1175 1176 1177 1178 1179 1180
	    } else {
		    savedname = gdm_lang_name (savedlang,
					       FALSE /* never_encoding */,
					       TRUE /* no_group */,
					       TRUE /* untranslated */,
					       TRUE /* markup */);
	    }
0's avatar
0 committed
1181

George Lebl's avatar
George Lebl committed
1182
	    msg = g_strdup_printf (_("You have chosen %s for this session, but your default setting is "
0's avatar
0 committed
1183
				     "%s.\nDo you wish to make %s the default for future sessions?"),
1184 1185 1186 1187
				   curname, savedname, curname);
	    g_free (curname);
	    g_free (savedname);

1188
	    savelang = gdm_common_query (msg, TRUE /* markup */, _("Make _Default"), _("Just For _This Session"), TRUE);
0's avatar
0 committed
1189
	    g_free (msg);
Martin Peterson's avatar
Martin Peterson committed
1190
	}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1191 1192 1193
    } else {
	g_free (language);
	language = g_strdup (savedlang);
Martin Peterson's avatar
Martin Peterson committed
1194 1195 1196
    }
}

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
static int dance_handler = 0;

static gboolean
dance (gpointer data)
{
	static double t1 = 0.0, t2 = 0.0;
	double xm, ym;
	int x, y;
	static int width = -1;
	static int height = -1;

	if (width == -1)
1209
		width = gdm_wm_screen.width;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1210
	if (height == -1)
1211
		height = gdm_wm_screen.height;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1212 1213 1214 1215 1216 1217 1218

	if (login == NULL ||
	    login->window == NULL) {
		dance_handler = 0;
		return FALSE;
	}

1219 1220
	xm = cos (2.31 * t1);
	ym = sin (1.03 * t2);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1221 1222 1223 1224

	t1 += 0.03 + (rand () % 10) / 500.0;
	t2 += 0.03 + (rand () % 10) / 500.0;

1225 1226
	x = gdm_wm_screen.x + (width / 2) + (width / 5) * xm;
	y = gdm_wm_screen.y + (height / 2) + (height / 5) * ym;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1227 1228 1229 1230 1231 1232 1233 1234

	set_screen_pos (login,
			x - login->allocation.width / 2,
			y - login->allocation.height / 2);

	return TRUE;
}

1235
static gboolean
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1236 1237
evil (const char *user)
{
1238
	static gboolean old_lock;
1239

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1240
	if (dance_handler == 0 &&
1241
	    /* do not translate */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1242
	    strcmp (user, "Start Dancing") == 0) {
1243
		gdm_common_setup_cursor (GDK_UMBRELLA);
1244
		dance_handler = g_timeout_add (50, dance, NULL);
1245
		old_lock = GdmLockPosition;
1246
		GdmLockPosition = TRUE;
1247 1248 1249
		gtk_entry_set_text (GTK_ENTRY (entry), "");
		return TRUE;
	} else if (dance_handler != 0 &&
1250
		   /* do not translate */
1251
		   strcmp (user, "Stop Dancing") == 0) {
1252
		gdm_common_setup_cursor (GDK_LEFT_PTR);
1253
		g_source_remove (dance_handler);
1254 1255
		dance_handler = 0;
		GdmLockPosition = old_lock;
1256
		gdm_wm_center_window (GTK_WINDOW (login));
1257 1258
		gtk_entry_set_text (GTK_ENTRY (entry), "");
		return TRUE;
1259
				 /* do not translate */
1260
	} else if (strcmp (user, "Gimme Random Cursor") == 0) {
1261
		gdm_common_setup_cursor (((rand () >> 3) % (GDK_LAST_CURSOR/2)) * 2);
1262
		gtk_entry_set_text (GTK_ENTRY (entry), "");
1263 1264
		return TRUE;
				 /* do not translate */
1265 1266 1267 1268 1269 1270
	} else if (strcmp (user, "Require Quater") == 0 ||
		   strcmp (user, "Require Quarter") == 0) {
		/* btw, note that I misspelled quarter before and
		 * thus this checks for Quater as well as Quarter to
		 * keep compatibility which is obviously important for
		 * something like this */
1271
		require_quarter = TRUE;
1272
		gtk_entry_set_text (GTK_ENTRY (entry), "");
1273
		return TRUE;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1274
	}
1275

1276
	return FALSE;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1277
}
Martin Peterson's avatar
Martin Peterson committed
1278

1279 1280
static void
gdm_login_enter (GtkWidget *entry)
Martin Peterson's avatar
Martin Peterson committed
1281
{
1282 1283
	const char *login_string;
	const char *str;
1284
	char *tmp;
1285

1286 1287
	if (entry == NULL)
		return;
Martin Peterson's avatar
Martin Peterson committed
1288

1289
	gtk_widget_set_sensitive (entry, FALSE);
1290
	gtk_widget_set_sensitive (ok_button, FALSE);
1291
	gtk_widget_set_sensitive (cancel_button, FALSE);
1292

1293
	login_string = gtk_entry_get_text (GTK_ENTRY (entry));
1294

1295 1296 1297 1298 1299 1300 1301 1302 1303
	str = gtk_label_get_text (GTK_LABEL (label));
	if (str != NULL &&
	    (strcmp (str, _("Username:")) == 0 ||
	     strcmp (str, _("_Username:")) == 0) &&
	    /* If in timed login mode, and if this is the login
	     * entry.  Then an enter by itself is sort of like I want to
	     * log in as the timed user "damn it".  */
	    ve_string_empty (login_string) &&
	    timed_handler_id != 0) {
1304
		/* timed interruption */
1305 1306
		printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN);
		fflush (stdout);
1307
		return;
1308 1309
	}

1310
	if (str != NULL &&
1311 1312
	    (strcmp (str, _("Username:")) == 0 ||
	     strcmp (str, _("_Username:")) == 0) &&
1313 1314 1315 1316 1317 1318
	    /* evilness */
	    evil (login_string)) {
		/* obviously being 100% reliable is not an issue for
		   this test */
		gtk_widget_set_sensitive (entry, TRUE);
		gtk_widget_set_sensitive (ok_button, TRUE);
1319
		gtk_widget_set_sensitive (cancel_button, FALSE);
1320 1321 1322
		gtk_widget_grab_focus (entry);	
		gtk_window_set_focus (GTK_WINDOW (login), entry);	
		return;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1323 1324
	}

1325 1326
	/* clear the err_box */
	if (err_box_clear_handler > 0)
1327
		g_source_remove (err_box_clear_handler);
1328
	err_box_clear_handler = 0;
1329
	gtk_label_set_text (GTK_LABEL (err_box), "");
1330

1331
	tmp = ve_locale_from_utf8 (gtk_entry_get_text (GTK_ENTRY (entry)));
1332
	printf ("%c%s\n", STX, tmp);
1333
	fflush (stdout);
1334
	g_free (tmp);
1335 1336 1337 1338 1339 1340 1341 1342
}

static void
gdm_login_ok_button_press (GtkButton *button, GtkWidget *entry)
{
	gdm_login_enter (entry);
}

1343 1344 1345 1346