diff options
author | Brian Cameron <bcameron@src.gnome.org> | 2007-05-14 02:05:04 +0000 |
---|---|---|
committer | Brian Cameron <bcameron@src.gnome.org> | 2007-05-14 02:05:04 +0000 |
commit | 9cc46d1815650cf479f2b513d905e1aefa46a82c (patch) | |
tree | 5d02f5d3b659f6f242f744763a571bc06642f109 /trunk/gui/greeter | |
parent | 27ec7d8d3e9fdb00663dc26d57075e24fcadaa08 (diff) | |
download | gdm-9cc46d1815650cf479f2b513d905e1aefa46a82c.tar.gz |
Tagged for release 2.19.1
svn path=/tags/GDM2_2_19_1/; revision=4918
Diffstat (limited to 'trunk/gui/greeter')
64 files changed, 10358 insertions, 0 deletions
diff --git a/trunk/gui/greeter/.cvsignore b/trunk/gui/greeter/.cvsignore new file mode 100644 index 00000000..7db66fb3 --- /dev/null +++ b/trunk/gui/greeter/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +gdmgreeter +.deps +.libs +gdmthemetester diff --git a/trunk/gui/greeter/Makefile.am b/trunk/gui/greeter/Makefile.am new file mode 100644 index 00000000..efcbc5f6 --- /dev/null +++ b/trunk/gui/greeter/Makefile.am @@ -0,0 +1,96 @@ +SUBDIRS = . themes + +## Process this file with automake to produce makefile.in +INCLUDES = \ + -I. \ + -I$(top_srcdir)/gui \ + -I$(top_srcdir)/daemon \ + -I$(top_srcdir)/common \ + -DAUTHDIR=\""$(authdir)"\" \ + -DDATADIR=\""$(datadir)"\" \ + -DDMCONFDIR=\""$(dmconfdir)"\" \ + -DGDM_CONFIG_FILE=\"$(gdmconfdir)/gdm.conf\" \ + -DGDMLOCALEDIR=\""$(gdmlocaledir)"\" \ + -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DSBINDIR=\""$(sbindir)"\" \ + -DPIXMAPDIR=\""$(pixmapdir)"\" \ + $(GUI_CFLAGS) \ + $(PANGO_CFLAGS) \ + $(PANGOFT_CFLAGS) \ + $(GREETER_CFLAGS) + +# +# -DG_DISABLE_DEPRECATED \ +# -DGDK_DISABLE_DEPRECATED \ +# -DGDK_PIXBUF_DISABLE_DEPRECATED \ +# -DGTK_DISABLE_DEPRECATED \ +# -DGNOME_DISABLE_DEPRECATED \ +# + +libexec_PROGRAMS = \ + gdmgreeter + +bin_SCRIPTS = \ + gdmthemetester + +CLEANFILES = gdmthemetester + +gdmthemetester: $(srcdir)/gdmthemetester.in + sed -e 's,[@]libexecdir[@],$(libexecdir),g' \ + <$(srcdir)/gdmthemetester.in >gdmthemetester + +gdmgreeter_SOURCES = \ + greeter.c \ + greeter.h \ + greeter_canvas_text.c \ + greeter_canvas_text.h \ + greeter_canvas_item.c \ + greeter_canvas_item.h \ + greeter_configuration.h \ + greeter_events.c \ + greeter_events.h \ + greeter_geometry.c \ + greeter_geometry.h \ + greeter_item.c \ + greeter_item_timed.c \ + greeter_item_timed.h \ + greeter_item_capslock.c \ + greeter_item_capslock.h \ + greeter_item_clock.c \ + greeter_item_clock.h \ + greeter_item.h \ + greeter_item_pam.c \ + greeter_item_pam.h \ + greeter_item_ulist.c \ + greeter_item_ulist.h \ + greeter_item_customlist.c \ + greeter_item_customlist.h \ + greeter_parser.c \ + greeter_parser.h \ + greeter_session.c \ + greeter_session.h \ + greeter_system.c \ + greeter_system.h + +gdmgreeter_LDADD = \ + $(EXTRA_GREETER_LIBS) \ + -L$(top_builddir)/gui \ + -lgdmwm \ + -lgdmcommon \ + $(top_builddir)/common/libgdmcommon.a \ + $(GLIB_LIBS) \ + $(GOBJECT_LIBS) \ + $(PANGO_LIBS) \ + $(PANGOFT_LIBS) \ + $(GDK_LIBS) \ + $(GDKPIXBUF_LIBS) \ + $(GREETER_LIBS) \ + $(X_EXTRA_LIBS) \ + $(XINERAMA_LIBS) \ + $(X_LIBS) \ + -lX11 + +EXTRA_DIST = \ + gdmthemetester.in \ + greeter.dtd diff --git a/trunk/gui/greeter/gdmthemetester.in b/trunk/gui/greeter/gdmthemetester.in new file mode 100755 index 00000000..139e1e01 --- /dev/null +++ b/trunk/gui/greeter/gdmthemetester.in @@ -0,0 +1,109 @@ +#!/bin/sh + +gdmwhich () { + COMMAND="$1" + OUTPUT= + IFS=: + for dir in $PATH + do + if test -x "$dir/$COMMAND" ; then + if test "x$OUTPUT" = "x" ; then + OUTPUT="$dir/$COMMAND" + fi + fi + done + IFS=$OLD_IFS + echo "$OUTPUT" +} + +echo +echo "GDM Theme Tester" +echo +echo "Be sure to test all the environments:" +echo " console, console-timed, flexi, remote-flexi, xdmcp" +echo "Also be sure to test using caps lock" +echo + +XNEST=`gdmwhich Xnest` +GDMXNEST=`gdmwhich gdmXnest` +GDMGREETER="@libexecdir@/gdmgreeter" + +if [ x$XNEST = x ]; then + echo "ERROR: Xnest not found" + echo "" + exit 1 +fi + +if [ x$GDMXNEST = x ]; then + echo "ERROR: gdmXnest not found" + echo "" + exit 1 +fi + +if [ x$GDMGREETER = x ]; then + echo "ERROR: gdmgreeter not found" + echo "" + exit 1 +fi + +USAGE=" +Usage: $0 <environment> <theme> +<environment> is one of: console, console-timed, flexi, remote-flexi, xdmcp +<theme> is either the path of the theme or the name of an installed theme + +If you set the environment variable XNESTSIZE to <width>x<height> (e.g. 800x600) +you can test the greeter at that resolution +" +if [ "$#" != 2 ]; then + echo "$USAGE" + exit 1 +fi + +GDM_THEME="$2" +DOING_GDM_DEVELOPMENT=yes +GDM_PARENT_DISPLAY="$DISPLAY" +export GDM_THEME DOING_GDM_DEVELOPMENT GDM_PARENT_DISPLAY + +case $1 in +console) + GDM_IS_LOCAL=yes + export GDM_IS_LOCAL + ;; +console-timed) + GDM_IS_LOCAL=yes + GDM_FAKE_TIMED=yes + export GDM_IS_LOCAL GDM_FAKE_TIMED + ;; +flexi) + GDM_IS_LOCAL=yes + GDM_FLEXI_SERVER=yes + export GDM_IS_LOCAL GDM_FLEXI_SERVER + ;; +remote-flexi) + GDM_FLEXI_SERVER=yes + export GDM_FLEXI_SERVER + ;; +xdmcp) + ;; +*) + echo "$USAGE" + exit 1 + ;; +esac + +if [ "x$XNESTSIZE" = x ] ; then + eval `gdmXnest -b` +else + eval `gdmXnest -b -o "-geometry $XNESTSIZE"` +fi +export DISPLAY + +if [ "x$GDM_PARENT_DISPLAY" = "x$DISPLAY" ]; then + echo "ERROR: Can't start the Xnest server" + exit 1 +fi + +# This may not be necessary +sleep 1 + +@libexecdir@/gdmgreeter diff --git a/trunk/gui/greeter/greeter.c b/trunk/gui/greeter/greeter.c new file mode 100644 index 00000000..47c26722 --- /dev/null +++ b/trunk/gui/greeter/greeter.c @@ -0,0 +1,1681 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <libintl.h> +#include <locale.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> + +#if HAVE_PAM +#include <security/pam_appl.h> +#define PW_ENTRY_SIZE PAM_MAX_RESP_SIZE +#else +#define PW_ENTRY_SIZE GDM_MAX_PASS +#endif + +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <libgnomecanvas/libgnomecanvas.h> + +#include "gdm-common.h" +#include "gdm-socket-protocol.h" +#include "gdm-daemon-config-keys.h" + +#include "gdm.h" +#include "gdmwm.h" +#include "gdmcomm.h" +#include "gdmcommon.h" +#include "gdmconfig.h" +#include "gdmsession.h" +#include "gdmlanguages.h" + +#include "greeter.h" +#include "greeter_configuration.h" +#include "greeter_parser.h" +#include "greeter_geometry.h" +#include "greeter_item_clock.h" +#include "greeter_item_pam.h" +#include "greeter_item_ulist.h" +#include "greeter_item_customlist.h" +#include "greeter_item_capslock.h" +#include "greeter_item_timed.h" +#include "greeter_events.h" +#include "greeter_session.h" +#include "greeter_system.h" + +gboolean DOING_GDM_DEVELOPMENT = FALSE; + +GtkWidget *window; +GtkWidget *canvas; + +gboolean GDM_IS_LOCAL = FALSE; +static gboolean ignore_buttons = FALSE; +gboolean GdmHaltFound = FALSE; +gboolean GdmRebootFound = FALSE; +gboolean *GdmCustomCmdsFound = NULL; +gboolean GdmAnyCustomCmdsFound = FALSE; +gboolean GdmSuspendFound = FALSE; +gboolean GdmConfiguratorFound = FALSE; + +/* FIXME: hack */ +GreeterItemInfo *welcome_string_info = NULL; +GreeterItemInfo *root = NULL; + +extern gboolean session_dir_whacked_out; +extern gboolean require_quarter; +extern gint gdm_timed_delay; +extern GtkButton *gtk_ok_button; +extern GtkButton *gtk_start_again_button; + +gboolean greeter_probably_login_prompt = FALSE; +static gboolean first_prompt = TRUE; + +static void process_operation (guchar opcode, const gchar *args); + +void +greeter_ignore_buttons (gboolean val) +{ + ignore_buttons = val; +} + +static char *get_theme_file (const char *in, char **theme_dir); + +/* If in random theme mode then grab a random theme from those selected. + * If a theme doesn't exist, try the rest of the list from the randomly chosen + * position for one that does. + */ +static char * +get_random_theme () +{ + char **vec; + char *themes_list; + char *theme = NULL; + char *dir; + int size; + int chosen; + int i; + + themes_list = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMES); + + if (ve_string_empty (themes_list)) + return NULL; + + vec = g_strsplit (themes_list, GDM_DELIMITER_THEMES, -1); + if (vec == NULL) + return NULL; + + /* Get Number of elements in vector */ + for (size = 0; vec[size] != NULL; size++) {} + + /* Get Random Theme from list */ + srand ( time(NULL) ); + chosen = rand() % size; + + /* Find a theme that exists */ + for (i = 0; i < size; i++) { + int j; + char *file; + + j = (i + chosen >= size) ? i+chosen-size : i+chosen; + file = get_theme_file( vec[j], &dir ); + + g_free(file); + if (g_file_test(dir, G_FILE_TEST_IS_DIR)) { + g_free(dir); + theme = g_strdup (vec[j]); + break; + } + g_free(dir); + } + + g_strfreev (vec); + + return theme; +} + +static gboolean +greeter_ctrl_handler (GIOChannel *source, + GIOCondition cond, + gint fd) +{ + gchar buf[PIPE_SIZE]; + gchar *p; + gsize len; + + /* If this is not incoming i/o then return */ + if (cond != G_IO_IN) + return TRUE; + + /* Read random garbage from i/o channel until first STX is found */ + do { + g_io_channel_read_chars (source, buf, 1, &len, NULL); + + if (len != 1) + return TRUE; + } while (buf[0] && buf[0] != STX); + + memset (buf, '\0', sizeof (buf)); + if (g_io_channel_read_chars (source, buf, sizeof (buf) - 1, &len, NULL) != + G_IO_STATUS_NORMAL) + return TRUE; + + p = memchr (buf, STX, len); + if (p != NULL) { + len = p - buf; + g_io_channel_seek_position (source, -((sizeof (buf) - 1) - len), G_SEEK_CUR, NULL); + memset (buf + len, '\0', (sizeof (buf) - 1) - len); + } + buf[len - 1] = '\0'; + + process_operation ((guchar) buf[0], buf + 1); + return TRUE; +} + +static GtkWidget * +hig_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GtkMessageType type, + GtkButtonsType buttons, + const gchar *primary_message, + const gchar *secondary_message) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + buttons, + "%s", primary_message); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary_message); + + gtk_window_set_title (GTK_WINDOW (dialog), ""); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14); + + return dialog; +} + +static void +process_operation (guchar op_code, + const gchar *args) +{ + GtkWidget *dlg; + char *tmp; + char *session; + GreeterItemInfo *conversation_info; + static GnomeCanvasItem *disabled_cover = NULL; + gint lookup_status = SESSION_LOOKUP_SUCCESS; + gchar *firstmsg = NULL; + gchar *secondmsg = NULL; + gint save_session = GTK_RESPONSE_NO; + + /* Parse opcode */ + switch (op_code) { + case GDM_SETLOGIN: + /* somebody is trying to fool us this is the user that + * wants to log in, and well, we are the gullible kind */ + + greeter_item_pam_set_user (args); + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_PROMPT: + tmp = ve_locale_to_utf8 (args); + if (tmp != NULL && strcmp (tmp, _("Username:")) == 0) { + gdm_common_login_sound (gdm_config_get_string (GDM_KEY_SOUND_PROGRAM), + gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE), + gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN)); + greeter_probably_login_prompt = TRUE; + } + if (gtk_ok_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE); + + if (gtk_start_again_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), !first_prompt); + + first_prompt = FALSE; + + greeter_ignore_buttons (FALSE); + + greeter_item_pam_prompt (tmp, PW_ENTRY_SIZE, TRUE); + g_free (tmp); + break; + + case GDM_NOECHO: + tmp = ve_locale_to_utf8 (args); + + greeter_probably_login_prompt = FALSE; + + if (gtk_ok_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE); + + if (gtk_start_again_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), !first_prompt); + + first_prompt = FALSE; + + greeter_ignore_buttons (FALSE); + greeter_item_pam_prompt (tmp, PW_ENTRY_SIZE, FALSE); + g_free (tmp); + + break; + + case GDM_MSG: + tmp = ve_locale_to_utf8 (args); + greeter_item_pam_message (tmp); + g_free (tmp); + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_ERRBOX: + tmp = ve_locale_to_utf8 (args); + greeter_item_pam_error (tmp); + g_free (tmp); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_ERRDLG: + /* we should be now fine for focusing new windows */ + gdm_wm_focus_new_windows (TRUE); + + tmp = ve_locale_to_utf8 (args); + dlg = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + tmp, + ""); + g_free (tmp); + + gdm_wm_center_window (GTK_WINDOW (dlg)); + + gdm_wm_no_login_focus_push (); + gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); + gdm_wm_no_login_focus_pop (); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_SESS: + tmp = ve_locale_to_utf8 (args); + session = gdm_session_lookup (tmp, &lookup_status); + if (lookup_status != SESSION_LOOKUP_SUCCESS) { + switch (lookup_status) { + case SESSION_LOOKUP_PREFERRED_MISSING: + firstmsg = g_strdup_printf (_("Do you wish to make %s the default for " + "future sessions?"), + gdm_session_name (tmp)); + secondmsg = g_strdup_printf (_("Your preferred session type %s is not " + "installed on this computer."), + gdm_session_name (gdm_get_default_session ())); + save_session = gdm_wm_query_dialog (firstmsg, secondmsg, + _("Make _Default"), _("Just _Log In"), TRUE); + + g_free (firstmsg); + g_free (secondmsg); + gdm_set_save_session (save_session); + break; + + case SESSION_LOOKUP_DEFAULT_MISMATCH: + firstmsg = g_strdup_printf (_("Do you wish to make %s the default for " + "future sessions?"), + gdm_session_name (session)); + secondmsg = g_strdup_printf (_("You have chosen %s for this " + "session, but your default " + "setting is %s."), + gdm_session_name (session), + gdm_session_name (tmp)); + save_session = gdm_wm_query_dialog (firstmsg, secondmsg, + _("Make _Default"), _("Just For _This Session"), TRUE); + + g_free (firstmsg); + g_free (secondmsg); + gdm_set_save_session (save_session); + break; + case SESSION_LOOKUP_USE_SWITCHDESK: + firstmsg = g_strdup_printf (_("You have chosen %s for this " + "session"), + gdm_session_name (session)); + secondmsg = g_strdup_printf (_("If you wish to make %s " + "the default for future sessions, " + "run the 'switchdesk' utility " + "(System->Desktop Switching Tool from " + "the panel menu)."), + gdm_session_name (session)); + gdm_wm_message_dialog (firstmsg, secondmsg); + g_free (firstmsg); + g_free (secondmsg); + break; + + default: + break; + } + } + g_free (tmp); + if (gdm_get_save_session () == GTK_RESPONSE_CANCEL) { + printf ("%c%s\n", STX, GDM_RESPONSE_CANCEL); + } else { + tmp = ve_locale_from_utf8 (session); + printf ("%c%s\n", STX, tmp); + g_free (tmp); + } + fflush (stdout); + g_free (session); + break; + + case GDM_LANG: + gdm_lang_op_lang (args); + break; + + case GDM_SSESS: + if (gdm_get_save_session () == GTK_RESPONSE_YES) + printf ("%cY\n", STX); + else + printf ("%c\n", STX); + fflush (stdout); + + break; + + case GDM_SLANG: + gdm_lang_op_slang (args); + break; + + case GDM_SETLANG: + gdm_lang_op_setlang (args); + break; + + case GDM_ALWAYS_RESTART: + gdm_lang_op_always_restart (args); + break; + + case GDM_RESET: + /* fall thru to reset */ + + case GDM_RESETOK: + + if (gtk_ok_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE); + if (gtk_start_again_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), FALSE); + + first_prompt = TRUE; + + conversation_info = greeter_lookup_id ("pam-conversation"); + + if (conversation_info) + { + tmp = ve_locale_to_utf8 (args); + g_object_set (G_OBJECT (conversation_info->item), + "text", tmp, + NULL); + g_free (tmp); + } + + printf ("%c\n", STX); + fflush (stdout); + greeter_ignore_buttons (FALSE); + greeter_item_ulist_enable (); + + break; + + case GDM_QUIT: + greeter_item_timed_stop (); + + if (require_quarter) { + /* we should be now fine for focusing new windows */ + gdm_wm_focus_new_windows (TRUE); + + dlg = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + /* translators: This is a nice and evil eggie text, translate + * to your favourite currency */ + _("Please insert 25 cents " + "to log in."), + ""); + gdm_wm_center_window (GTK_WINDOW (dlg)); + + gdm_wm_no_login_focus_push (); + gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); + gdm_wm_no_login_focus_pop (); + } + + greeter_item_pam_leftover_messages (); + + gdk_flush (); + + if (greeter_show_only_background (root)) { + GdkPixbuf *background; + int width, height; + + gtk_window_get_size (GTK_WINDOW (window), &width, &height); + background = gdk_pixbuf_get_from_drawable (NULL, gtk_widget_get_root_window(window), NULL, 0, 0, 0, 0 ,width, height); + if (background) { + gdm_common_set_root_background (background); + g_object_unref (background); + } + } + + printf ("%c\n", STX); + fflush (stdout); + + /* screw gtk_main_quit, we want to make sure we definately die */ + _exit (EXIT_SUCCESS); + break; + + case GDM_STARTTIMER: + greeter_item_timed_start (); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_STOPTIMER: + greeter_item_timed_stop (); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_DISABLE: + gtk_widget_set_sensitive (window, FALSE); + + if (disabled_cover == NULL) + { + disabled_cover = gnome_canvas_item_new + (gnome_canvas_root (GNOME_CANVAS (canvas)), + GNOME_TYPE_CANVAS_RECT, + "x1", 0.0, + "y1", 0.0, + "x2", (double)canvas->allocation.width, + "y2", (double)canvas->allocation.height, + "fill_color_rgba", (guint)0x00000088, + NULL); + } + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_ENABLE: + gtk_widget_set_sensitive (window, TRUE); + + if (disabled_cover != NULL) + { + gtk_object_destroy (GTK_OBJECT (disabled_cover)); + disabled_cover = NULL; + } + + printf ("%c\n", STX); + fflush (stdout); + break; + + /* These are handled separately so ignore them here and send + * back a NULL response so that the daemon quits sending them */ + case GDM_NEEDPIC: + case GDM_READPIC: + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_NOFOCUS: + gdm_wm_no_login_focus_push (); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_FOCUS: + gdm_wm_no_login_focus_pop (); + + printf ("%c\n", STX); + fflush (stdout); + break; + + case GDM_SAVEDIE: + /* Set busy cursor */ + gdm_common_setup_cursor (GDK_WATCH); + + gdm_wm_save_wm_order (); + + gdk_flush (); + + _exit (EXIT_SUCCESS); + + case GDM_QUERY_CAPSLOCK: + if (greeter_is_capslock_on ()) + printf ("%cY\n", STX); + else + printf ("%c\n", STX); + fflush (stdout); + + break; + + default: + gdm_common_fail_greeter ("Unexpected greeter command received: '%c'", op_code); + break; + } +} + +static gboolean +key_press_event (GtkWidget *widget, GdkEventKey *key, gpointer data) +{ + if (DOING_GDM_DEVELOPMENT && (key->keyval == GDK_Escape)) + { + process_operation (GDM_QUIT, NULL); + + return TRUE; + } + + return FALSE; +} + +/* + * The buttons with these handlers never appear in the F10 menu, + * so they can make use of callback data. + */ +static void +greeter_ok_handler (GreeterItemInfo *info, + gpointer user_data) +{ + if (ignore_buttons == FALSE) + { + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + GtkWidget *entry; + entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + greeter_ignore_buttons (TRUE); + greeter_item_pam_login (GTK_ENTRY (entry), entry_info); + } + } +} + +static void +greeter_cancel_handler (GreeterItemInfo *info, + gpointer user_data) +{ + if (ignore_buttons == FALSE) + { + greeter_item_ulist_unset_selected_user (); + greeter_item_ulist_disable (); + greeter_ignore_buttons (TRUE); + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_CANCEL); + fflush (stdout); + } +} + +static void +greeter_language_handler (GreeterItemInfo *info, + gpointer user_data) +{ + gdm_lang_handler (user_data); +} + +static void +greeter_setup_items (void) +{ + greeter_item_clock_setup (); + greeter_item_pam_setup (); + + /* This will query the daemon for pictures through stdin/stdout! */ + greeter_item_ulist_setup (); + + greeter_item_capslock_setup (window); + greeter_item_timed_setup (); + greeter_item_register_action_callback ("ok_button", + greeter_ok_handler, + (gpointer) window); + greeter_item_register_action_callback ("cancel_button", + greeter_cancel_handler, + (gpointer) window); + greeter_item_register_action_callback ("language_button", + greeter_language_handler, + NULL); + greeter_item_register_action_callback ("disconnect_button", + (ActionFunc)gtk_main_quit, + NULL); + greeter_item_system_setup (); + greeter_item_session_setup (); + + /* Setup the custom widgets */ + greeter_item_customlist_setup (); +} + +enum { + RESPONSE_RESTART, + RESPONSE_REBOOT, + RESPONSE_CLOSE +}; + +static int +verify_gdm_version (void) +{ + const char *gdm_version; + const char *gdm_protocol_version; + + gdm_version = g_getenv ("GDM_VERSION"); + gdm_protocol_version = g_getenv ("GDM_GREETER_PROTOCOL_VERSION"); + + if (! DOING_GDM_DEVELOPMENT && + ((gdm_protocol_version != NULL && + strcmp (gdm_protocol_version, GDM_GREETER_PROTOCOL_VERSION) != 0) || + (gdm_protocol_version == NULL && + (gdm_version == NULL || + strcmp (gdm_version, VERSION) != 0))) && + (g_getenv ("GDM_IS_LOCAL") != NULL)) + { + GtkWidget *dialog; + gchar *msg; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon " + "version. " + "You have probably just upgraded GDM. " + "Please restart the GDM daemon or the computer."), + VERSION); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Cannot start the greeter"), + msg); + g_free (msg); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return EXIT_SUCCESS; + } + + if (! DOING_GDM_DEVELOPMENT && + gdm_protocol_version == NULL && + gdm_version == NULL) + { + GtkWidget *dialog; + gchar *msg; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon " + "version. " + "You have probably just upgraded GDM. " + "Please restart the GDM daemon or the computer."), + VERSION); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Cannot start the greeter"), + msg); + g_free (msg); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("Restart Machine"), + RESPONSE_REBOOT, + GTK_STOCK_CLOSE, + RESPONSE_CLOSE, + NULL); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + switch (gtk_dialog_run (GTK_DIALOG (dialog))) + { + case RESPONSE_REBOOT: + gtk_widget_destroy (dialog); + return DISPLAY_REBOOT; + default: + gtk_widget_destroy (dialog); + return DISPLAY_ABORT; + } + } + + if (! DOING_GDM_DEVELOPMENT && + ((gdm_protocol_version != NULL && + strcmp (gdm_protocol_version, GDM_GREETER_PROTOCOL_VERSION) != 0) || + (gdm_protocol_version == NULL && + strcmp (gdm_version, VERSION) != 0))) + { + GtkWidget *dialog; + gchar *msg; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon " + "version (%s). " + "You have probably just upgraded GDM. " + "Please restart the GDM daemon or the computer."), + VERSION, gdm_version); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Cannot start the greeter"), + msg); + g_free (msg); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("Restart GDM"), + RESPONSE_RESTART, + _("Restart Machine"), + RESPONSE_REBOOT, + GTK_STOCK_CLOSE, + RESPONSE_CLOSE, + NULL); + + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), RESPONSE_RESTART); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + switch (gtk_dialog_run (GTK_DIALOG (dialog))) + { + case RESPONSE_RESTART: + gtk_widget_destroy (dialog); + return DISPLAY_RESTARTGDM; + case RESPONSE_REBOOT: + gtk_widget_destroy (dialog); + return DISPLAY_REBOOT; + default: + gtk_widget_destroy (dialog); + return DISPLAY_ABORT; + } + } + + return 0; +} + +static void +gdm_set_welcomemsg (void) +{ + char *welcomemsg = gdm_common_get_welcomemsg (); + + if (welcome_string_info->data.text.orig_text != NULL) + g_free (welcome_string_info->data.text.orig_text); + + welcome_string_info->data.text.orig_text = welcomemsg; + greeter_item_update_text (welcome_string_info); +} + +/* + * If new configuration keys are added to this program, make sure to add the + * key to the gdm_read_config and gdm_reread_config functions. Note if the + * number of configuration values used by gdmlogin is greater than + * GDM_SUP_MAX_MESSAGES defined in daemon/gdm.h (currently defined to be 80), + * consider bumping that number so that all the config can be read in one + * socket connection. + */ +static void +gdm_read_config (void) +{ + gint i; + + /* Read config data in bulk */ + gdmcomm_comm_bulk_start (); + + /* + * Read all the keys at once and close sockets connection so we do + * not have to keep the socket open. + */ + gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME); + gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMES); + gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME_DIR); + gdm_config_get_string (GDM_KEY_GTKRC); + gdm_config_get_string (GDM_KEY_GTK_THEME); + gdm_config_get_string (GDM_KEY_INCLUDE); + gdm_config_get_string (GDM_KEY_EXCLUDE); + gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR); + gdm_config_get_string (GDM_KEY_LOCALE_FILE); + gdm_config_get_string (GDM_KEY_HALT); + gdm_config_get_string (GDM_KEY_REBOOT); + gdm_config_get_string (GDM_KEY_SUSPEND); + gdm_config_get_string (GDM_KEY_CONFIGURATOR); + gdm_config_get_string (GDM_KEY_INFO_MSG_FILE); + gdm_config_get_string (GDM_KEY_INFO_MSG_FONT); + gdm_config_get_string (GDM_KEY_TIMED_LOGIN); + gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMED_COLOR); + gdm_config_get_string (GDM_KEY_BACKGROUND_COLOR); + gdm_config_get_string (GDM_KEY_DEFAULT_FACE); + gdm_config_get_string (GDM_KEY_DEFAULT_SESSION); + gdm_config_get_string (GDM_KEY_SOUND_PROGRAM); + gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE); + gdm_config_get_string (GDM_KEY_USE_24_CLOCK); + gdm_config_get_string (GDM_KEY_WELCOME); + gdm_config_get_string (GDM_KEY_REMOTE_WELCOME); + gdm_config_get_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS); + gdm_config_get_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU); + + gdm_config_get_int (GDM_KEY_XINERAMA_SCREEN); + gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY); + gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES); + gdm_config_get_int (GDM_KEY_MAX_ICON_HEIGHT); + gdm_config_get_int (GDM_KEY_MAX_ICON_WIDTH); + gdm_config_get_int (GDM_KEY_MINIMAL_UID); + gdm_config_get_bool (GDM_KEY_ENTRY_CIRCLES); + gdm_config_get_bool (GDM_KEY_ENTRY_INVISIBLE); + gdm_config_get_bool (GDM_KEY_SHOW_XTERM_FAILSAFE); + gdm_config_get_bool (GDM_KEY_SHOW_GNOME_FAILSAFE); + gdm_config_get_bool (GDM_KEY_INCLUDE_ALL); + gdm_config_get_bool (GDM_KEY_SYSTEM_MENU); + gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE); + gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON); + gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE); + gdm_config_get_bool (GDM_KEY_GRAPHICAL_THEME_RAND); + gdm_config_get_bool (GDM_KEY_SHOW_LAST_SESSION); + gdm_config_get_bool (GDM_KEY_ALLOW_ROOT); + gdm_config_get_bool (GDM_KEY_ALLOW_REMOTE_ROOT); + gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN); + gdm_config_get_bool (GDM_KEY_DEFAULT_WELCOME); + gdm_config_get_bool (GDM_KEY_DEFAULT_REMOTE_WELCOME); + gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES); + gdm_config_get_bool (GDM_KEY_BROWSER); + + /* Keys for custom commands */ + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gchar * key_string = NULL; + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i); + gdm_config_get_string (key_string); + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i); + gdm_config_get_string (key_string); + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i); + gdm_config_get_string (key_string); + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i); + gdm_config_get_string (key_string); + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i); + gdm_config_get_string (key_string); + + g_free (key_string); + } + + /* Keys not to include in reread_config */ + gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR); + gdm_config_get_string (GDM_KEY_PRE_FETCH_PROGRAM); + + gdmcomm_comm_bulk_stop (); +} + +static gboolean +greeter_reread_config (int sig, gpointer data) +{ + gint i; + gboolean custom_changed = FALSE; + + /* Read config data in bulk */ + gdmcomm_comm_bulk_start (); + + /* FIXME: The following is evil, we should update on the fly rather + * then just restarting */ + /* Also we may not need to check ALL those keys but just a few */ + if (gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEME) || + gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEMES) || + gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEME_DIR) || + gdm_config_reload_string (GDM_KEY_GTKRC) || + gdm_config_reload_string (GDM_KEY_GTK_THEME) || + gdm_config_reload_string (GDM_KEY_INCLUDE) || + gdm_config_reload_string (GDM_KEY_EXCLUDE) || + gdm_config_reload_string (GDM_KEY_SESSION_DESKTOP_DIR) || + gdm_config_reload_string (GDM_KEY_LOCALE_FILE) || + gdm_config_reload_string (GDM_KEY_HALT) || + gdm_config_reload_string (GDM_KEY_REBOOT) || + gdm_config_reload_string (GDM_KEY_SUSPEND) || + gdm_config_reload_string (GDM_KEY_CONFIGURATOR) || + gdm_config_reload_string (GDM_KEY_INFO_MSG_FILE) || + gdm_config_reload_string (GDM_KEY_INFO_MSG_FONT) || + gdm_config_reload_string (GDM_KEY_TIMED_LOGIN) || + gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEMED_COLOR) || + gdm_config_reload_string (GDM_KEY_BACKGROUND_COLOR) || + gdm_config_reload_string (GDM_KEY_DEFAULT_FACE) || + gdm_config_reload_string (GDM_KEY_DEFAULT_SESSION) || + gdm_config_reload_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS) || + gdm_config_reload_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU) || + + gdm_config_reload_int (GDM_KEY_XINERAMA_SCREEN) || + gdm_config_reload_int (GDM_KEY_TIMED_LOGIN_DELAY) || + gdm_config_reload_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES) || + gdm_config_reload_int (GDM_KEY_MAX_ICON_HEIGHT) || + gdm_config_reload_int (GDM_KEY_MAX_ICON_WIDTH) || + gdm_config_reload_int (GDM_KEY_MINIMAL_UID) || + + gdm_config_reload_bool (GDM_KEY_ENTRY_CIRCLES) || + gdm_config_reload_bool (GDM_KEY_ENTRY_INVISIBLE) || + gdm_config_reload_bool (GDM_KEY_SHOW_XTERM_FAILSAFE) || + gdm_config_reload_bool (GDM_KEY_SHOW_GNOME_FAILSAFE) || + gdm_config_reload_bool (GDM_KEY_INCLUDE_ALL) || + gdm_config_reload_bool (GDM_KEY_SYSTEM_MENU) || + gdm_config_reload_bool (GDM_KEY_CONFIG_AVAILABLE) || + gdm_config_reload_bool (GDM_KEY_CHOOSER_BUTTON) || + gdm_config_reload_bool (GDM_KEY_TIMED_LOGIN_ENABLE) || + gdm_config_reload_bool (GDM_KEY_GRAPHICAL_THEME_RAND) || + gdm_config_reload_bool (GDM_KEY_SHOW_LAST_SESSION) || + gdm_config_reload_bool (GDM_KEY_ALLOW_ROOT) || + gdm_config_reload_bool (GDM_KEY_ALLOW_REMOTE_ROOT) || + gdm_config_reload_bool (GDM_KEY_ADD_GTK_MODULES) || + gdm_config_reload_bool (GDM_KEY_BROWSER)) { + + /* Set busy cursor */ + gdm_common_setup_cursor (GDK_WATCH); + + gdm_wm_save_wm_order (); + gdmcomm_comm_bulk_stop (); + + _exit (DISPLAY_RESTARTGREETER); + } + + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gchar *key_string = NULL; + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i); + if (gdm_config_reload_string (key_string)) + custom_changed = TRUE; + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i); + if (gdm_config_reload_string (key_string)) + custom_changed = TRUE; + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i); + if (gdm_config_reload_string (key_string)) + custom_changed = TRUE; + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i); + if (gdm_config_reload_string (key_string)) + custom_changed = TRUE; + + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i); + if (gdm_config_reload_string (key_string)) + custom_changed = TRUE; + + g_free (key_string); + } + + if(custom_changed){ + /* Set busy cursor */ + gdm_common_setup_cursor (GDK_WATCH); + + gdm_wm_save_wm_order (); + gdmcomm_comm_bulk_stop (); + + _exit (DISPLAY_RESTARTGREETER); + } + + gdm_config_reload_string (GDM_KEY_SOUND_PROGRAM); + gdm_config_reload_bool (GDM_KEY_SOUND_ON_LOGIN); + gdm_config_reload_string (GDM_KEY_SOUND_ON_LOGIN_FILE); + gdm_config_reload_string (GDM_KEY_USE_24_CLOCK); + + if (gdm_config_reload_string (GDM_KEY_WELCOME) || + gdm_config_reload_bool (GDM_KEY_DEFAULT_WELCOME) || + gdm_config_reload_string (GDM_KEY_REMOTE_WELCOME) || + gdm_config_reload_bool (GDM_KEY_DEFAULT_REMOTE_WELCOME)) { + + gdm_set_welcomemsg (); + + /* Set busy cursor */ + gdm_common_setup_cursor (GDK_WATCH); + + gdm_wm_save_wm_order (); + gdmcomm_comm_bulk_stop (); + + _exit (DISPLAY_RESTARTGREETER); + } + + gdmcomm_comm_bulk_stop (); + + return TRUE; +} + +static void +greeter_done (int sig) +{ + _exit (EXIT_SUCCESS); +} + + +static char * +get_theme_file (const char *in, char **theme_dir) +{ + char *file, *dir, *info, *s; + + if (in == NULL) + in = "circles"; + + *theme_dir = NULL; + + if (g_path_is_absolute (in)) + { + dir = g_strdup (in); + } + else + { + dir = NULL; + if (DOING_GDM_DEVELOPMENT) + { + if (g_access (in, F_OK) == 0) + { + dir = g_strdup (in); + } + else + { + dir = g_build_filename ("themes", in, NULL); + if (g_access (dir, F_OK) != 0) + { + g_free (dir); + dir = NULL; + } + } + } + if (dir == NULL) + dir = g_build_filename (gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME_DIR), in, NULL); + } + + *theme_dir = dir; + + info = g_build_filename (dir, "GdmGreeterTheme.desktop", NULL); + if (g_access (info, F_OK) != 0) { + g_free (info); + info = g_build_filename (dir, "GdmGreeterTheme.info", NULL); + } + if (g_access (info, F_OK) != 0) + { + char *base = g_path_get_basename (in); + /* just guess the name, we have no info about the theme at + * this point */ + g_free (info); + file = g_strdup_printf ("%s/%s.xml", dir, base); + g_free (base); + return file; + } + + s = gdm_get_theme_greeter (info, in); + file = g_build_filename (dir, s, NULL); + + g_free (info); + g_free (s); + + return file; +} + +/* 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; +} + +static gboolean +reap_flexiserver (gpointer data) +{ + int reapminutes = gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES); + + if (reapminutes > 0 && + ((time (NULL) - last_reap_delay) / 60) > reapminutes) { + _exit (DISPLAY_REMANAGE); + } + return TRUE; +} + +static gboolean +gdm_event (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + GdkEvent *event; + + /* 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 */ + if (n_param_values != 2 || + !G_VALUE_HOLDS (¶m_values[1], GDK_TYPE_EVENT)) + return FALSE; + + event = g_value_get_boxed (¶m_values[1]); + 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; + + /* 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)) { + + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + GtkWidget *entry; + entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + gtk_entry_set_text (GTK_ENTRY (entry), ""); + } + } + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + char *bg_color; + struct sigaction hup; + struct sigaction term; + sigset_t mask; + GIOChannel *ctrlch; + GError *error; + char *theme_file; + char *theme_dir; + gchar *gdm_graphical_theme; + const char *gdm_gtk_theme; + guint sid; + int r; + gint i; + + if (g_getenv ("DOING_GDM_DEVELOPMENT") != NULL) + DOING_GDM_DEVELOPMENT = TRUE; + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + setlocale (LC_ALL, ""); + + if (ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) + GDM_IS_LOCAL = FALSE; + else + GDM_IS_LOCAL = TRUE; + + /* + * gdm_common_atspi_launch () needs gdk initialized. + * We cannot start gtk before the registry is running + * because the atk-bridge will crash. + */ + gdk_init (&argc, &argv); + if (! DOING_GDM_DEVELOPMENT) { + gdm_common_atspi_launch (); + } + + gtk_init (&argc, &argv); + + gdm_common_setup_cursor (GDK_WATCH); + + gdm_common_log_init (); + gdm_common_log_set_debug (gdm_config_get_bool (GDM_KEY_DEBUG)); + + /* Read all configuration at once, so the values get cached */ + gdm_read_config (); + + if ( ! ve_string_empty (gdm_config_get_string (GDM_KEY_GTKRC))) + gtk_rc_parse (gdm_config_get_string (GDM_KEY_GTKRC)); + + gdm_gtk_theme = g_getenv ("GDM_GTK_THEME"); + if (ve_string_empty (gdm_gtk_theme)) + gdm_gtk_theme = gdm_config_get_string (GDM_KEY_GTK_THEME); + + if ( ! ve_string_empty (gdm_gtk_theme)) { + gdm_set_theme (gdm_gtk_theme); + } + + gdm_wm_screen_init (gdm_config_get_int (GDM_KEY_XINERAMA_SCREEN)); + + r = verify_gdm_version (); + if (r != 0) + return r; + + /* Load the background as early as possible so GDM does not leave */ + /* the background unfilled. The cursor should be a watch already */ + /* but just in case */ + bg_color = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMED_COLOR); + /* If a graphical theme color does not exist fallback to the plain color */ + if (ve_string_empty (bg_color)) { + bg_color = gdm_config_get_string (GDM_KEY_BACKGROUND_COLOR); + } + gdm_common_setup_background_color (bg_color); + greeter_session_init (); + gdm_lang_initialize_model (gdm_config_get_string (GDM_KEY_LOCALE_FILE)); + + ve_signal_add (SIGHUP, greeter_reread_config, NULL); + + hup.sa_handler = ve_signal_notify; + hup.sa_flags = 0; + sigemptyset (&hup.sa_mask); + sigaddset (&hup.sa_mask, SIGCHLD); + + if (sigaction (SIGHUP, &hup, NULL) < 0) { + gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main", + "HUP", strerror (errno)); + } + + term.sa_handler = greeter_done; + term.sa_flags = 0; + sigemptyset (&term.sa_mask); + sigaddset (&term.sa_mask, SIGCHLD); + + if G_UNLIKELY (sigaction (SIGINT, &term, NULL) < 0) { + gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main", + "INT", strerror (errno)); + } + + if G_UNLIKELY (sigaction (SIGTERM, &term, NULL) < 0) { + gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main", + "TERM", strerror (errno)); + } + + sigemptyset (&mask); + sigaddset (&mask, SIGTERM); + sigaddset (&mask, SIGHUP); + sigaddset (&mask, SIGINT); + + if G_UNLIKELY (sigprocmask (SIG_UNBLOCK, &mask, NULL) == -1) { + gdm_common_fail_greeter ("Could not set signal mask!"); + } + + /* ignore SIGCHLD */ + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + + if G_UNLIKELY (sigprocmask (SIG_BLOCK, &mask, NULL) == -1) { + gdm_common_fail_greeter ("Could not set signal mask!"); + } + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + if G_UNLIKELY (DOING_GDM_DEVELOPMENT) { + g_signal_connect (G_OBJECT (window), "key_press_event", + G_CALLBACK (key_press_event), NULL); + } + + canvas = gnome_canvas_new_aa (); + GTK_WIDGET_UNSET_FLAGS (canvas, GTK_CAN_FOCUS); + gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), + 0.0, 0.0, + (double) gdm_wm_screen.width, + (double) gdm_wm_screen.height); + gtk_window_set_decorated (GTK_WINDOW (window), FALSE); + gtk_window_set_default_size (GTK_WINDOW (window), + gdm_wm_screen.width, + gdm_wm_screen.height); + gtk_container_add (GTK_CONTAINER (window), canvas); + + /* + * Initialize the value with the default value so the first time it + * is displayed it doesn't show as 0. Also determine if the Halt, + * Reboot, Suspend and Configurator commands work. + */ + gdm_timed_delay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY); + GdmHaltFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_HALT)); + GdmRebootFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_REBOOT)); + GdmSuspendFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_SUSPEND)); + GdmConfiguratorFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR)); + + GdmCustomCmdsFound = g_new0 (gboolean, GDM_CUSTOM_COMMAND_MAX); + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gchar * key_string = NULL; + /* For each possible custom command */ + key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i); + GdmCustomCmdsFound[i] = gdm_working_command_exists (gdm_config_get_string (key_string)); + if (GdmCustomCmdsFound[i]) + GdmAnyCustomCmdsFound = TRUE; + + g_free (key_string); + } + + if (g_getenv ("GDM_THEME") != NULL) + gdm_graphical_theme = g_strdup (g_getenv ("GDM_THEME")); + else if (gdm_config_get_bool (GDM_KEY_GRAPHICAL_THEME_RAND)) + gdm_graphical_theme = get_random_theme (); + else + gdm_graphical_theme = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME); + + theme_file = get_theme_file (gdm_graphical_theme, &theme_dir); + + error = NULL; + root = greeter_parse (theme_file, theme_dir, + GNOME_CANVAS (canvas), + gdm_wm_screen.width, + gdm_wm_screen.height, + &error); + + if G_UNLIKELY (root == NULL) + { + GtkWidget *dialog; + char *s; + char *tmp; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + tmp = ve_filename_to_utf8 (ve_sure_string (gdm_graphical_theme)); + s = g_strdup_printf (_("There was an error loading the " + "theme %s"), tmp); + g_free (tmp); + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + s, + (error && error->message) ? error->message : ""); + g_free (s); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (DOING_GDM_DEVELOPMENT) + { + exit (1); + } + } + + if G_UNLIKELY (error) + g_clear_error (&error); + + /* Try circles.xml */ + if G_UNLIKELY (root == NULL) + { + g_free (theme_file); + g_free (theme_dir); + theme_file = get_theme_file ("circles", &theme_dir); + root = greeter_parse (theme_file, theme_dir, + GNOME_CANVAS (canvas), + gdm_wm_screen.width, + gdm_wm_screen.height, + NULL); + } + + g_free (theme_file); + + if G_UNLIKELY (root != NULL && greeter_lookup_id ("user-pw-entry") == NULL) + { + GtkWidget *dialog; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("The greeter theme is corrupt"), + _("The theme does not contain " + "definition for the username/password " + "entry element.")); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + root = NULL; + } + + /* FIXME: beter information should be printed */ + if G_UNLIKELY (DOING_GDM_DEVELOPMENT && root == NULL) + { + g_warning ("No theme could be loaded"); + exit (1); + } + + if G_UNLIKELY (root == NULL) + { + GtkWidget *dialog; + + gdm_wm_init (0); + gdm_wm_focus_new_windows (TRUE); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("There was an error loading the " + "theme, and the default theme " + "could not be loaded. " + "Attempting to start the " + "standard greeter"), + ""); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + execl (LIBEXECDIR "/gdmlogin", LIBEXECDIR "/gdmlogin", NULL); + execlp ("gdmlogin", "gdmlogin", NULL); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("The GTK+ greeter could not be started. " + "This display will abort and you may " + "have to login another way and fix the " + "installation of GDM"), + ""); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + _exit (DISPLAY_ABORT); + } + + greeter_layout (root, GNOME_CANVAS (canvas)); + + greeter_setup_items (); + + if G_LIKELY (! DOING_GDM_DEVELOPMENT) { + ctrlch = g_io_channel_unix_new (STDIN_FILENO); + g_io_channel_set_encoding (ctrlch, NULL, NULL); + g_io_channel_set_buffered (ctrlch, TRUE); + g_io_channel_set_flags (ctrlch, + g_io_channel_get_flags (ctrlch) | G_IO_FLAG_NONBLOCK, + NULL); + g_io_add_watch (ctrlch, + G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) greeter_ctrl_handler, + NULL); + g_io_channel_unref (ctrlch); + } + + gdm_common_setup_blinking (); + + gtk_widget_show_all (window); + gtk_window_move (GTK_WINDOW (window), gdm_wm_screen.x, gdm_wm_screen.y); + gtk_widget_show_now (window); + + greeter_item_ulist_unset_selected_user (); + greeter_item_ulist_enable (); + greeter_item_ulist_check_show_userlist (); + + /* can it ever happen that it'd be NULL here ??? */ + if G_UNLIKELY (window->window != NULL) + { + gdm_wm_init (GDK_WINDOW_XWINDOW (window->window)); + + /* Run the focus, note that this will work no matter what + * since gdm_wm_init will set the display to the gdk one + * if it fails */ + gdm_wm_focus_window (GDK_WINDOW_XWINDOW (window->window)); + } + + if G_UNLIKELY (session_dir_whacked_out) + { + GtkWidget *dialog; + + gdm_wm_focus_new_windows (TRUE); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Session directory is missing"), + _("Your session directory is missing or empty! " + "There are two available sessions you can use, but " + "you should log in and correct the gdm configuration.")); + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gdm_wm_no_login_focus_push (); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + gdm_wm_no_login_focus_pop (); + } + + if G_UNLIKELY (g_getenv ("GDM_WHACKED_GREETER_CONFIG") != NULL) + { + GtkWidget *dialog; + + gdm_wm_focus_new_windows (TRUE); + + dialog = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Configuration is not correct"), + _("The configuration file contains an invalid command " + "line for the login dialog, so running the " + "default command. Please fix your configuration.")); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + + gdm_wm_no_login_focus_push (); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + gdm_wm_no_login_focus_pop (); + } + + /* if a flexiserver, reap self after some time */ + if (gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES) > 0 && + ! ve_string_empty (g_getenv ("GDM_FLEXI_SERVER")) && + /* but don't reap Xnest flexis */ + ve_string_empty (g_getenv ("GDM_PARENT_DISPLAY"))) + { + sid = g_signal_lookup ("activate", + GTK_TYPE_MENU_ITEM); + g_signal_add_emission_hook (sid, + 0 /* detail */, + delay_reaping, + NULL /* data */, + NULL /* destroy_notify */); + + sid = g_signal_lookup ("key_press_event", + GTK_TYPE_WIDGET); + g_signal_add_emission_hook (sid, + 0 /* detail */, + delay_reaping, + NULL /* data */, + NULL /* destroy_notify */); + + sid = g_signal_lookup ("button_press_event", + GTK_TYPE_WIDGET); + g_signal_add_emission_hook (sid, + 0 /* detail */, + delay_reaping, + NULL /* data */, + NULL /* destroy_notify */); + + last_reap_delay = time (NULL); + g_timeout_add (60*1000, reap_flexiserver, NULL); + } + + sid = g_signal_lookup ("event", + GTK_TYPE_WIDGET); + g_signal_add_emission_hook (sid, + 0 /* detail */, + gdm_event, + NULL /* data */, + NULL /* destroy_notify */); + + gdm_wm_restore_wm_order (); + + gdm_wm_show_info_msg_dialog (gdm_config_get_string (GDM_KEY_INFO_MSG_FILE), + gdm_config_get_string (GDM_KEY_INFO_MSG_FONT)); + + gdm_common_setup_cursor (GDK_LEFT_PTR); + gdm_wm_center_cursor (); + gdm_common_pre_fetch_launch (); + gtk_main (); + + return 0; +} diff --git a/trunk/gui/greeter/greeter.dtd b/trunk/gui/greeter/greeter.dtd new file mode 100644 index 00000000..74fa7b9d --- /dev/null +++ b/trunk/gui/greeter/greeter.dtd @@ -0,0 +1,79 @@ +<!-- dtd for greeter --> +<!ENTITY % colorattrs "file CDATA #IMPLIED + color CDATA #IMPLIED + font CDATA #IMPLIED + tint CDATA #IMPLIED"> +<!ELEMENT greeter (item+)> +<!ELEMENT item (pos | normal? | active? | prelight? | children? | show? | text? | fixed? | box? | listitem? | border?)*> +<!ELEMENT children (item+)> +<!ELEMENT pos EMPTY> +<!ELEMENT show EMPTY> +<!ELEMENT text (#PCDATA)> +<!ELEMENT normal EMPTY> +<!ELEMENT active EMPTY> +<!ELEMENT prelight EMPTY> +<!ELEMENT stock EMPTY> +<!ELEMENT fixed (item+)> +<!ELEMENT box (item+)> +<!ELEMENT listitem (text+)> +<!-- additional elements--> +<!ELEMENT border EMPTY> + +<!-- internal id's are one of (user-pw-entry | caps-lock-warning | clock | pam-error | pam-message | pam-prompt | pam-warning | timed-label | language_button | disconnect_button | reboot_button | halt_button | session_button | suspend_button | system_button | config_button | chooser_button | userlist) + but there can be other id's --> +<!ATTLIST item + type (rect | entry | pixmap | label | svg | rect | list) #REQUIRED + id CDATA #IMPLIED + button (true | false) #IMPLIED + background (true | false) #IMPLIED +> +<!ATTLIST pos + x CDATA #IMPLIED + y CDATA #IMPLIED + anchor CDATA "c" + width CDATA #IMPLIED + height CDATA #IMPLIED +> +<!ATTLIST normal + %colorattrs; + alpha CDATA #IMPLIED +> +<!ATTLIST active + %colorattrs; + alpha CDATA #IMPLIED +> +<!ATTLIST prelight + %colorattrs; + file CDATA #IMPLIED +> +<!ATTLIST stock + type (language | session | system | disconnect | quit | caps-lock-warning | timed-label | welcome-label | username-label | config | chooser) #REQUIRED +> +<!ATTLIST box + orientation (horizontal | vertical) "horizontal" + spacing CDATA #IMPLIED + xpadding CDATA #IMPLIED + ypadding CDATA #IMPLIED + min-width CDATA #IMPLIED + min-height CDATA #IMPLIED +> +<!-- console,console-fixed,console-flexi,remote-flexi,flexi,remote--> +<!ATTLIST show + modes CDATA #IMPLIED + type (config | chooser | system | halt | reboot | suspend | timed) #IMPLIED +> +<!ATTLIST text + xml:lang CDATA #IMPLIED +> +<!ATTLIST listitem + id CDATA #REQUIRED +> + +<!-- <border red="0" green="0" blue="10" alpha="255"/>--> + +<!ATTLIST border + red CDATA #IMPLIED + green CDATA #IMPLIED + blue CDATA #IMPLIED + alpha CDATA #IMPLIED +> diff --git a/trunk/gui/greeter/greeter.h b/trunk/gui/greeter/greeter.h new file mode 100644 index 00000000..8be51441 --- /dev/null +++ b/trunk/gui/greeter/greeter.h @@ -0,0 +1,32 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_H__ +#define __GREETER_H__ + +#include <gtk/gtk.h> + +extern gboolean DOING_GDM_DEVELOPMENT; +extern GtkWidget *canvas; +extern GtkWidget *window; + +extern gboolean greeter_probably_login_prompt; + +void greeter_ignore_buttons (gboolean val); + +#endif diff --git a/trunk/gui/greeter/greeter_canvas_item.c b/trunk/gui/greeter/greeter_canvas_item.c new file mode 100644 index 00000000..dd32aed0 --- /dev/null +++ b/trunk/gui/greeter/greeter_canvas_item.c @@ -0,0 +1,773 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <math.h> +#include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <librsvg/rsvg.h> + +#include "gdm.h" +#include "gdmcommon.h" +#include "gdmconfig.h" + +#include "gdm-common.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter.h" +#include "greeter_item.h" +#include "greeter_events.h" +#include "greeter_system.h" +#include "greeter_canvas_item.h" +#include "greeter_configuration.h" +#include "greeter_canvas_text.h" +#include "greeter_parser.h" + +/* Keep track of buttons so they can be set sensitive/insensitive */ +GtkButton *gtk_ok_button = NULL; +GtkButton *gtk_start_again_button = NULL; + +static void +apply_tint (GdkPixbuf *pixbuf, guint32 tint_color) +{ + guchar *pixels; + guint r, g, b; + gboolean has_alpha; + guint w, h, stride; + guint pixel_stride; + guchar *line; + int i; + + pixels = gdk_pixbuf_get_pixels (pixbuf); + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + + r = (tint_color & 0xff0000) >> 16; + g = (tint_color & 0x00ff00) >> 8; + b = (tint_color & 0x0000ff); + + w = gdk_pixbuf_get_width (pixbuf); + h = gdk_pixbuf_get_height (pixbuf); + stride = gdk_pixbuf_get_rowstride (pixbuf); + + pixel_stride = (has_alpha) ? 4 : 3; + + while (h-->0) + { + line = pixels; + + for (i = 0; i < w; i++) + { + line[0] = line[0] * r / 0xff; + line[1] = line[1] * g / 0xff; + line[2] = line[2] * b / 0xff; + line += pixel_stride; + } + + pixels += stride; + } +} + +static GdkPixbuf * +transform_pixbuf (GdkPixbuf *orig, + gboolean has_tint, guint32 tint_color, + double alpha, gint width, gint height) +{ + GdkPixbuf *scaled; + gint p_width, p_height; + + p_width = gdk_pixbuf_get_width (orig); + p_height = gdk_pixbuf_get_height (orig); + + if (p_width != width || + p_height != height || + alpha < 1.0 || + has_tint) + { + int alpha_i; + + if (alpha >= 1.0) + alpha_i = 0xff; + else if (alpha <= 0.0) + alpha_i = 0; + else + alpha_i = (guint) floor (0xff*alpha); + if (alpha != 0xff) + { + scaled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + gdk_pixbuf_fill (scaled, 0); + gdk_pixbuf_composite (orig, scaled, 0, 0, width, height, + 0, 0, (double)width/p_width, (double)height/p_height, + GDK_INTERP_BILINEAR, alpha_i); + } + else + scaled = gdk_pixbuf_scale_simple (orig, width, height, GDK_INTERP_BILINEAR); + } + else + scaled = g_object_ref (orig); + + if (has_tint) + apply_tint (scaled, tint_color); + + return scaled; +} + +static void +activate_button (GtkWidget *widget, gpointer data) +{ + const char *id = data; + if (id != NULL) + greeter_item_run_action_callback (id); +} + +static void +menubar_done (GtkMenuShell *menushell, gpointer data) +{ + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + + gtk_widget_grab_focus (entry); +} + +static GtkWidget * +make_menubar (void) +{ + GtkWidget *w, *menu; + GtkWidget *menubar = gtk_menu_bar_new (); + + /* FIXME: add translatable string here */ + w = gtk_menu_item_new_with_label ("Menu"); + gtk_menu_shell_append (GTK_MENU_SHELL (menubar), w); + gtk_widget_show (GTK_WIDGET (w)); + + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), menu); + + w = gtk_menu_item_new_with_mnemonic (_("Select _Language...")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (activate_button), + "language_button"); + + w = gtk_menu_item_new_with_mnemonic (_("Select _Session...")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (activate_button), + "session_button"); + + greeter_system_append_system_menu (menu); + + /* Add a quit/disconnect item when in xdmcp mode or flexi mode */ + /* Do note that the order is important, we always want "Quit" for + * flexi, even if not local (non-local xnest). and Disconnect + * only for xdmcp */ + if ( ! ve_string_empty (g_getenv ("GDM_FLEXI_SERVER"))) { + w = gtk_menu_item_new_with_mnemonic (_("_Quit")); + } else if (ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) { + w = gtk_menu_item_new_with_mnemonic (_("D_isconnect")); + } else { + w = NULL; + } + if (w != NULL) { + GtkWidget *sep; + /* add separator before the quit */ + sep = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); + gtk_widget_show (GTK_WIDGET (sep)); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (gtk_main_quit), NULL); + } + + g_signal_connect (G_OBJECT(gtk_menu_item_get_submenu( + gtk_container_get_children(GTK_CONTAINER(menubar))->data)), "selection-done", G_CALLBACK (menubar_done), NULL); + + return menubar; +} + +static void +get_gdk_color_from_rgb (GdkColor *c, guint32 rgb) +{ + c->red = ((rgb & 0xff0000) >> 16) * 0x101; + c->green = ((rgb & 0xff00) >> 8) * 0x101; + c->blue = (rgb & 0xff) * 0x101; + c->pixel = 0; +} + +static void +menu_position_func (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + GreeterItemInfo *item) +{ + GtkAllocation rect; + GtkRequisition requisition; + + rect = item->allocation; + gtk_widget_size_request (GTK_WIDGET (menu), &requisition); + *x = rect.x; + if (requisition.height <= rect.y) + *y = rect.y - requisition.height; + else + *y = rect.y + rect.height; + + *push_in = TRUE; +} + +/* + * The button with this handler never appears in the F10 menu, so + * it can make use of callback data. + */ +static void +greeter_options_handler (GreeterItemInfo *item, GtkWidget *menubar) +{ + gtk_menu_popup (GTK_MENU(gtk_menu_item_get_submenu( + gtk_container_get_children(GTK_CONTAINER(menubar))->data)), + NULL, NULL, (GtkMenuPositionFunc)menu_position_func, + item, 0, gtk_get_current_event_time()); +} + +static void +greeter_item_run_button_action_callback (GtkButton *button, const char *id) +{ + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + + greeter_item_run_action_callback (id); + gtk_widget_grab_focus (entry); +} + +void +greeter_item_create_canvas_item (GreeterItemInfo *item) +{ + GnomeCanvasGroup *group; + GtkJustification just; + GtkWidget *entry; + GtkWidget *gtkbutton; + GtkWidget *list; + GtkWidget *swin; + double x1, y1, x2, y2; + int i; + GtkAllocation rect; + char *text; + GtkTooltips *tooltips; + char *num_locale; + GdkColor c; + + if (item->item != NULL) + return; + + if ( ! greeter_item_is_visible (item)) + return; + + g_assert (item->parent->group_item); + + if (item->fixed_children != NULL || + item->box_children != NULL) + { + item->group_item = + (GnomeCanvasGroup *)gnome_canvas_item_new (item->parent->group_item, + GNOME_TYPE_CANVAS_GROUP, + "x", (gdouble) 0.0, + "y", (gdouble) 0.0, + NULL); + group = item->group_item; + } + else + group = item->parent->group_item; + + rect = item->allocation; + + + x1 = (gdouble) rect.x; + y1 = (gdouble) rect.y; + x2 = (gdouble) rect.x + rect.width; + y2 = (gdouble) rect.y + rect.height; + + switch (item->item_type) { + case GREETER_ITEM_TYPE_RECT: + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_RECT, + "x1", x1, + "y1", y1, + "x2", x2, + "y2", y2, + "fill_color_rgba", item->data.rect.colors[GREETER_ITEM_STATE_NORMAL], + NULL); + break; + case GREETER_ITEM_TYPE_SVG: + num_locale = g_strdup (setlocale (LC_NUMERIC, NULL)); + setlocale (LC_NUMERIC, "C"); + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if (item->data.pixmap.files[i] != NULL) + { + if (i > 0 && + item->data.pixmap.files[0] != NULL && + item->data.pixmap.pixbufs[0] != NULL && + strcmp (item->data.pixmap.files[0], item->data.pixmap.files[i]) == 0) + item->data.pixmap.pixbufs[i] = g_object_ref (item->data.pixmap.pixbufs[0]); + else + item->data.pixmap.pixbufs[i] = + gdk_pixbuf_new_from_file_at_size (item->data.pixmap.files[i], rect.width, rect.height, NULL); + } + else + item->data.pixmap.pixbufs[i] = NULL; + } + setlocale (LC_NUMERIC, num_locale); + g_free (num_locale); + num_locale = NULL; + + /* Fall through */ + case GREETER_ITEM_TYPE_PIXMAP: + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + GdkPixbuf *pb = item->data.pixmap.pixbufs[i]; + if (pb != NULL) + { + item->data.pixmap.pixbufs[i] = + transform_pixbuf (pb, + (item->data.pixmap.have_tint & (1<<i)), item->data.pixmap.tints[i], + (double)item->data.pixmap.alphas[i] / 256.0, rect.width, rect.height); + g_object_unref (pb); + } + } + + if (item->data.pixmap.pixbufs[GREETER_ITEM_STATE_NORMAL] != NULL) + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_PIXBUF, + "x", (gdouble) x1, + "y", (gdouble) y1, + "pixbuf", item->data.pixmap.pixbufs[GREETER_ITEM_STATE_NORMAL], + NULL); + break; + case GREETER_ITEM_TYPE_LABEL: + text = gdm_common_expand_text (item->data.text.orig_text); + + /* Justification is taken from the anchor */ + if (item->anchor == GTK_ANCHOR_NORTH_WEST || + item->anchor == GTK_ANCHOR_SOUTH_WEST || + item->anchor == GTK_ANCHOR_WEST) + just = GTK_JUSTIFY_LEFT; + else if (item->anchor == GTK_ANCHOR_NORTH_EAST || + item->anchor == GTK_ANCHOR_SOUTH_EAST || + item->anchor == GTK_ANCHOR_EAST) + just = GTK_JUSTIFY_RIGHT; + else + just = GTK_JUSTIFY_CENTER; + + item->item = gnome_canvas_item_new (group, + GREETER_TYPE_CANVAS_TEXT, + "text", "", + "x", x1, + "y", y1, + "anchor", item->anchor, + "font_desc", item->data.text.fonts[GREETER_ITEM_STATE_NORMAL], + "fill_color_rgba", item->data.text.colors[GREETER_ITEM_STATE_NORMAL], + "justification", just, + NULL); + + greeter_canvas_item_break_set_string (item, + text, + TRUE /* markup */, + item->data.text.real_max_width, + NULL /* width */, + NULL /* height */, + NULL /* canvas */, + item->item); + g_free (text); + + /* if there is an accelerator we do an INCREDIBLE hack */ + if (strchr (item->data.text.orig_text, '_') != NULL) + { + GreeterItemInfo *button; + GtkWidget *fake_button = gtk_button_new_with_mnemonic (item->data.text.orig_text); + gtk_widget_show (fake_button); + GTK_WIDGET_UNSET_FLAGS (fake_button, GTK_CAN_FOCUS); + gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)), + GNOME_TYPE_CANVAS_WIDGET, + "widget", fake_button, + "x", (double)-999.0, + "y", (double)-999.0, + "height", (double)20.0, + "width", (double)20.0, + NULL); + button = item->my_button; + if (button == NULL) + button = item; + g_signal_connect_data (G_OBJECT (fake_button), "clicked", + G_CALLBACK (activate_button), + g_strdup (button->id), + (GClosureNotify)g_free, + 0 /* connect_flags */); + } + + break; + + case GREETER_ITEM_TYPE_BUTTON: + gtkbutton = gtk_button_new_with_mnemonic (item->data.text.orig_text); + gtk_widget_set_name (gtkbutton, item->id); + if (strcmp (ve_sure_string (item->id), "ok_button") == 0) { + gtk_ok_button = GTK_BUTTON (gtkbutton); + } else if (strcmp (ve_sure_string (item->id), "cancel_button") == 0) { + gtk_start_again_button = GTK_BUTTON (gtkbutton); + } + + g_signal_connect (G_OBJECT (gtkbutton), "clicked", + G_CALLBACK (greeter_item_run_button_action_callback), + item->id); + + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_WIDGET, + "widget", gtkbutton, + "x", x1, + "y", y1, + "height", (double)rect.height, + "width", (double)rect.width, + NULL); + + break; + + case GREETER_ITEM_TYPE_ENTRY: + entry = gtk_entry_new (); + gtk_widget_set_name (entry, "user-pw-entry"); + gtk_entry_set_has_frame (GTK_ENTRY (entry), FALSE); + + if (gdm_config_get_bool (GDM_KEY_ENTRY_INVISIBLE)) + gtk_entry_set_invisible_char (GTK_ENTRY (entry), 0); + else if (gdm_config_get_bool (GDM_KEY_ENTRY_CIRCLES)) + gtk_entry_set_invisible_char (GTK_ENTRY (entry), 0x25cf); + + gtk_widget_modify_font (entry, item->data.text.fonts[GREETER_ITEM_STATE_NORMAL]); + + get_gdk_color_from_rgb (&c, item->data.text.colors[GREETER_ITEM_STATE_NORMAL]); + gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &c); + + if (item->id != NULL && strcmp (item->id, "user-pw-entry") == 0) { + /* HACK! Add a menubar, this is kind of evil isn't it, + * should probably be done in the pam item setup thingie. + * but this is really widget kind of thing. I dunno where + * this belongs but it's a hack here. */ + item->data.text.menubar = make_menubar (); + + gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)), + GNOME_TYPE_CANVAS_WIDGET, + "widget", item->data.text.menubar, + "x", (double)x1, + "y", (double)y1, + "height", (double)rect.height, + "width", (double)rect.width, + NULL); + + greeter_item_register_action_callback ("options_button", + (ActionFunc)greeter_options_handler, + item->data.text.menubar); + + /* Here add a tooltip, so that the user knows about F10 */ + tooltips = gtk_tooltips_new (); + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (entry), + _("Answer questions here and press Enter " + "when done. For a menu press F10."), + NULL); + + /* FIXME: how to make this accessible??? */ + } + + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_WIDGET, + "widget", entry, + "x", x1, + "y", y1, + "height", (double)rect.height, + "width", (double)rect.width, + NULL); + + /* cursor blinking is evil on remote displays, don't do it forever */ + gdm_common_setup_blinking_entry (entry); + + break; + + case GREETER_ITEM_TYPE_LIST: + /* Note a list type must be setup later and we will add the list store + * to it then, depending on the type. Likely userlist is the + * only type we support */ + + if (item->data.list.combo_type) { + list = gtk_combo_box_new_text (); + + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_WIDGET, + "widget", list, + "x", x1, + "y", y1, + "height", (double)rect.height, + "width", (double)rect.width, + NULL); + } else { + list = gtk_tree_view_new (); + + swin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), + GTK_SHADOW_NONE); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (swin), list); + + item->item = gnome_canvas_item_new (group, + GNOME_TYPE_CANVAS_WIDGET, + "widget", swin, + "x", x1, + "y", y1, + "height", (double)rect.height, + "width", (double)rect.width, + NULL); + } + + break; + } + + if (item->item_type == GREETER_ITEM_TYPE_RECT || + item->item_type == GREETER_ITEM_TYPE_SVG || + item->item_type == GREETER_ITEM_TYPE_PIXMAP || + item->item_type == GREETER_ITEM_TYPE_LABEL) + g_signal_connect (G_OBJECT (item->item), "event", + G_CALLBACK (greeter_item_event_handler), + item); +} + +/* This is so evil it hurts */ +static char * +make_ugly_long_string_with_line_breaks (const char *orig) +{ + const char *p; + int n_chars, i; + GString *foo = g_string_new (NULL); + gboolean in_element = FALSE; + + n_chars = g_utf8_strlen (orig, -1); + p = orig; + + i = 0; + while (i < n_chars) { + gunichar ch = g_utf8_get_char (p); + if (ch == '<') + in_element = TRUE; + else if (ch == '>') + in_element = FALSE; + g_string_append_unichar (foo, ch); + if ( ! in_element) + g_string_append_unichar (foo, '\n'); + p = g_utf8_next_char (p); + i++; + } + + return g_string_free (foo, FALSE); +} + +/* This function is very VERY evil */ +static gboolean +append_word (GString *str, GString *line, GString *word, const char *after, int max_width, const char *textattr, GnomeCanvasItem *canvas_item) +{ + int width, height; + char *post = make_ugly_long_string_with_line_breaks (after); + char *try = g_strconcat (str->str, word->str, "\n", post, NULL); + g_free (post); + gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, try, NULL); + g_free (try); + + pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, &width, &height); + + if (width > max_width) { + if ( ! ve_string_empty (line->str)) { + if (str->len > 0 && + str->str[str->len-1] == ' ') { + g_string_truncate (str, str->len-1); + } + g_string_append_unichar (str, '\n'); + } + g_string_assign (line, word->str); + g_string_append (str, word->str); + g_string_assign (word, ""); + + return TRUE; + } else { + g_string_append (line, word->str); + g_string_append (str, word->str); + g_string_assign (word, ""); + + return FALSE; + } +} + +/* This function is very VERY evil */ +/* Note that it should just use pango and do all the right things rather then + the utter hacks it tries to do. But I couldn't figure out how to do this + simply with pango and how to interact with markup properly (it seems easy + to do if there is no markup */ +void +greeter_canvas_item_break_set_string (GreeterItemInfo *info, + const char *orig, + gboolean markup, + int max_width, + int *width, + int *height, + GnomeCanvas *canvas, + GnomeCanvasItem *real_item) +{ + PangoLogAttr *attrs; + int n_chars; + GString *str; + GString *word; + GString *line; + int i; + int n_attrs; + int ia; + const char *p; + int in_current_row; + GnomeCanvasItem *canvas_item; + const char *textattr; + int lwidth, lheight; + + str = g_string_new (NULL); + word = g_string_new (NULL); + line = g_string_new (NULL); + + /* avoid errors and even possible crashes */ + if (markup && ! pango_parse_markup (orig, -1, 0, NULL, NULL, NULL, NULL)) { + markup = FALSE; + } + + textattr = markup ? "markup" : "text"; + + /* A gross hack */ + if (real_item != NULL) + canvas_item = real_item; + else + canvas_item = gnome_canvas_item_new (gnome_canvas_root (canvas), + GREETER_TYPE_CANVAS_TEXT, + textattr, "", + "x", 0.0, + "y", 0.0, + "font_desc", info->data.text.fonts[GREETER_ITEM_STATE_NORMAL], + NULL); + + if (max_width == 0) { + gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, orig, NULL); + pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, width, height); + + if (real_item != canvas_item) { + gtk_object_destroy (GTK_OBJECT (canvas_item)); + g_string_free (line, TRUE); + g_string_free (word, TRUE); + g_string_free (str, TRUE); + } + return; + } + + n_chars = g_utf8_strlen (orig, -1); + + gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, orig, NULL); + pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, &lwidth, &lheight); + if (lwidth <= max_width) { + if (width != NULL) + *width = lwidth; + if (height != NULL) + *height = lheight; + if (real_item != canvas_item) { + gtk_object_destroy (GTK_OBJECT (canvas_item)); + g_string_free (line, TRUE); + g_string_free (word, TRUE); + g_string_free (str, TRUE); + } + return; + } + + pango_layout_get_log_attrs (GNOME_CANVAS_TEXT (canvas_item)->layout, &attrs, &n_attrs); + + i = 0; + ia = 0; + in_current_row = 0; + p = orig; + while (i < n_chars) { + gunichar ch; + + ch = g_utf8_get_char (p); + + if (markup && ch == '<') { + while (i < n_chars) { + g_string_append_unichar (word, ch); + p = g_utf8_next_char (p); + i++; + + if (ch == '>') { + ch = g_utf8_get_char (p); + break; + } else { + ch = g_utf8_get_char (p); + } + } + if (i >= n_chars) + break; + } + + if (attrs[ia].is_line_break && in_current_row > 0) { + if (append_word (str, line, word, p, max_width, textattr, canvas_item)) + in_current_row = 0; + } + + in_current_row++; + g_string_append_unichar (word, ch); + + p = g_utf8_next_char (p); + i++; + ia++; + + /* eeek! */ + if (ia >= n_attrs) { + while (i < n_chars) { + ch = g_utf8_get_char (p); + g_string_append_unichar (word, ch); + p = g_utf8_next_char (p); + i++; + } + break; + } + } + + if ( ! ve_string_empty (word->str)) + append_word (str, line, word, "", max_width, textattr, canvas_item); + + gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, str->str, NULL); + pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, width, height); + + if (real_item != canvas_item) + gtk_object_destroy (GTK_OBJECT (canvas_item)); + g_free (attrs); + + g_string_free (line, TRUE); + g_string_free (word, TRUE); + + g_string_free (str, TRUE); +} + diff --git a/trunk/gui/greeter/greeter_canvas_item.h b/trunk/gui/greeter/greeter_canvas_item.h new file mode 100644 index 00000000..cbea3eef --- /dev/null +++ b/trunk/gui/greeter/greeter_canvas_item.h @@ -0,0 +1,33 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_CANVAS_ITEM_H +#define GREETER_CANVAS_ITEM_H + +void greeter_item_create_canvas_item (GreeterItemInfo *item); + +void greeter_canvas_item_break_set_string (GreeterItemInfo *info, + const char *orig, + gboolean markup, + int max_width, + int *width, + int *height, + GnomeCanvas *canvas, + GnomeCanvasItem *real_item); + +#endif /* GREETER_CANVAS_ITEM_H */ diff --git a/trunk/gui/greeter/greeter_canvas_text.c b/trunk/gui/greeter/greeter_canvas_text.c new file mode 100644 index 00000000..961f5190 --- /dev/null +++ b/trunk/gui/greeter/greeter_canvas_text.c @@ -0,0 +1,213 @@ +#include <string.h> + +#include "greeter_canvas_text.h" + +#include <libgnomecanvas/gnome-canvas.h> +#include <libgnomecanvas/gnome-canvas-text.h> +#include <pango/pangoft2.h> + + +enum +{ + PROP_0, + PROP_TEXT, + PROP_MARKUP +}; + +static void greeter_canvas_text_class_init (GreeterCanvasTextClass *class); +static void greeter_canvas_text_init (GreeterCanvasText *text); +static void greeter_canvas_text_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void greeter_canvas_text_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE (GreeterCanvasText, greeter_canvas_text, GNOME_TYPE_CANVAS_TEXT) + +static void +greeter_canvas_text_class_init (GreeterCanvasTextClass *greeter_class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (greeter_class); + + gobject_class->set_property = greeter_canvas_text_set_property; + gobject_class->get_property = greeter_canvas_text_get_property; + + g_object_class_install_property + (gobject_class, + PROP_TEXT, + g_param_spec_string ("text", + "Text", + "Text to render", + NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + g_object_class_install_property + (gobject_class, + PROP_MARKUP, + g_param_spec_string ("markup", + "Markup", + "Markup to render", + NULL, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); +} + +static void +greeter_canvas_text_init (GreeterCanvasText *text) +{ +} + +static gdouble +greeter_canvas_text_get_screen_dpi (GreeterCanvasText *text) +{ + GdkDisplay *display; + GdkScreen *screen; + GdkAtom atom, type; + gint resources_length; + gchar *resources, *resource, *end; + gdouble dpi; + static const gdouble default_dpi = 96.0; + + atom = gdk_atom_intern ("RESOURCE_MANAGER", TRUE); + + if (atom == 0) + return default_dpi; + + display = + gtk_widget_get_display (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas)); + + if (display == NULL) + return default_dpi; + + screen = + gtk_widget_get_screen (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas)); + + if (screen == NULL) + return default_dpi; + + gdk_error_trap_push (); + if (!gdk_property_get (gdk_screen_get_root_window (screen), + atom, GDK_TARGET_STRING, + 0, G_MAXINT, + FALSE, + &type, NULL, &resources_length, + (void *) &resources)) + { + gdk_error_trap_pop (); + return default_dpi; + } + + gdk_display_sync (display); + gdk_error_trap_pop (); + + if (type != GDK_TARGET_STRING) + return default_dpi; + + if (resources == NULL) + return default_dpi; + + resource = strstr (resources, "Xft.dpi:\t"); + + if (resource == NULL) + return default_dpi; + + resource += sizeof ("Xft.dpi:\t") - 1; + + dpi = strtod (resource, &end); + + g_assert (end != NULL); + + if ((end == resource) || (*end != '\n')) + return default_dpi; + + g_free (resources); + + if (dpi < G_MINDOUBLE) + return default_dpi; + + return dpi; +} + +static void +greeter_canvas_text_init_layout (GreeterCanvasText *greeter_item) +{ + GnomeCanvasItem *item; + GnomeCanvasText *text; + + PangoContext *gtk_context, *context; + static PangoFT2FontMap *font_map; + gdouble dpi; + + item = GNOME_CANVAS_ITEM (greeter_item); + text = GNOME_CANVAS_TEXT (greeter_item); + + if (text->layout != NULL) + return; + + gtk_context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas)); + + if (font_map == NULL) + { + font_map = (PangoFT2FontMap *) pango_ft2_font_map_new (); + dpi = greeter_canvas_text_get_screen_dpi (greeter_item); + pango_ft2_font_map_set_resolution (font_map, dpi, dpi); + } + + context = pango_ft2_font_map_create_context (font_map); + + pango_context_set_language (context, + pango_context_get_language (gtk_context)); + pango_context_set_base_dir (context, + pango_context_get_base_dir (gtk_context)); + pango_context_set_font_description (context, + pango_context_get_font_description (gtk_context)); + + text->layout = pango_layout_new (context); + g_object_unref (context); +} + +static void +greeter_canvas_text_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (param_id) + { + case PROP_TEXT: + greeter_canvas_text_init_layout (GREETER_CANVAS_TEXT (object)); + g_object_set_property (object, "GnomeCanvasText::text", value); + break; + case PROP_MARKUP: + greeter_canvas_text_init_layout (GREETER_CANVAS_TEXT (object)); + g_object_set_property (object, "GnomeCanvasText::markup", value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +greeter_canvas_text_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + switch (param_id) + { + case PROP_TEXT: + g_object_get_property (object, "GnomeCanvasText::text", value); + break; + case PROP_MARKUP: + g_object_get_property (object, "GnomeCanvasText::markup", value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} diff --git a/trunk/gui/greeter/greeter_canvas_text.h b/trunk/gui/greeter/greeter_canvas_text.h new file mode 100644 index 00000000..f2131023 --- /dev/null +++ b/trunk/gui/greeter/greeter_canvas_text.h @@ -0,0 +1,33 @@ +#ifndef GREETER_CANVAS_TEXT_H +#define GREETER_CANVAS_TEXT_H + +#include <libgnomecanvas/gnome-canvas.h> +#include <libgnomecanvas/gnome-canvas-text.h> + +G_BEGIN_DECLS + +#define GREETER_TYPE_CANVAS_TEXT (greeter_canvas_text_get_type ()) +#define GREETER_CANVAS_TEXT(obj) (GTK_CHECK_CAST ((obj), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasText)) +#define GREETER_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasTextClass)) +#define GREETER_IS_CANVAS_TEXT(obj) (GTK_CHECK_TYPE ((obj), GREETER_TYPE_CANVAS_TEXT)) +#define GREETER_IS_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GREETER_TYPE_CANVAS_TEXT)) +#define GREETER_CANVAS_TEXT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasTextClass)) + + +typedef struct _GreeterCanvasText GreeterCanvasText; +typedef struct _GreeterCanvasTextClass GreeterCanvasTextClass; + +struct _GreeterCanvasText { + GnomeCanvasText text; +}; + +struct _GreeterCanvasTextClass { + GnomeCanvasTextClass parent_class; +}; + + +GType greeter_canvas_text_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif diff --git a/trunk/gui/greeter/greeter_configuration.h b/trunk/gui/greeter/greeter_configuration.h new file mode 100644 index 00000000..d4dabaf9 --- /dev/null +++ b/trunk/gui/greeter/greeter_configuration.h @@ -0,0 +1,72 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_CONFIGURATION_H +#define GREETER_CONFIGURATION_H + +extern gboolean GdmUseCirclesInEntry; +extern gboolean GdmUseInvisibleInEntry; +extern gboolean GdmShowGnomeFailsafeSession; +extern gboolean GdmShowXtermFailsafeSession; +extern gboolean GdmShowLastSession; +extern gboolean GdmSystemMenu; +extern gboolean GdmConfigAvailable; +extern gboolean GdmChooserButton; +extern gchar *GdmHalt; +extern gchar *GdmReboot; +extern gchar *GdmSuspend; +extern gchar *GdmConfigurator; +extern gboolean GdmHaltFound; +extern gboolean GdmRebootFound; +extern gboolean GdmCustomCmdFound; +extern gboolean *GdmCustomCmdsFound; +extern gboolean GdmAnyCustomCmdsFound; +extern gboolean GdmSuspendFound; +extern gboolean GdmConfiguratorFound; +extern gchar *GdmSessionDir; +extern gchar *GdmDefaultSession; +extern gchar *GdmDefaultLocale; +extern gchar *GdmLocaleFile; +extern gboolean GdmTimedLoginEnable; +extern gboolean GdmUse24Clock; +extern gchar *GdmTimedLogin; +extern gint GdmTimedLoginDelay; +extern gchar *GdmGlobalFaceDir; +extern gchar *GdmDefaultFace; +extern gint GdmIconMaxHeight; +extern gint GdmIconMaxWidth; +extern gchar *GdmExclude; +extern int GdmMinimalUID; +extern gboolean GdmAllowRoot; +extern gboolean GdmAllowRemoteRoot; +extern gchar *GdmWelcome; +extern gchar *GdmServAuthDir; +extern gchar *GdmInfoMsgFile; +extern gchar *GdmInfoMsgFont; +extern gchar *GdmSoundProgram; +extern gchar *GdmSoundOnLoginReadyFile; +extern gchar *GdmSoundOnLoginSuccessFile; +extern gchar *GdmSoundOnLoginFailureFile; +extern gboolean GdmSoundOnLoginReady; +extern gboolean GdmSoundOnLoginSuccess; +extern gboolean GdmSoundOnLoginFailure; + +extern gboolean GDM_IS_LOCAL; +extern gboolean DOING_GDM_DEVELOPMENT; + +#endif /* GREETER_CONFIGURATION_H */ diff --git a/trunk/gui/greeter/greeter_dialogs.c b/trunk/gui/greeter/greeter_dialogs.c new file mode 100644 index 00000000..ceb4c1ac --- /dev/null +++ b/trunk/gui/greeter/greeter_dialogs.c @@ -0,0 +1,25 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 "greeter_dialogs.h" + + +GtkWidget * +greeter_lang_dialog (void) +{ +} diff --git a/trunk/gui/greeter/greeter_dialogs.h b/trunk/gui/greeter/greeter_dialogs.h new file mode 100644 index 00000000..c2f3e7f7 --- /dev/null +++ b/trunk/gui/greeter/greeter_dialogs.h @@ -0,0 +1,26 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_DIALOGS_H__ +#define __GREETER_DIALOGS_H__ + +#include <gtk/gtk.h> + +GtkWidget *greeter_lang_dialog (void); + +#endif diff --git a/trunk/gui/greeter/greeter_events.c b/trunk/gui/greeter/greeter_events.c new file mode 100644 index 00000000..34b96040 --- /dev/null +++ b/trunk/gui/greeter/greeter_events.c @@ -0,0 +1,256 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <string.h> +#include <stdlib.h> + +#include "greeter_item.h" +#include "greeter_parser.h" +#include "greeter_events.h" + +struct CallbackInfo { + ActionFunc func; + gpointer user_data; +}; + +static GHashTable *callback_hash = NULL; + +static void +state_run (GreeterItemInfo *info, + GreeterItemState old_state) +{ + if (info->state != old_state && + info->have_state & (1<<(info->state)) && + info->have_state != (1<<GREETER_ITEM_STATE_NORMAL) && + info->item != NULL) + { + if (GREETER_ITEM_TYPE_IS_PIXMAP (info) && + info->data.pixmap.pixbufs[info->state] != NULL) + gnome_canvas_item_set (info->item, + "pixbuf", info->data.pixmap.pixbufs[info->state], + NULL); + if ((GREETER_ITEM_TYPE_IS_TEXT (info) || + GREETER_ITEM_TYPE_IS_RECT (info)) && + info->data.rect.have_color & (1<<(info->state))) + gnome_canvas_item_set (info->item, + "fill_color_rgba", info->data.rect.colors[info->state], + NULL); + if (GREETER_ITEM_TYPE_IS_TEXT (info) && + info->data.text.fonts[info->state] != NULL) + gnome_canvas_item_set (info->item, + "font_desc", info->data.text.fonts[info->state], + NULL); + } +} + +static void propagate_state (GreeterItemInfo *info, + GreeterItemState old_state); + +static void +propagate_state_foreach (gpointer data, gpointer user_data) +{ + GreeterItemInfo *info = data; + GreeterItemState state = GPOINTER_TO_INT (user_data); + GreeterItemState old_state; + + old_state = info->state; + info->state = state; + + propagate_state (info, old_state); +} + +static void +propagate_state (GreeterItemInfo *info, + GreeterItemState old_state) +{ + state_run (info, old_state); + + g_list_foreach (info->fixed_children, propagate_state_foreach, + GINT_TO_POINTER ((int) info->state)); + g_list_foreach (info->box_children, propagate_state_foreach, + GINT_TO_POINTER ((int) info->state)); +} + +static void propagate_reset_state (GreeterItemInfo *info, + GreeterItemState old_state); + +static void +propagate_reset_state_foreach (gpointer data, gpointer user_data) +{ + GreeterItemInfo *info = data; + GreeterItemState old_state; + + old_state = info->state; + info->state = info->base_state; + + propagate_state (info, old_state); +} + +static void +propagate_reset_state (GreeterItemInfo *info, + GreeterItemState old_state) +{ + state_run (info, old_state); + + g_list_foreach (info->fixed_children, propagate_reset_state_foreach, NULL); + g_list_foreach (info->box_children, propagate_reset_state_foreach, NULL); +} + +void +greeter_item_run_action_callback (const char *id) +{ + struct CallbackInfo *cb_info; + GreeterItemInfo *info; + + g_return_if_fail (id != NULL); + + if G_UNLIKELY (callback_hash == NULL) + return; + + info = greeter_lookup_id (id); + cb_info = g_hash_table_lookup (callback_hash, id); + + /* + * If run_action_callback gets called and there is no + * callback function registered, don't try to call it. + * This can happen because the button_release event + * tries calling the callback function for any + * item that has an id (like the Username field). + */ + if (cb_info) + (*cb_info->func) (info, cb_info->user_data); +} + +gint +greeter_item_event_handler (GnomeCanvasItem *item, + GdkEvent *event, + gpointer data) +{ + GreeterItemState old_state; + GreeterItemInfo *info; + GreeterItemInfo *button; + + info = data; + button = info->my_button; + if (button != NULL && button != info) + { + /* FIXME: this is a hack, we have not really left the container, + * but the container gets a stupid leave event and + * we send it an enter event back, it does two event propagations + * one of them is pointless. */ + /* if this is a button, fake an event on the button */ + return greeter_item_event_handler (button->item, + event, + button); + } + + old_state = info->state; + + switch (event->type) { + case GDK_ENTER_NOTIFY: + info->mouse_over = TRUE; + break; + + case GDK_LEAVE_NOTIFY: + info->mouse_over = FALSE; + break; + + case GDK_BUTTON_PRESS: + info->mouse_down = TRUE; + break; + + case GDK_BUTTON_RELEASE: + info->mouse_down = FALSE; + + if (info->mouse_over && info->id && callback_hash) + greeter_item_run_action_callback (info->id); + + /* Make sure entry has focus if a type BUTTON has been pressed. */ + if (info->item_type == GREETER_ITEM_TYPE_BUTTON) { + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + /* Make sure entry has focus after button press */ + gtk_widget_grab_focus (entry); + } + } + + break; + + default: + break; + } + + if (info->mouse_over) + { + if (info->mouse_down) + info->state = GREETER_ITEM_STATE_ACTIVE; + else + info->state = GREETER_ITEM_STATE_PRELIGHT; + } + else + info->state = GREETER_ITEM_STATE_NORMAL; + + info->base_state = info->state; + + if (info->state != old_state) + { + if (info->canvasbutton) + { + if (info->state == GREETER_ITEM_STATE_NORMAL) + propagate_reset_state (info, old_state); + else + propagate_state (info, old_state); + } + else + state_run (info, old_state); + } + + return FALSE; +} + +void +greeter_item_register_action_callback (char *id, + ActionFunc func, + gpointer user_data) +{ + struct CallbackInfo *info; + + if G_UNLIKELY (callback_hash == NULL) + callback_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + info = g_new (struct CallbackInfo, 1); + + info->func = func; + info->user_data = user_data; + + g_hash_table_insert (callback_hash, + g_strdup (id), + info); +} + diff --git a/trunk/gui/greeter/greeter_events.h b/trunk/gui/greeter/greeter_events.h new file mode 100644 index 00000000..1c1ba1d7 --- /dev/null +++ b/trunk/gui/greeter/greeter_events.h @@ -0,0 +1,35 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_EVENTS_H +#define GREETER_EVENTS_H + +typedef void (*ActionFunc) (GreeterItemInfo *info, + gpointer user_data); + +gint greeter_item_event_handler (GnomeCanvasItem *item, + GdkEvent *event, + gpointer data); + +void greeter_item_register_action_callback (char *id, + ActionFunc func, + gpointer user_data); + +void greeter_item_run_action_callback (const char *id); + +#endif /* GREETER_EVENTS_H */ diff --git a/trunk/gui/greeter/greeter_geometry.c b/trunk/gui/greeter/greeter_geometry.c new file mode 100644 index 00000000..265b19be --- /dev/null +++ b/trunk/gui/greeter/greeter_geometry.c @@ -0,0 +1,623 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <librsvg/rsvg.h> +#include "gdmcommon.h" +#include "gdmwm.h" +#include "greeter_geometry.h" +#include "greeter_canvas_item.h" + +static void greeter_item_size_request (GreeterItemInfo *item, + GtkRequisition *requisition_out, + gint parent_width, + gint parent_height, + GnomeCanvas *canvas); +static void greeter_size_allocate_fixed (GreeterItemInfo *fixed, + GList *items, + GnomeCanvas *canvas); +static void greeter_size_allocate_box (GreeterItemInfo *box, + GList *items, + GnomeCanvas *canvas, + GtkAllocation *allocation); +static void fixup_from_anchor (GtkAllocation *rect, + GtkAnchorType anchor); +static void update_real_max_width (GreeterItemInfo *info, + int max_width); + +static void +update_real_max_width (GreeterItemInfo *info, int max_width) +{ + if (info->data.text.real_max_width == 0 || + info->data.text.real_max_width > max_width) + info->data.text.real_max_width = max_width; +} + + +/* Position the item */ +static void +greeter_item_size_allocate (GreeterItemInfo *item, + GtkAllocation *allocation, + GnomeCanvas *canvas) +{ + item->allocation = *allocation; + + if ( ! greeter_item_is_visible (item)) + return; + + if (item->item == NULL) + greeter_item_create_canvas_item (item); + + if (item->fixed_children) + greeter_size_allocate_fixed (item, + item->fixed_children, + canvas); + + if (item->box_children) + greeter_size_allocate_box (item, + item->box_children, + canvas, + allocation); + +} + +static void +fixup_from_anchor (GtkAllocation *rect, + GtkAnchorType anchor) +{ + switch (anchor) + { + case GTK_ANCHOR_NW: + break; + case GTK_ANCHOR_N: + rect->x -= rect->width/2; + break; + case GTK_ANCHOR_NE: + rect->x -= rect->width; + break; + + case GTK_ANCHOR_W: + rect->y -= rect->height/2; + break; + case GTK_ANCHOR_CENTER: + rect->x -= rect->width/2; + rect->y -= rect->height/2; + break; + case GTK_ANCHOR_E: + rect->x -= rect->width; + rect->y -= rect->height/2; + break; + + case GTK_ANCHOR_SW: + rect->y -= rect->height; + break; + case GTK_ANCHOR_S: + rect->x -= rect->width/2; + rect->y -= rect->height; + break; + case GTK_ANCHOR_SE: + rect->x -= rect->width; + rect->y -= rect->height; + break; + default: + break; + } +} + +/* Position the children of the parent given + * the size */ +static void +greeter_size_allocate_fixed (GreeterItemInfo *fixed, + GList *items, + GnomeCanvas *canvas) +{ + GList *l; + GreeterItemInfo *child; + GtkRequisition requisition; + GtkAllocation child_allocation; + + l = items; + while (l != NULL) + { + child = l->data; + l = l->next; + + if ( ! greeter_item_is_visible (child)) + continue; + + greeter_item_size_request (child, + &requisition, + fixed->allocation.width, + fixed->allocation.height, + canvas); + + child_allocation.x = fixed->allocation.x; + child_allocation.y = fixed->allocation.y; + + child_allocation.width = requisition.width; + child_allocation.height = requisition.height; + + if (child->x_type == GREETER_ITEM_POS_ABSOLUTE) + child_allocation.x += ( ! child->x_negative) ? child->x : fixed->allocation.width + child->x; + else if (child->x_type == GREETER_ITEM_POS_RELATIVE) + child_allocation.x += fixed->allocation.width * child->x / 100.0; + + if (child->y_type == GREETER_ITEM_POS_ABSOLUTE) + child_allocation.y += ( ! child->y_negative) ? child->y : fixed->allocation.height + child->y; + else if (child->y_type == GREETER_ITEM_POS_RELATIVE) + child_allocation.y += fixed->allocation.height * child->y / 100.0; + + if (child->item_type != GREETER_ITEM_TYPE_LABEL) + fixup_from_anchor (&child_allocation, child->anchor); + + greeter_item_size_allocate (child, + &child_allocation, + canvas); + } +} + + +/* Position the children of the parent given + * the size */ +static void +greeter_size_allocate_box (GreeterItemInfo *box, + GList *items, + GnomeCanvas *canvas, + GtkAllocation *allocation) +{ + GreeterItemInfo *child; + GList *children; + GtkAllocation child_allocation; + GtkRequisition child_requisition; + gint nvis_children; + gint nexpand_children; + gint child_major_size; + gint major_size; + gint extra; + gint major; + gint w, h; + + nvis_children = 0; + nexpand_children = 0; + + children = items; + while (children) + { + child = children->data; + children = children->next; + + if (greeter_item_is_visible (child)) + { + nvis_children += 1; + if (child->expand) + nexpand_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (box->box_homogeneous) + { + major_size = (allocation->width - + box->box_x_padding * 2 - + (nvis_children - 1) * box->box_spacing); + extra = major_size / nvis_children; + } + else if (nexpand_children > 0) + { + major_size = (gint) allocation->width - (gint) box->requisition.width; + extra = major_size / nexpand_children; + } + else + { + major_size = 0; + extra = 0; + } + + major = allocation->x + box->box_x_padding; + } + else + { + if (box->box_homogeneous) + { + major_size = (allocation->height - + box->box_y_padding * 2 - + (nvis_children - 1) * box->box_spacing); + extra = major_size / nvis_children; + } + else if (nexpand_children > 0) + { + major_size = (gint) allocation->height - (gint) box->requisition.height; + extra = major_size / nexpand_children; + } + else + { + major_size = 0; + extra = 0; + } + + major = allocation->y + box->box_y_padding; + } + + + children = items; + while (children) + { + child = children->data; + children = children->next; + + if ( ! greeter_item_is_visible (child)) + continue; + + if (box->box_homogeneous) + { + if (nvis_children == 1) + child_major_size = major_size; + else + child_major_size = extra; + + major_size -= extra; + + nvis_children -= 1; + } + else + { + greeter_item_size_request (child, + &child_requisition, + 0, 0, canvas); + + if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) + child_major_size = child_requisition.width; + else + child_major_size = child_requisition.height; + + if (child->expand) + { + if (nexpand_children == 1) + child_major_size += major_size; + else + child_major_size += extra; + + nexpand_children -= 1; + major_size -= extra; + } + } + + /* Dirty the child requisition, since + * we now know the right parent size. + */ + child->has_requisition = FALSE; + w = (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) ? child_major_size : allocation->width - 2 * box->box_x_padding; + h = (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) ? allocation->height - 2 * box->box_y_padding : child_major_size; + + greeter_item_size_request (child, + &child_requisition, + w, h, canvas); + + child_allocation.width = child_requisition.width; + child_allocation.height = child_requisition.height; + + if (box->box_orientation == GTK_ORIENTATION_VERTICAL && + child->item_type == GREETER_ITEM_TYPE_LABEL) { + update_real_max_width (child, allocation->width); + } + + if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) + { + child_allocation.x = major; + child_allocation.y = allocation->y + box->box_y_padding; + } + else + { + child_allocation.x = allocation->x + box->box_x_padding; + child_allocation.y = major; + } + + if (child->x_type == GREETER_ITEM_POS_ABSOLUTE) + child_allocation.x += ( ! child->x_negative) ? child->x : w + child->x; + else if (child->x_type == GREETER_ITEM_POS_RELATIVE) + child_allocation.x += w * child->x / 100.0; + + if (child->y_type == GREETER_ITEM_POS_ABSOLUTE) + child_allocation.y += ( ! child->y_negative) ? child->y : h + child->y; + else if (child->y_type == GREETER_ITEM_POS_RELATIVE) + child_allocation.y += h * child->y / 100.0; + + if (child->item_type != GREETER_ITEM_TYPE_LABEL) + fixup_from_anchor (&child_allocation, child->anchor); + + if (child_allocation.x + child_allocation.width > allocation->x + allocation->width) + child_allocation.width -= (child_allocation.x + child_allocation.width + - allocation->x - allocation->width); + + greeter_item_size_allocate (child, + &child_allocation, + canvas); + + major += child_major_size + box->box_spacing; + } + } +} + +static void +greeter_size_request_box (GreeterItemInfo *box, + GtkRequisition *requisition, + GnomeCanvas *canvas) +{ + + GreeterItemInfo *child; + GtkRequisition child_requisition; + GList *children; + gint nvis_children; + + requisition->width = 0; + requisition->height = 0; + + nvis_children = 0; + + children = box->box_children; + while (children) + { + child = children->data; + children = children->next; + + if ( ! greeter_item_is_visible (child)) + continue; + + greeter_item_size_request (child, + &child_requisition, + 0, 0, canvas); + + if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (box->box_homogeneous) + { + requisition->width = MAX (requisition->width, + child_requisition.width); + } + else + { + requisition->width += child_requisition.width; + } + + requisition->height = MAX (requisition->height, child_requisition.height); + } + else + { + if (box->box_homogeneous) + { + requisition->height = MAX (requisition->height, + child_requisition.height); + } + else + { + requisition->height += child_requisition.height; + } + + requisition->width = MAX (requisition->width, child_requisition.width); + } + + + nvis_children += 1; + } + + if (nvis_children > 0) + { + + if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (box->box_homogeneous) + requisition->width *= nvis_children; + requisition->width += (nvis_children - 1) * box->box_spacing; + } + else + { + if (box->box_homogeneous) + requisition->height *= nvis_children; + requisition->height += (nvis_children - 1) * box->box_spacing; + } + } + + requisition->width += box->box_x_padding * 2; + requisition->height += box->box_y_padding * 2; + + requisition->width = MAX (requisition->width, box->box_min_width); + requisition->height = MAX (requisition->height, box->box_min_height); +} + +/* Calculate the requested minimum size of the item */ +static void +greeter_item_size_request (GreeterItemInfo *item, + GtkRequisition *requisition_out, + gint parent_width, + gint parent_height, + GnomeCanvas *canvas) +{ + GtkRequisition *req; + GtkRequisition box_requisition = {0, 0}; + int set_width = 0; + int set_height = 0; + + if (item->has_requisition) + { + *requisition_out = item->requisition; + return; + } + + req = &item->requisition; + + req->width = 0; + req->height = 0; + + if (item->width_type == GREETER_ITEM_SIZE_BOX || + item->height_type == GREETER_ITEM_SIZE_BOX) + { + greeter_size_request_box (item, + &box_requisition, + canvas); + } + + switch (item->width_type) + { + case GREETER_ITEM_SIZE_ABSOLUTE: + set_width = (item->width > 0) ? item->width : parent_width + item->width; + break; + case GREETER_ITEM_SIZE_RELATIVE: + set_width = item->width*parent_width / 100.0; + break; + case GREETER_ITEM_SIZE_BOX: + set_width = box_requisition.width; + break; + case GREETER_ITEM_SIZE_SCALE: + case GREETER_ITEM_SIZE_UNSET: + break; + } + + switch (item->height_type) + { + case GREETER_ITEM_SIZE_ABSOLUTE: + set_height = (item->height > 0) ? item->height : parent_height + item->height; + break; + case GREETER_ITEM_SIZE_RELATIVE: + set_height = item->height*parent_height / 100.0; + break; + case GREETER_ITEM_SIZE_BOX: + set_height = box_requisition.height; + break; + case GREETER_ITEM_SIZE_SCALE: + case GREETER_ITEM_SIZE_UNSET: + break; + } + + if (item->item_type == GREETER_ITEM_TYPE_LABEL) + { + int width, height; + char *text; + int max_width = G_MAXINT; + + /* This is not the ugly hack you're looking for. + * You can go about your business. + * Move Along + */ + text = gdm_common_expand_text (item->data.text.orig_text); + + if (set_width > 0) + max_width = set_width; + + if (item->data.text.max_width < max_width) + max_width = item->data.text.max_width; + + if (item->data.text.max_screen_percent_width/100.0 * gdm_wm_screen.width < max_width) + max_width = item->data.text.max_screen_percent_width/100.0 * gdm_wm_screen.width; + + greeter_canvas_item_break_set_string (item, + text, + TRUE /* markup */, + max_width, + &width, + &height, + canvas, + NULL /* real_item */); + + req->width = width; + req->height = height; + + g_free (text); + } + + if (item->item_type == GREETER_ITEM_TYPE_PIXMAP) + { + req->width = gdk_pixbuf_get_width (item->data.pixmap.pixbufs[0]); + req->height = gdk_pixbuf_get_height (item->data.pixmap.pixbufs[0]); + } + + if (item->item_type == GREETER_ITEM_TYPE_SVG) + { + GdkPixbuf *svg; + + svg = rsvg_pixbuf_from_file (item->data.pixmap.files[0], NULL); + req->width = gdk_pixbuf_get_width (svg); + req->height = gdk_pixbuf_get_height (svg); + g_object_unref (svg); + } + + if (item->item_type == GREETER_ITEM_TYPE_BUTTON) + { +#define ITEM_BUTTON_MIN_RECOMMANDED_WIDTH_OFFSET 15 +#define ITEM_BUTTON_MIN_RECOMMANDED_HEIGHT_OFFSET 10 + PangoLayout *layout; + int pango_width, pango_height; + int pix_width, pix_height; + + GtkWidget *dummy_w = gtk_button_new (); + + layout = gtk_widget_create_pango_layout (dummy_w, item->data.text.orig_text); + + pango_layout_get_size (layout, &pango_width, &pango_height); + + pix_height = PANGO_PIXELS (pango_height) + ITEM_BUTTON_MIN_RECOMMANDED_HEIGHT_OFFSET; + pix_width = PANGO_PIXELS (pango_width) + ITEM_BUTTON_MIN_RECOMMANDED_WIDTH_OFFSET; + + if (pix_width > item->parent->box_min_width) + req->width = pix_width; + else + req->width = item->parent->box_min_width; + + if (pix_height > item->parent->box_min_height) + req->height = pix_height; + else + req->height = item->parent->box_min_height; + } + + if (req->width > 0 && req->height > 0) + { + if (item->width_type == GREETER_ITEM_SIZE_SCALE && set_height > 0) + set_width = (req->width * set_height) / req->height; + else if (item->height_type == GREETER_ITEM_SIZE_SCALE && set_width > 0) + set_height = (req->height * set_width) / req->width; + } + + if (set_width > 0) + req->width = set_width; + if (set_height > 0) + req->height = set_height; + + *requisition_out = item->requisition; + item->has_requisition = TRUE; +} + + + +void +greeter_layout (GreeterItemInfo *root_item, + GnomeCanvas *canvas) +{ + root_item->allocation.x = 0; + root_item->allocation.y = 0; + root_item->allocation.width = root_item->width; + root_item->allocation.height = root_item->height; + + greeter_size_allocate_fixed (root_item, + root_item->fixed_children, + canvas); +} diff --git a/trunk/gui/greeter/greeter_geometry.h b/trunk/gui/greeter/greeter_geometry.h new file mode 100644 index 00000000..182ef9e9 --- /dev/null +++ b/trunk/gui/greeter/greeter_geometry.h @@ -0,0 +1,27 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_GEOMETRY_H +#define GREETER_GEOMETRY_H + +#include "greeter_item.h" + +void greeter_layout (GreeterItemInfo *root_item, + GnomeCanvas *canvas); + +#endif diff --git a/trunk/gui/greeter/greeter_item.c b/trunk/gui/greeter/greeter_item.c new file mode 100644 index 00000000..b6838114 --- /dev/null +++ b/trunk/gui/greeter/greeter_item.c @@ -0,0 +1,249 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include "gdm.h" +#include "gdmwm.h" +#include "gdmconfig.h" +#include "gdmcommon.h" +#include "misc.h" + +#include "gdm-common.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter_item.h" +#include "greeter_configuration.h" + +extern gboolean GdmHaltFound; +extern gboolean GdmRebootFound; +extern gboolean GdmCustomCmdFound; +extern gboolean *GdmCustomCmdsFound; +extern gboolean GdmSuspendFound; +extern gboolean GdmConfiguratorFound; + +GreeterItemInfo * +greeter_item_info_new (GreeterItemInfo *parent, + GreeterItemType type) +{ + GreeterItemInfo *info; + int i; + + info = g_new0 (GreeterItemInfo, 1); + + info->item_type = type; + info->parent = parent; + + info->anchor = GTK_ANCHOR_NW; + info->x_type = GREETER_ITEM_POS_UNSET; + info->y_type = GREETER_ITEM_POS_UNSET; + info->width_type = GREETER_ITEM_SIZE_UNSET; + info->height_type = GREETER_ITEM_SIZE_UNSET; + + if (type != GREETER_ITEM_TYPE_LIST) + { + for (i=0; i< GREETER_ITEM_STATE_MAX; i++) + { + /* these happen to coincide for all + items but list */ + info->data.rect.alphas[i] = 0xff; + } + } + + info->box_orientation = GTK_ORIENTATION_VERTICAL; + + info->state = GREETER_ITEM_STATE_NORMAL; + info->base_state = GREETER_ITEM_STATE_NORMAL; + + info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE; + + info->canvasbutton = FALSE; + info->gtkbutton = FALSE; + info->background = FALSE; + + if (GREETER_ITEM_TYPE_IS_TEXT (info)) + { + info->data.text.max_width = 0xffff; + info->data.text.max_screen_percent_width = 90; + info->data.text.real_max_width = 0; + info->data.text.menubar= NULL; + } + + return info; +} + +void +greeter_item_info_free (GreeterItemInfo *info) +{ + int i; + GList *list; + + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if (GREETER_ITEM_TYPE_IS_PIXMAP (info)) + { + if (info->data.pixmap.pixbufs[i] != NULL) + g_object_unref (G_OBJECT (info->data.pixmap.pixbufs[i])); + if (info->data.pixmap.files[i] != NULL) + g_free (info->data.pixmap.files[i]); + } + else if (GREETER_ITEM_TYPE_IS_TEXT (info)) + { + if (info->data.text.fonts[i] != NULL) + pango_font_description_free (info->data.text.fonts[i]); + } + } + + list = info->fixed_children; + info->fixed_children = NULL; + g_list_foreach (list, (GFunc) greeter_item_info_free, NULL); + g_list_free (list); + + list = info->box_children; + info->box_children = NULL; + g_list_foreach (list, (GFunc) greeter_item_info_free, NULL); + g_list_free (list); + + if (GREETER_ITEM_TYPE_IS_TEXT (info)) + g_free (info->data.text.orig_text); + + /* FIXME: what about custom list items! */ + + g_free (info->id); + g_free (info->show_type); + + memset (info, 0, sizeof (GreeterItemInfo)); + g_free (info); +} + +void +greeter_item_update_text (GreeterItemInfo *info) +{ + char *text; + if (info && info->item && + GNOME_IS_CANVAS_TEXT (info->item) && + GREETER_ITEM_TYPE_IS_TEXT (info)) + { + text = gdm_common_expand_text (info->data.text.orig_text); + + g_object_set (G_OBJECT (info->item), + "markup", text, + NULL); + + g_free (text); + } + +} + +gboolean +greeter_item_is_visible (GreeterItemInfo *info) +{ + static gboolean checked = FALSE; + static gboolean GDM_IS_LOCAL = FALSE; + static gboolean GDM_FLEXI_SERVER = FALSE; + gboolean sysmenu = FALSE; + gint i = 0; + + if ( ! checked) + { + if (g_getenv ("GDM_IS_LOCAL") != NULL) + GDM_IS_LOCAL = TRUE; + if (g_getenv ("GDM_FLEXI_SERVER") != NULL) + GDM_FLEXI_SERVER = TRUE; + } + + if (GDM_IS_LOCAL && ! GDM_FLEXI_SERVER && + ! (info->show_modes & GREETER_ITEM_SHOW_CONSOLE_FIXED)) + return FALSE; + if (GDM_IS_LOCAL && GDM_FLEXI_SERVER && + ! (info->show_modes & GREETER_ITEM_SHOW_CONSOLE_FLEXI)) + return FALSE; + if ( ! GDM_IS_LOCAL && GDM_FLEXI_SERVER && + ! (info->show_modes & GREETER_ITEM_SHOW_REMOTE_FLEXI)) + return FALSE; + if ( ! GDM_IS_LOCAL && ! GDM_FLEXI_SERVER && + ! (info->show_modes & GREETER_ITEM_SHOW_REMOTE)) + return FALSE; + + if ((gdm_wm_screen.width < info->minimum_required_screen_width) || + (gdm_wm_screen.height < info->minimum_required_screen_height)) + return FALSE; + + sysmenu = gdm_config_get_bool (GDM_KEY_SYSTEM_MENU); + + /* + * Disable Configuration if using accessibility (AddGtkModules) since + * using it with accessibility causes a hang. + */ + if (( ! gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) || + gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) || + ! sysmenu || + ! GdmConfiguratorFound) && + (info->show_type != NULL && + strcmp (info->show_type, "config") == 0)) + return FALSE; + + if (( ! gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON) || ! sysmenu) && + (info->show_type != NULL && + strcmp (info->show_type, "chooser") == 0)) + return FALSE; + + if ( ! sysmenu && info->show_type != NULL && + strcmp (info->show_type, "system") == 0) + return FALSE; + + if (( ! sysmenu || ! GdmHaltFound) && + (info->show_type != NULL && + strcmp (info->show_type, "halt") == 0)) + return FALSE; + if (( ! sysmenu || ! GdmRebootFound) && + (info->show_type != NULL && + strcmp (info->show_type, "reboot") == 0)) + return FALSE; + if (( ! sysmenu || ! GdmSuspendFound) && + (info->show_type != NULL && + strcmp (info->show_type, "suspend") == 0)) + return FALSE; + + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gchar * key_string = g_strdup_printf ("custom_cmd%d", i); + if (( ! sysmenu || ! GdmCustomCmdsFound[i]) && + (info->show_type != NULL && + strcmp (info->show_type, key_string) == 0)) { + g_free (key_string); + return FALSE; + } + g_free (key_string); + } + + if (( ! gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) || + ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN)) || + NULL == g_getenv("GDM_TIMED_LOGIN_OK")) && + (info->show_type != NULL && + strcmp (info->show_type, "timed") == 0)) + return FALSE; + + return TRUE; +} diff --git a/trunk/gui/greeter/greeter_item.h b/trunk/gui/greeter/greeter_item.h new file mode 100644 index 00000000..c72b5424 --- /dev/null +++ b/trunk/gui/greeter/greeter_item.h @@ -0,0 +1,231 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_ITEM_H +#define GREETER_ITEM_H + +#include <libgnomecanvas/libgnomecanvas.h> + +typedef struct _GreeterItemInfo GreeterItemInfo; +typedef struct _GreeterItemListItem GreeterItemListItem; +typedef enum _GreeterItemState GreeterItemState; +typedef enum _GreeterItemType GreeterItemType; +typedef enum _GreeterItemSizeType GreeterItemSizeType; +typedef enum _GreeterItemPosType GreeterItemPosType; +typedef enum _GreeterItemShowModes GreeterItemShowModes; + +/* Make sure to adjust the bitfield in the structure if + you make this larger */ +enum _GreeterItemState { + GREETER_ITEM_STATE_NORMAL, + GREETER_ITEM_STATE_PRELIGHT, + GREETER_ITEM_STATE_ACTIVE, + GREETER_ITEM_STATE_MAX +}; + +/* Make sure to adjust the bitfield in the structure if + you make this larger */ +enum _GreeterItemType { + GREETER_ITEM_TYPE_RECT, + GREETER_ITEM_TYPE_SVG, + GREETER_ITEM_TYPE_PIXMAP, + GREETER_ITEM_TYPE_LABEL, + GREETER_ITEM_TYPE_ENTRY, + GREETER_ITEM_TYPE_LIST, + GREETER_ITEM_TYPE_BUTTON +}; + +/* Make sure to adjust the bitfield in the structure if + you make this larger */ +enum _GreeterItemSizeType { + GREETER_ITEM_SIZE_UNSET, + GREETER_ITEM_SIZE_ABSOLUTE, + GREETER_ITEM_SIZE_RELATIVE, + GREETER_ITEM_SIZE_BOX, + GREETER_ITEM_SIZE_SCALE +}; + +/* Make sure to adjust the bitfield in the structure if + you make this larger */ +enum _GreeterItemPosType { + GREETER_ITEM_POS_UNSET, + GREETER_ITEM_POS_ABSOLUTE, + GREETER_ITEM_POS_RELATIVE +}; + +/* Make sure to adjust the bitfield in the structure if + you make this larger */ +enum _GreeterItemShowModes { + GREETER_ITEM_SHOW_EVERYWHERE = 0xf, + GREETER_ITEM_SHOW_NOWHERE = 0, + GREETER_ITEM_SHOW_CONSOLE_FIXED = 1<<0, + GREETER_ITEM_SHOW_CONSOLE = (1<<0) | (1<<1), + GREETER_ITEM_SHOW_CONSOLE_FLEXI = 1<<1, + GREETER_ITEM_SHOW_REMOTE_FLEXI = 1<<2, + GREETER_ITEM_SHOW_FLEXI = (1<<1) | (1<<2), + GREETER_ITEM_SHOW_REMOTE = 1<<3 +}; + +struct _GreeterItemInfo { + GreeterItemInfo *parent; + + GtkAnchorType anchor; + float x; + float y; + float width; + float height; + + int minimum_required_screen_width; + int minimum_required_screen_height; + + GreeterItemPosType x_type:2; + GreeterItemPosType y_type:2; + GreeterItemSizeType width_type:4; + GreeterItemSizeType height_type:4; + guint x_negative:1; /* needed for -0 */ + guint y_negative:1; /* needed for -0 */ + + /* For packed items */ + guint expand:1; + + /* The item type */ + GreeterItemType item_type:4; + + GreeterItemShowModes show_modes:4; + + /* Runtime state: */ + GreeterItemState state:2; + GreeterItemState base_state:2; + guint mouse_down:1; + guint mouse_over:1; + + /* box flags */ + guint box_homogeneous:1; + + /* is a canvas rectangle that acts like a button */ + /* (see the my_button comment) */ + guint canvasbutton:1; + + /* is a real GTK button (not the fake canvas button) */ + guint gtkbutton:1; + + /* item is used to draw background */ + guint background:1; + + /* geometry handling: */ + guint has_requisition:1; + GtkRequisition requisition; + GtkAllocation allocation; + + /* Button can propagate states and collect states from underlying items, + * it should be a parent of this item */ + GreeterItemInfo *my_button; + + char *show_type; /* timed, system, config, chooser, halt, suspend, reboot */ + + char *id; + + GList *box_children; + GtkOrientation box_orientation; + guint16 box_x_padding; + guint16 box_y_padding; + guint16 box_min_width; + guint16 box_min_height; + guint16 box_spacing; + + /* Container data */ + GList *fixed_children; + + union { + /* Note: we want to have alphas, colors and have_color coincide for + * all types that have it */ +#define GREETER_ITEM_TYPE_IS_TEXT(info) ((info)->item_type == GREETER_ITEM_TYPE_LABEL || (info)->item_type == GREETER_ITEM_TYPE_ENTRY) + struct { + guint8 alphas[GREETER_ITEM_STATE_MAX]; + guint32 colors[GREETER_ITEM_STATE_MAX]; + + guint8 have_color; /* this is a bitfield since these are + true/false values */ + + PangoFontDescription *fonts[GREETER_ITEM_STATE_MAX]; + char *orig_text; + guint16 max_width; + guint8 max_screen_percent_width; + guint16 real_max_width; + GtkWidget *menubar; + } text; /* text and entry (entry only uses fonts) */ + +#define GREETER_ITEM_TYPE_IS_PIXMAP(info) ((info)->item_type == GREETER_ITEM_TYPE_PIXMAP || (info)->item_type == GREETER_ITEM_TYPE_SVG) + struct { + guint8 alphas[GREETER_ITEM_STATE_MAX]; + guint32 tints[GREETER_ITEM_STATE_MAX]; + guint8 have_tint; /* this is a bitfield since these are + true/false values */ + + char *files[GREETER_ITEM_STATE_MAX]; + GdkPixbuf *pixbufs[GREETER_ITEM_STATE_MAX]; + } pixmap; + +#define GREETER_ITEM_TYPE_IS_LIST(info) ((info)->item_type == GREETER_ITEM_TYPE_LIST) + struct { + char *icon_color; + char *label_color; + /* If this is a custom list, then these are the items + to pick from */ + GList *items; + gboolean combo_type; + } list; + +#define GREETER_ITEM_TYPE_IS_RECT(info) ((info)->item_type == GREETER_ITEM_TYPE_RECT) + struct { + guint8 alphas[GREETER_ITEM_STATE_MAX]; + guint32 colors[GREETER_ITEM_STATE_MAX]; + + guint8 have_color; /* this is a bitfield since these are + true/false values */ + } rect; + } data; + + guint8 have_state; /* this is a bitfield since these are + true/false values */ + + /* Canvas data: */ + GnomeCanvasItem *item; + GnomeCanvasGroup *group_item; +}; + +struct _GreeterItemListItem { + char *id; + char *text; +}; + +gint greeter_item_event_handler (GnomeCanvasItem *item, + GdkEvent *event, + gpointer data); + +GreeterItemInfo *greeter_item_info_new (GreeterItemInfo *parent, + GreeterItemType type); +void greeter_item_info_free (GreeterItemInfo *info); + +char *greeter_item_expand_text (const char *text); + +void greeter_item_update_text (GreeterItemInfo *info); + +gboolean greeter_item_is_visible (GreeterItemInfo *info); + +#endif /* GREETER_ITEM_H */ diff --git a/trunk/gui/greeter/greeter_item_capslock.c b/trunk/gui/greeter/greeter_item_capslock.c new file mode 100644 index 00000000..385c0374 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_capslock.c @@ -0,0 +1,133 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> +#include <string.h> +#include <gdk/gdkx.h> +#include <X11/XKBlib.h> + +#include "greeter_parser.h" +#include "greeter_item_capslock.h" + +static gboolean caps_lock_state = FALSE; + +static Display * +get_parent_display (void) +{ + static gboolean tested = FALSE; + static Display *dsp = NULL; + + if (tested) + return dsp; + + tested = TRUE; + + if (g_getenv ("GDM_PARENT_DISPLAY") != NULL) + { + char *old_xauth = g_strdup (g_getenv ("XAUTHORITY")); + if (g_getenv ("GDM_PARENT_XAUTHORITY") != NULL) + { + g_setenv ("XAUTHORITY", + g_getenv ("GDM_PARENT_XAUTHORITY"), TRUE); + } + dsp = XOpenDisplay (g_getenv ("GDM_PARENT_DISPLAY")); + if (old_xauth != NULL) + g_setenv ("XAUTHORITY", old_xauth, TRUE); + else + g_unsetenv ("XAUTHORITY"); + g_free (old_xauth); + } + + return dsp; +} + +gboolean +greeter_is_capslock_on (void) +{ + XkbStateRec states; + Display *dsp; + + /* HACK! incredible hack, if this is set we get + * indicator state from the parent display, since we must be inside an + * Xnest */ + dsp = get_parent_display (); + if (dsp == NULL) + dsp = GDK_DISPLAY (); + + if (XkbGetState (dsp, XkbUseCoreKbd, &states) != Success) + return FALSE; + + return (states.locked_mods & LockMask) != 0; +} + + +static void +capslock_update (gboolean new_state) +{ + GreeterItemInfo *info; + GnomeCanvasItem *item; + + caps_lock_state = new_state; + + info = greeter_lookup_id ("caps-lock-warning"); + + if (info) + { + if (info->group_item != NULL) + item = GNOME_CANVAS_ITEM (info->group_item); + else + item = info->item; + + if (caps_lock_state) + { + gnome_canvas_item_show (item); + } + else + { + gnome_canvas_item_hide (item); + } + } +} + +static gboolean +cl_key_press_event (GtkWidget *widget, GdkEventKey *key, gpointer data) +{ + gboolean new_state; + + new_state = greeter_is_capslock_on (); + if (new_state != caps_lock_state) + capslock_update (new_state); + + return FALSE; +} + + +gboolean +greeter_item_capslock_setup (GtkWidget *window) +{ + capslock_update (greeter_is_capslock_on ()); + + g_signal_connect (G_OBJECT (window), "key_press_event", + G_CALLBACK (cl_key_press_event), NULL); + return TRUE; +} + diff --git a/trunk/gui/greeter/greeter_item_capslock.h b/trunk/gui/greeter/greeter_item_capslock.h new file mode 100644 index 00000000..089ce591 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_capslock.h @@ -0,0 +1,27 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_ITEM_CAPSLOCK_H__ +#define __GREETER_ITEM_CAPSLOCK_H__ + +#include "greeter_item.h" + +gboolean greeter_item_capslock_setup (GtkWidget *window); +gboolean greeter_is_capslock_on (void); + +#endif diff --git a/trunk/gui/greeter/greeter_item_clock.c b/trunk/gui/greeter/greeter_item_clock.c new file mode 100644 index 00000000..0779f9ab --- /dev/null +++ b/trunk/gui/greeter/greeter_item_clock.c @@ -0,0 +1,68 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <time.h> +#include "greeter_item_clock.h" +#include "greeter_parser.h" + +static gboolean +update_clock (gpointer data) +{ + GreeterItemInfo *info = data; + struct tm *the_tm; + time_t the_time; + gint time_til_next_min; + + greeter_item_update_text (info); + + time (&the_time); + the_tm = localtime (&the_time); + /* account for leap seconds */ + time_til_next_min = 60 - the_tm->tm_sec; + time_til_next_min = (time_til_next_min>=0?time_til_next_min:0); + + g_timeout_add (time_til_next_min*1000, update_clock, info); + + return FALSE; +} + + +gboolean +greeter_item_clock_setup (void) +{ + GreeterItemInfo *info; + + info = greeter_lookup_id ("clock"); + if (info) + update_clock (info); + + return TRUE; +} + +void +greeter_item_clock_update (void) +{ + GreeterItemInfo *info; + + info = greeter_lookup_id ("clock"); + if (info) + greeter_item_update_text (info); +} diff --git a/trunk/gui/greeter/greeter_item_clock.h b/trunk/gui/greeter/greeter_item_clock.h new file mode 100644 index 00000000..d2af2bf9 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_clock.h @@ -0,0 +1,27 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_ITEM_CLOCK_H__ +#define __GREETER_ITEM_CLOCK_H__ + +#include "greeter_item.h" + +gboolean greeter_item_clock_setup (void); +void greeter_item_clock_update (void); + +#endif diff --git a/trunk/gui/greeter/greeter_item_customlist.c b/trunk/gui/greeter/greeter_item_customlist.c new file mode 100644 index 00000000..6ab9cccd --- /dev/null +++ b/trunk/gui/greeter/greeter_item_customlist.c @@ -0,0 +1,667 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <stdlib.h> +#include <string.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include "gdm.h" +#include "gdmconfig.h" +#include "gdmsession.h" +#include "gdmlanguages.h" + +#include "gdm-common.h" +#include "gdm-daemon-config-keys.h" +#include "gdm-socket-protocol.h" + +#include "greeter_item.h" +#include "greeter_configuration.h" +#include "greeter_item_customlist.h" +#include "greeter_parser.h" +#include "greeter_session.h" + +#define LAST_LANGUAGE "Last" + +/* + * Keep track of the session/language widgets so we can + * set their values when the session/language dialogs are + * changed. + */ +static GtkWidget *session_widget = NULL; +static GtkWidget *language_widget = NULL; +static gchar *session_key = NULL; + +extern GList *sessions; +extern GHashTable *sessnames; + +enum +{ + GREETER_LIST_TEXT = 0, + GREETER_LIST_ID +}; + +/* + * This function sets the custom list when the session list has changed in + * the session dialog (launched from session button or F10 menu). + */ +void +greeter_custom_set_session (gchar *session) +{ + GList *tmp; + int i=0; + + /* + * Since the sessions are created before the session list is generated, + * keep track of the session and set active row when it is setup. This + * function will get a NULL when the session is initialized to NULL + * at startup, so just return. + */ + if (session == NULL) + return; + else + { + /* + * If the session_widget hasn't been setup yet (which it won't be when + * the greeter_sessioninit function is called, then just store the + * session and we'll set the value when the combo box is initialized later. + */ + g_free (session_key); + session_key = g_strdup (session); + } + + /* Do nothing if there is no session widget */ + if (session_widget == NULL) + return; + + /* Last isn't in the session list, so handle separate. */ + if (strcmp (session, LAST_SESSION) == 0) + { + if (GTK_IS_COMBO_BOX (session_widget)) + { + gtk_combo_box_set_active (GTK_COMBO_BOX (session_widget), 0); + } + else if (GTK_IS_SCROLLED_WINDOW (session_widget) && + GTK_IS_TREE_VIEW (GTK_BIN (session_widget)->child)) + { + GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (session_widget)->child); + GtkTreeModel *tm = gtk_tree_view_get_model (tv); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tv); + GtkTreeIter loopiter; + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter)) + gtk_tree_selection_select_iter (selection, &loopiter); + } + } + + /* + * Handle for either combo box or list style, depending on which is being + * used. + . */ + if (GTK_IS_COMBO_BOX (session_widget)) + { + for (tmp = sessions; tmp != NULL; tmp = tmp->next) + { + char *file; + + i++; + file = tmp->data; + if (strcmp (session, file) == 0) + { + gtk_combo_box_set_active (GTK_COMBO_BOX (session_widget), i); + break; + } + } + } + else if (GTK_IS_SCROLLED_WINDOW (session_widget) && + GTK_IS_TREE_VIEW (GTK_BIN (session_widget)->child)) + { + GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (session_widget)->child); + GtkTreeModel *tm = gtk_tree_view_get_model (tv); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tv); + GtkTreeIter loopiter; + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter)) + { + do + { + char *file; + + gtk_tree_model_get (GTK_TREE_MODEL (tm), &loopiter, GREETER_LIST_ID, &file, -1); + if (file != NULL && strcmp (session, file) == 0) + { + GtkTreePath *path = gtk_tree_model_get_path (tm, &loopiter); + + gtk_tree_selection_select_iter (selection, &loopiter); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tv), + path, NULL, + FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + break; + } + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tm), &loopiter)); + } + } +} + +/* + * This function sets the custom list when the language list has changed in + * the language dialog (launched from language button or F10 menu). + */ +void +lang_set_custom_callback (gchar *language) +{ + GtkListStore *lang_model = gdm_lang_get_model (); + GtkTreeIter iter; + gboolean valid; + char *locale_name; + int i=0; + + /* Do nothing if there is no language widget */ + if (language_widget == NULL) + return; + + /* + * Handle for either combo box or list style, depending on which is being + * used. + . */ + if (GTK_IS_COMBO_BOX (language_widget)) + { + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model), + &iter); + while (valid) + { + gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter, + LOCALE_COLUMN, &locale_name, -1); + + if (strcmp (language, locale_name) == 0) + { + gtk_combo_box_set_active (GTK_COMBO_BOX (language_widget), i); + break; + } + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter); + i++; + } + } + else if (GTK_IS_SCROLLED_WINDOW (language_widget) && + GTK_IS_TREE_VIEW (GTK_BIN (language_widget)->child)) + { + GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (language_widget)->child); + GtkTreeModel *tm = gtk_tree_view_get_model (tv); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tv); + GtkTreeIter loopiter; + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter)) + { + do + { + char *locale_file; + + gtk_tree_model_get (GTK_TREE_MODEL (tm), &loopiter, GREETER_LIST_ID, &locale_file, -1); + if (locale_file != NULL && strcmp (language, locale_file) == 0) + { + GtkTreePath *path = gtk_tree_model_get_path (tm, &loopiter); + + gtk_tree_selection_select_iter (selection, &loopiter); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tv), + path, NULL, + FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + break; + } + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tm), &loopiter)); + } + } +} + +/* Helper function to set custom list values */ +static void +populate_list (GtkTreeModel *tm, GtkTreeSelection *selection, GList *list_items) +{ + GList *li; + + for (li = list_items; li != NULL; li = li->next) + { + GtkTreeIter iter = {0}; + GreeterItemListItem *litem = li->data; + gtk_list_store_append (GTK_LIST_STORE (tm), &iter); + gtk_list_store_set (GTK_LIST_STORE (tm), &iter, + GREETER_LIST_TEXT, litem->text, + GREETER_LIST_ID, litem->id, + -1); + } +} + +/* Helper function to set session values */ +static void +populate_session (GObject * object) +{ + GList *tmp; + + /* Last isn't in the session list, so add separate. */ + if (GTK_IS_COMBO_BOX (object)) + gtk_combo_box_append_text (GTK_COMBO_BOX (object), _("Last session")); + else if (GTK_IS_TREE_MODEL (object)) + { + GtkTreeIter loopiter; + GtkTreeModel *tm = GTK_TREE_MODEL (object); + + gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter); + + gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter, + GREETER_LIST_TEXT, _("Last session"), + GREETER_LIST_ID, LAST_SESSION, + -1); + } + + /* Loop through the sessions and set the custom list values. */ + for (tmp = sessions; tmp != NULL; tmp = tmp->next) + { + GdmSession *session; + char *file; + + file = (char *) tmp->data; + session = g_hash_table_lookup (sessnames, file); + + if (GTK_IS_COMBO_BOX (object)) + { + if (session->clearname != NULL) + gtk_combo_box_append_text (GTK_COMBO_BOX (object), (session->clearname)); + else + gtk_combo_box_append_text (GTK_COMBO_BOX (object), (session->name)); + } + else if (GTK_IS_TREE_MODEL (object)) + { + GtkTreeIter loopiter; + GtkTreeModel *tm = GTK_TREE_MODEL (object); + gchar *to_display; + + gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter); + if (session->clearname != NULL) + to_display = session->clearname; + else + to_display = session->name; + + gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter, + GREETER_LIST_TEXT, to_display, + GREETER_LIST_ID, file, + -1); + } + } + + /* + * Set the session if one exists, this will calback and set the + * custom list + */ + if (session_key != NULL) + greeter_custom_set_session (session_key); +} + +/* Helper function to set language values */ +static void +populate_language (GObject *object) +{ + GtkListStore *lang_model = gdm_lang_get_model (); + GtkTreeIter iter; + char *name, *untranslated, *lang_display_name, *locale_name; + gboolean valid; + + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model), + &iter); + while (valid) + { + gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter, + TRANSLATED_NAME_COLUMN, &name, + UNTRANSLATED_NAME_COLUMN, &untranslated, + LOCALE_COLUMN, &locale_name, -1); + + if (untranslated) + lang_display_name = g_strdup_printf ("%s (%s)", name, untranslated); + else + lang_display_name = g_strdup (name); + + if (GTK_IS_COMBO_BOX (object)) + gtk_combo_box_append_text (GTK_COMBO_BOX (object), lang_display_name); + else if (GTK_IS_TREE_MODEL (object)) + { + GtkTreeIter loopiter; + GtkTreeModel *tm = GTK_TREE_MODEL (object); + + gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter); + gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter, + GREETER_LIST_TEXT, lang_display_name, + GREETER_LIST_ID, locale_name, + -1); + } + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter); + } +} + +/* Callback helper function to set session value */ +static void +combo_session_selected (char *session_val) +{ + GList *tmp; + char *file; + + /* Last isn't in the session list, so add separate. */ + if (strcmp (session_val, _("Last session")) == 0) + greeter_set_session (LAST_SESSION); + else + { + /* + * Loop through the sessions to find the row the + * user has selected, and set that session. + */ + for (tmp = sessions; tmp != NULL; tmp = tmp->next) + { + GdmSession *session; + char *name; + + file = tmp->data; + session = g_hash_table_lookup (sessnames, file); + + if (session->clearname) + name = session->clearname; + else + name = session->name; + + if (strcmp (name, session_val) == 0) + { + greeter_set_session (file); + break; + } + } + } +} + +/* Callback function for combo style custom lists */ +static void +combo_selected (GtkComboBox *combo, GreeterItemInfo *item) +{ + char *id = NULL; + char *file; + char *active; + + if (ve_string_empty (item->id)) + return; + + active = gtk_combo_box_get_active_text (combo); + + if (strcmp (item->id, "session") == 0) + { + combo_session_selected (active); + } + else if (strcmp (item->id, "language") == 0) + { + /* + * Since combo boxes can't store the ID value, have to do some + * extra work to figure out which row is selected. + */ + GtkListStore *lang_model = gdm_lang_get_model (); + GtkTreeIter iter; + char *name, *untranslated, *lang_display_name, *locale_name; + gboolean valid; + + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model), + &iter); + while (valid) + { + gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter, + TRANSLATED_NAME_COLUMN, &name, + UNTRANSLATED_NAME_COLUMN, &untranslated, + LOCALE_COLUMN, &locale_name, -1); + + if (untranslated) + lang_display_name = g_strdup_printf ("%s (%s)", name, untranslated); + else + lang_display_name = g_strdup (name); + + if (strcmp (lang_display_name, active) == 0) + { + gdm_lang_set_restart_dialog (locale_name); + break; + } + g_free (lang_display_name); + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter); + } + } + else + { + if (DOING_GDM_DEVELOPMENT) + return; + + id = gtk_combo_box_get_active_text (combo); + file = g_strdup_printf ("%s/%s.GreeterInfo", + ve_sure_string (gdm_config_get_string (GDM_KEY_SERV_AUTHDIR)), + ve_sure_string (g_getenv ("DISPLAY"))); + + gdm_save_customlist_data (file, item->id, id); + } +} + +/* Setup combo sytle custom list */ +static void +setup_combo_customlist (GtkComboBox *combo, GreeterItemInfo *item) +{ + GList *li; + + g_signal_connect (G_OBJECT (combo), "changed", + G_CALLBACK (combo_selected), item); + + /* Make sure that focus never leaves username/password entry */ + gtk_combo_box_set_focus_on_click (combo, FALSE); + + if (strcmp (item->id, "session") == 0) + { + populate_session (G_OBJECT (combo)); + /* + * Do not select since the session_init will initialize the + * value and cause the combo list to get set without needing + * to do it here. + */ + } + else if (strcmp (item->id, "language") == 0) + { + populate_language (G_OBJECT (combo)); + /* Select first */ + gtk_combo_box_set_active (combo, 0); + } + else + { + for (li = item->data.list.items; li != NULL; li = li->next) + { + GreeterItemListItem *litem = li->data; + gtk_combo_box_append_text (combo, litem->text); + } + /* Select first */ + gtk_combo_box_set_active (combo, 0); + } +} + +/* Callback function for list style custom lists */ +static void +list_selected (GtkTreeSelection *selection, GreeterItemInfo *item) +{ + GtkTreeModel *tm = NULL; + GtkTreeIter iter = {0}; + char *id = NULL; + char *file; + + if (ve_string_empty (item->id)) + return; + + if (gtk_tree_selection_get_selected (selection, &tm, &iter)) + { + gtk_tree_model_get (tm, &iter, GREETER_LIST_ID, + &id, -1); + } + + /* + * Note for session and language we are using the id to store the + * value to pass in. + */ + if (strcmp (item->id, "session") == 0) + { + if (id != NULL) + greeter_set_session (id); + } + else if (strcmp (item->id, "language") == 0) + { + if (id != NULL) + gdm_lang_set_restart_dialog (id); + } + else + { + if (DOING_GDM_DEVELOPMENT) + return; + + file = g_strdup_printf ("%s/%s.GreeterInfo", + ve_sure_string (gdm_config_get_string (GDM_KEY_SERV_AUTHDIR)), + ve_sure_string (g_getenv ("DISPLAY"))); + + gdm_save_customlist_data (file, item->id, id); + } +} + +static gboolean custom_list_release_event (GtkWidget *widget, + GdkEventSelection *event, + gpointer user_data) +{ + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + + /* Make sure that focus never leaves username/password entry */ + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + gtk_widget_grab_focus (entry); + } + return FALSE; +} + +/* Setup custom list style */ +static void +setup_customlist (GtkWidget *tv, GreeterItemInfo *item) +{ + GtkTreeModel *tm; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + GtkTreeIter iter = {0}; + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), + FALSE); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + + g_signal_connect (selection, "changed", + G_CALLBACK (list_selected), + item); + + tm = (GtkTreeModel *)gtk_list_store_new (2, + G_TYPE_STRING, + G_TYPE_STRING); + gtk_tree_view_set_model (GTK_TREE_VIEW (tv), tm); + + column = gtk_tree_view_column_new_with_attributes + ("Choice", + gtk_cell_renderer_text_new (), + "text", GREETER_LIST_TEXT, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + g_signal_connect (tv, "button_release_event", + G_CALLBACK (custom_list_release_event), + NULL); + + if (strcmp (item->id, "session") == 0) + { + populate_session (G_OBJECT (tm)); + /* + * Do not select since the session_init will initialize the + * value and cause the combo list to get set without needing + * to do it here. + */ + } + else if (strcmp (item->id, "language") == 0) + { + populate_language (G_OBJECT (tm)); + + /* Select first item */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } + else + { + populate_list (tm, selection, item->data.list.items); + + /* Select first item */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +/* + * This function initializes all custom lists aside from + * the userlist (face browser), which is handled + * separately. + */ +gboolean +greeter_item_customlist_setup (void) +{ + const GList *custom_items = greeter_custom_items (); + const GList *li; + for (li = custom_items; li != NULL; li = li->next) + { + GreeterItemInfo *info = li->data; + + if (info != NULL && + info->item_type == GREETER_ITEM_TYPE_LIST && + info->item != NULL && + GNOME_IS_CANVAS_WIDGET (info->item)) + { + GtkWidget *sw = GNOME_CANVAS_WIDGET (info->item)->widget; + + /* + * Store these so that when the values change in the + * F10 session/language dialogs, we can easily modify + * them. + */ + if (strcmp (info->id, "session") == 0) + session_widget = sw; + else if (strcmp (info->id, "language") == 0) + language_widget = sw; + + /* If combo or list style, process appropriately */ + if (GTK_IS_SCROLLED_WINDOW (sw) && + GTK_IS_TREE_VIEW (GTK_BIN (sw)->child)) + { + setup_customlist (GTK_BIN (sw)->child, info); + } + else if (GTK_IS_COMBO_BOX (sw)) + { + setup_combo_customlist (GTK_COMBO_BOX (sw), info); + } + } + } + return TRUE; +} + diff --git a/trunk/gui/greeter/greeter_item_customlist.h b/trunk/gui/greeter/greeter_item_customlist.h new file mode 100644 index 00000000..edcdd735 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_customlist.h @@ -0,0 +1,28 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_ITEM_CUSTOMLIST_H__ +#define __GREETER_ITEM_CUSTOMLIST_H__ + +#include "greeter_item.h" + +gboolean greeter_item_customlist_setup (void); +void greeter_custom_set_session (gchar *session); +void lang_set_custom_callback (gchar *language); + +#endif diff --git a/trunk/gui/greeter/greeter_item_pam.c b/trunk/gui/greeter/greeter_item_pam.c new file mode 100644 index 00000000..59fa1e46 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_pam.c @@ -0,0 +1,456 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> + +#include "gdm-common.h" +#include "gdm-socket-protocol.h" + +#include "greeter.h" +#include "greeter_item.h" +#include "greeter_item_pam.h" +#include "greeter_item_ulist.h" +#include "greeter_item_timed.h" +#include "greeter_parser.h" +#include "greeter_configuration.h" +#include "greeter_canvas_item.h" +#include "gdm.h" +#include "gdmwm.h" +#include "gdmcommon.h" + +static gboolean messages_to_give = FALSE; +static gboolean replace_msg = TRUE; +static guint err_box_clear_handler = 0; + +gchar *greeter_current_user = NULL; + +gboolean require_quarter = FALSE; + +extern gboolean greeter_probably_login_prompt; +extern GtkButton *gtk_ok_button; +extern GtkButton *gtk_start_again_button; + +static void +greeter_item_pam_error_set (gboolean display) +{ + GreeterItemInfo *info; + GnomeCanvasItem *item; + + info = greeter_lookup_id ("pam-error-logo"); + + if (info) + { + if (info->group_item != NULL) + item = GNOME_CANVAS_ITEM (info->group_item); + else + item = info->item; + + if (display) + gnome_canvas_item_show (item); + else + gnome_canvas_item_hide (item); + } +} + +void +greeter_item_pam_set_user (const char *user) +{ + g_free (greeter_current_user); + greeter_current_user = g_strdup (user); + greeter_item_ulist_set_user (user); +} + +static gboolean +evil (GtkEntry *entry, const char *user) +{ + /* do not translate */ + if (strcmp (user, "Gimme Random Cursor") == 0) { + gdm_common_setup_cursor (((rand () >> 3) % (GDK_LAST_CURSOR/2)) * 2); + gtk_entry_set_text (GTK_ENTRY (entry), ""); + return TRUE; + /* do not translate */ + } 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 */ + require_quarter = TRUE; + gtk_entry_set_text (GTK_ENTRY (entry), ""); + return TRUE; + } + + return FALSE; +} + +static void +set_text (GreeterItemInfo *info, const char *text) +{ + greeter_canvas_item_break_set_string (info, + text, + FALSE /* markup */, + info->data.text.real_max_width, + NULL /* width */, + NULL /* height */, + NULL /* canvas */, + info->item); +} + +void +greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info) +{ + const char *str; + char *tmp; + GreeterItemInfo *error_info; + + if (gtk_ok_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE); + if (gtk_start_again_button != NULL) + gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), FALSE); + + greeter_ignore_buttons (TRUE); + + str = gtk_entry_get_text (GTK_ENTRY (entry)); + if (greeter_probably_login_prompt && + /* evilness */ + evil (entry, str)) + { + /* obviously being 100% reliable is not an issue for + this test */ + gtk_entry_set_text (GTK_ENTRY (entry), ""); + return; + } + + if (greeter_probably_login_prompt && + ve_string_empty (str) && + greeter_item_timed_is_timed ()) + { + /* timed interruption */ + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN); + fflush (stdout); + return; + } + + gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE); + + /* clear the err_box */ + if (err_box_clear_handler > 0) + { + g_source_remove (err_box_clear_handler); + err_box_clear_handler = 0; + } + error_info = greeter_lookup_id ("pam-error"); + if (error_info) { + greeter_item_pam_error_set (FALSE); + set_text (error_info, ""); + } + + tmp = ve_locale_from_utf8 (str); + printf ("%c%s\n", STX, tmp); + fflush (stdout); + g_free (tmp); +} + +static gboolean +pam_key_release_event (GtkWidget *entry, GdkEventKey *event, gpointer data) +{ + GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry"); + + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + const char *login_string; + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + + if ((event->keyval == GDK_Tab || + event->keyval == GDK_KP_Tab) && + (event->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_SHIFT_MASK)) == 0) + { + greeter_item_pam_login (GTK_ENTRY (entry), entry_info); + return TRUE; + } + + if (gtk_ok_button != NULL) + { + /* + * Set ok button to sensitive only if there are characters in + * the entry field + */ + login_string = gtk_entry_get_text (GTK_ENTRY (entry)); + if (login_string != NULL && login_string[0] != '\0') + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), TRUE); + else + gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE); + } + } + return FALSE; +} + +gboolean +greeter_item_pam_setup (void) +{ + GreeterItemInfo *entry_info; + + greeter_item_pam_error_set (FALSE); + + entry_info = greeter_lookup_id ("user-pw-entry"); + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget)) + { + GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + gtk_widget_grab_focus (entry); + + if ( ! DOING_GDM_DEVELOPMENT) + { + /* hack. For some reason if we leave it blank, + * we'll get a little bit of activity on first keystroke, + * this way we get rid of it, it will be cleared for the + * first prompt anyway. */ + gtk_entry_set_text (GTK_ENTRY (entry), "..."); + + /* initially insensitive */ + gtk_widget_set_sensitive (entry, FALSE); + } + + g_signal_connect (entry, "activate", + G_CALLBACK (greeter_item_pam_login), entry_info); + g_signal_connect (G_OBJECT (entry), "key_release_event", + G_CALLBACK (pam_key_release_event), NULL); + } + + return TRUE; +} + + +void +greeter_item_pam_prompt (const char *message, + int entry_len, + gboolean entry_visible) +{ + GreeterItemInfo *conversation_info; + GreeterItemInfo *entry_info; + GtkWidget *entry; + + conversation_info = greeter_lookup_id ("pam-prompt"); + entry_info = greeter_lookup_id ("user-pw-entry"); + + if (conversation_info) + { + set_text (conversation_info, message); + + /* + * Add Accessibility text for entry field. + * Might be nice to set ATK_RELATION_LABEL_FOR, LABELLED_BY between + * the label (pam-prompt) and the entry, but gdmgreeter doesn't use real + * GTK widgets for text fields. For now, just set the entry field's + * name. + */ + if (entry_info != NULL) + { + GnomeCanvasWidget *item = GNOME_CANVAS_WIDGET (entry_info->item); + if (item != NULL) + { + GtkWidget *widget = item->widget; + if (widget != NULL) + { + AtkObject *atk_widget; + atk_widget = gtk_widget_get_accessible (widget); + if (atk_widget != NULL) + { + atk_object_set_name (atk_widget, message); + } + } + } + } + } + + if (entry_info && entry_info->item && + GNOME_IS_CANVAS_WIDGET (entry_info->item)) + { + entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; + + gtk_entry_set_visibility (GTK_ENTRY (entry), entry_visible); + gtk_widget_set_sensitive (GTK_WIDGET (entry), TRUE); + gtk_entry_set_max_length (GTK_ENTRY (entry), entry_len); + gtk_entry_set_text (GTK_ENTRY (entry), ""); + gtk_widget_grab_focus (entry); + } + + messages_to_give = FALSE; + replace_msg = TRUE; +} + +void +greeter_item_pam_message (const char *message) +{ + GreeterItemInfo *message_info; + char *oldtext; + char *newtext; + + /* the user has not yet seen messages */ + messages_to_give = TRUE; + + message_info = greeter_lookup_id ("pam-message"); + + if (message_info) + { + /* HAAAAAAACK. Sometimes pam sends many many messages, SO + * we try to collect them until the next prompt or reset or + * whatnot */ + if ( ! replace_msg && + /* empty message is for clearing */ + ! ve_string_empty (message)) + { + g_object_get (G_OBJECT (message_info->item), + "text", &oldtext, + NULL); + if (strlen (oldtext) > 0) + { + newtext = g_strdup_printf ("%s\n%s", oldtext, message); + set_text (message_info, newtext); + g_free (newtext); + } + else + set_text (message_info, message); + } + else + set_text (message_info, message); + } + replace_msg = FALSE; +} + + +static gboolean +error_clear (gpointer data) +{ + GreeterItemInfo *error_info = data; + err_box_clear_handler = 0; + + set_text (error_info, ""); + greeter_item_pam_error_set (FALSE); + + return FALSE; +} + +void +greeter_item_pam_error (const char *message) +{ + GreeterItemInfo *error_info; + + /* The message I got from pam had a silly newline + * in the beginning. That may make sense for a + * terminal based conversation, but it sucks for + * us, so skip it. + */ + if (message[0] == '\n') + message++; + + error_info = greeter_lookup_id ("pam-error"); + if (error_info) + { + set_text (error_info, message); + + if (err_box_clear_handler > 0) + g_source_remove (err_box_clear_handler); + + if (strlen (message) == 0) + err_box_clear_handler = 0; + else + err_box_clear_handler = g_timeout_add (30000, + error_clear, + error_info); + greeter_item_pam_error_set (TRUE); + } +} + +static GtkWidget * +hig_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GtkMessageType type, + GtkButtonsType buttons, + const gchar *primary_message, + const gchar *secondary_message) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + buttons, + "%s", primary_message); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", secondary_message); + + gtk_window_set_title (GTK_WINDOW (dialog), ""); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14); + + return dialog; +} + +void +greeter_item_pam_leftover_messages (void) +{ + if (messages_to_give) + { + char *oldtext = NULL; + GreeterItemInfo *message_info; + + message_info = greeter_lookup_id ("pam-message"); + + if (message_info != NULL) + { + g_object_get (G_OBJECT (message_info->item), + "text", &oldtext, + NULL); + } + + if ( ! ve_string_empty (oldtext)) + { + GtkWidget *dlg; + + /* we should be now fine for focusing new windows */ + gdm_wm_focus_new_windows (TRUE); + + dlg = hig_dialog_new (NULL /* parent */, + GTK_DIALOG_MODAL /* flags */, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + oldtext, + ""); + gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE); + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + gdm_wm_center_window (GTK_WINDOW (dlg)); + + gdm_wm_no_login_focus_push (); + gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); + gdm_wm_no_login_focus_pop (); + } + messages_to_give = FALSE; + } +} + diff --git a/trunk/gui/greeter/greeter_item_pam.h b/trunk/gui/greeter/greeter_item_pam.h new file mode 100644 index 00000000..0d1d3a6e --- /dev/null +++ b/trunk/gui/greeter/greeter_item_pam.h @@ -0,0 +1,36 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_ITEM_PAM_H +#define GREETER_ITEM_PAM_H + +#include "greeter_item.h" + +gboolean greeter_item_pam_setup (void); +void greeter_item_pam_prompt (const char *message, + int entry_len, + gboolean entry_visible); +void greeter_item_pam_message (const char *message); +void greeter_item_pam_error (const char *message); +void greeter_item_pam_set_user (const char *user); +void greeter_item_pam_leftover_messages (void); +void greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info); + +extern gchar *greeter_current_user; + +#endif diff --git a/trunk/gui/greeter/greeter_item_timed.c b/trunk/gui/greeter/greeter_item_timed.c new file mode 100644 index 00000000..ea6a50b6 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_timed.c @@ -0,0 +1,156 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "gdm.h" +#include "gdmconfig.h" + +#include "gdm-common.h" +#include "gdm-socket-protocol.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter_parser.h" +#include "greeter_configuration.h" +#include "greeter_item_timed.h" + +extern gint gdm_timed_delay; + +static guint timed_handler_id = 0; + +static void +greeter_item_timed_update (void) +{ + GreeterItemInfo *info; + + info = greeter_lookup_id ("timed-label"); + if (info != NULL) + { + greeter_item_update_text (info); + } +} + +/* + * Timed Login: Timer + */ + +static gboolean +gdm_timer (gpointer data) +{ + greeter_item_timed_update (); + gdm_timed_delay--; + if (gdm_timed_delay <= 0) + { + /* timed interruption */ + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN); + fflush (stdout); + } + return TRUE; +} + +/* + * Timed Login: On GTK events, increase delay to at least 30 + * seconds. Or the GDM_KEY_TIMED_LOGIN_DELAY, whichever is higher + */ + +static gboolean +gdm_timer_up_delay (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + int timeddelay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY); + + if (gdm_timed_delay < 30) + gdm_timed_delay = 30; + if (gdm_timed_delay < timeddelay) + gdm_timed_delay = timeddelay; + return TRUE; +} + +gboolean +greeter_item_timed_setup (void) +{ + + /* if in timed mode, delay timeout on keyboard or menu activity */ + if ( ! ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN))) + { + guint sid; + + g_type_class_ref (GTK_TYPE_MENU_ITEM); + + sid = g_signal_lookup ("activate", + GTK_TYPE_MENU_ITEM); + g_signal_add_emission_hook (sid, + 0 /* detail */, + gdm_timer_up_delay, + NULL /* data */, + NULL /* destroy_notify */); + + sid = g_signal_lookup ("key_press_event", + GTK_TYPE_WIDGET); + g_signal_add_emission_hook (sid, + 0 /* detail */, + gdm_timer_up_delay, + NULL /* data */, + NULL /* destroy_notify */); + sid = g_signal_lookup ("button_press_event", + GTK_TYPE_WIDGET); + g_signal_add_emission_hook (sid, + 0 /* detail */, + gdm_timer_up_delay, + NULL /* data */, + NULL /* destroy_notify */); + } + + return TRUE; +} + +void +greeter_item_timed_start (void) +{ + int timeddelay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY); + + if (timed_handler_id == 0 && + gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) && + ! ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN)) && + timeddelay > 0) + { + gdm_timed_delay = timeddelay; + timed_handler_id = g_timeout_add (1000, gdm_timer, NULL); + } +} + +void +greeter_item_timed_stop (void) +{ + if (timed_handler_id != 0) + { + g_source_remove (timed_handler_id); + timed_handler_id = 0; + } +} + +gboolean +greeter_item_timed_is_timed (void) +{ + return timed_handler_id != 0; +} diff --git a/trunk/gui/greeter/greeter_item_timed.h b/trunk/gui/greeter/greeter_item_timed.h new file mode 100644 index 00000000..bd544adc --- /dev/null +++ b/trunk/gui/greeter/greeter_item_timed.h @@ -0,0 +1,29 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_ITEM_TIMED_H +#define GREETER_ITEM_TIMED_H + +#include "greeter_item.h" + +gboolean greeter_item_timed_setup (void); +void greeter_item_timed_start (void); +void greeter_item_timed_stop (void); +gboolean greeter_item_timed_is_timed (void); + +#endif diff --git a/trunk/gui/greeter/greeter_item_ulist.c b/trunk/gui/greeter/greeter_item_ulist.c new file mode 100644 index 00000000..20cad3e4 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_ulist.c @@ -0,0 +1,479 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <math.h> +#include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <librsvg/rsvg.h> + +#include "gdm.h" +#include "gdmcommon.h" +#include "gdmcomm.h" +#include "gdmconfig.h" +#include "gdmuser.h" + +#include "gdm-common.h" +#include "gdm-socket-protocol.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter.h" +#include "greeter_item_ulist.h" +#include "greeter_parser.h" +#include "greeter_configuration.h" +#include "greeter_item.h" + +static GList *users = NULL; +static GList *users_string = NULL; +static GdkPixbuf *defface; +static GHashTable *displays_hash = NULL; + +static GtkWidget *pam_entry = NULL; +static GtkWidget *user_list = NULL; +static gboolean selecting_user = FALSE; +static gchar *selected_user = NULL; +static int num_users = 0; + +enum +{ + GREETER_ULIST_ICON_COLUMN = 0, + GREETER_ULIST_LABEL_COLUMN, + GREETER_ULIST_LOGIN_COLUMN, + GREETER_ULIST_ACTIVE_COLUMN +}; + +/* Hide the userlist if there are no users displayed */ +void +greeter_item_ulist_check_show_userlist (void) +{ + /* + * If the browser feature isn't enabled or if there are no users, + * then hide the rectangle used to contain the userlist. The + * userlist-rect id allows a rectangle to be defined with alpha + * behind the userlist that also goes away when the list is empty. + */ + if (num_users == 0 || !gdm_config_get_bool (GDM_KEY_BROWSER)) { + + GreeterItemInfo *urinfo = greeter_lookup_id ("userlist-rect"); + + if (user_list != NULL) + gtk_widget_hide (user_list); + + if (urinfo) { + GnomeCanvasItem *item; + + if (urinfo->group_item != NULL) + item = GNOME_CANVAS_ITEM (urinfo->group_item); + else + item = urinfo->item; + + gnome_canvas_item_hide (item); + } + } +} + +void +greeter_item_ulist_unset_selected_user (void) +{ + GtkTreeSelection *selection; + if (user_list != NULL) { + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_list)); + gtk_tree_selection_unselect_all (GTK_TREE_SELECTION (selection)); + } + + if (selected_user != NULL) + g_free (selected_user); + selected_user = NULL; +} + +static int +vector_len (char * const *v) +{ + int i; + if (v == NULL) + return 0; + for (i = 0; v[i] != NULL; i++) + ; + return i; +} + +static void +check_for_displays (void) +{ + char *ret; + char **vec; + char *auth_cookie = NULL; + int i; + + /* + * Might be nice to move this call into read_config() so that it happens + * on the same socket call as reading the configuration. + */ + ret = gdmcomm_call_gdm (GDM_SUP_ATTACHED_SERVERS, auth_cookie, "2.2.4.0", 5); + if (ve_string_empty (ret) || strncmp (ret, "OK ", 3) != 0) { + g_free (ret); + return; + } + + vec = g_strsplit (&ret[3], ";", -1); + g_free (ret); + if (vec == NULL) + return; + + if (displays_hash == NULL) + displays_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + for (i = 0; vec[i] != NULL; i++) { + char **rvec; + + rvec = g_strsplit (vec[i], ",", -1); + if (rvec == NULL || vector_len (rvec) != 3) + continue; + + g_hash_table_insert (displays_hash, + g_strdup (rvec[1]), + g_strdup (rvec[0])); + + g_strfreev (rvec); + } + + g_strfreev (vec); +} + +static void +gdm_greeter_users_init (void) +{ + gint size_of_users = 0; + + defface = gdm_common_get_face (NULL, + gdm_config_get_string (GDM_KEY_DEFAULT_FACE), + gdm_config_get_int (GDM_KEY_MAX_ICON_WIDTH), + gdm_config_get_int (GDM_KEY_MAX_ICON_HEIGHT)); + if (! defface) { + gdm_common_warning ("Can't open DefaultImage: %s!", + gdm_config_get_string (GDM_KEY_DEFAULT_FACE)); + } + + gdm_users_init (&users, &users_string, NULL, defface, + &size_of_users, GDM_IS_LOCAL, !DOING_GDM_DEVELOPMENT); +} + +static void +greeter_populate_user_list (GtkTreeModel *tm) +{ + GList *li; + + for (li = users; li != NULL; li = li->next) { + GdmUser *usr = li->data; + GtkTreeIter iter = {0}; + char *label; + char *name; + gboolean active; + + if (usr->gecos && strcmp (usr->gecos, "") != 0) { + name = gdm_common_text_to_escaped_utf8 (usr->gecos); + } else { + name = gdm_common_text_to_escaped_utf8 (usr->login); + } + + if (g_hash_table_lookup (displays_hash, usr->login)) + active = TRUE; + else + active = FALSE; + + if (active) { + label = g_strdup_printf ("<b>%s</b>\n <i><small>%s</small></i>", + name, + _("Already logged in")); + } else { + label = g_strdup_printf ("<b>%s</b>\n", + name); + } + + g_free (name); + + gtk_list_store_append (GTK_LIST_STORE (tm), &iter); + gtk_list_store_set (GTK_LIST_STORE (tm), &iter, + GREETER_ULIST_ICON_COLUMN, usr->picture, + GREETER_ULIST_LOGIN_COLUMN, usr->login, + GREETER_ULIST_LABEL_COLUMN, label, + GREETER_ULIST_ACTIVE_COLUMN, active, + -1); + g_free (label); + num_users++; + } +} + +void +greeter_item_ulist_select_user (gchar *login) +{ + printf ("%c%c%c%s\n", STX, BEL, + GDM_INTERRUPT_SELECT_USER, login); + + fflush (stdout); +} + +static void +user_selected (GtkTreeSelection *selection, gpointer data) +{ + GtkTreeModel *tm = NULL; + GtkTreeIter iter = {0}; + + if (gtk_tree_selection_get_selected (selection, &tm, &iter)) { + char *login; + + gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN, + &login, -1); + if (login != NULL) { + if (selecting_user && greeter_probably_login_prompt) { + gtk_entry_set_text (GTK_ENTRY (pam_entry), login); + } + if (selecting_user) { + GreeterItemInfo *pamlabel = greeter_lookup_id ("pam-message"); + if (pamlabel == NULL) { + gdm_common_warning ("Theme broken: must have pam-message label!"); + } + greeter_item_ulist_select_user (login); + if (selected_user != NULL) + g_free (selected_user); + selected_user = g_strdup (login); + } + } + } +} + +static void +browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + gtk_widget_grab_focus (pam_entry); +} + +static void +greeter_generate_userlist (GtkWidget *tv, GreeterItemInfo *info) +{ + GtkTreeModel *tm; + GtkTreeViewColumn *column_one, *column_two; + GtkTreeSelection *selection; + GList *list, *li; + + gdm_greeter_users_init (); + + check_for_displays (); + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), + FALSE); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + if (users != NULL) { + g_signal_connect (selection, "changed", + G_CALLBACK (user_selected), + NULL); + + g_signal_connect (GTK_TREE_VIEW (tv), "button_release_event", + G_CALLBACK (browser_change_focus), + NULL); + + tm = (GtkTreeModel *)gtk_list_store_new (4, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + gtk_tree_view_set_model (GTK_TREE_VIEW (tv), tm); + column_one = gtk_tree_view_column_new_with_attributes (_("Icon"), + gtk_cell_renderer_pixbuf_new (), + "pixbuf", GREETER_ULIST_ICON_COLUMN, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column_one); + + column_two = gtk_tree_view_column_new_with_attributes (_("Username"), + gtk_cell_renderer_text_new (), + "markup", GREETER_ULIST_LABEL_COLUMN, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column_two); + + /* Only populate the user list if the browser is turned on */ + if (gdm_config_get_bool (GDM_KEY_BROWSER)) + greeter_populate_user_list (tm); + + list = gtk_tree_view_column_get_cell_renderers (column_one); + for (li = list; li != NULL; li = li->next) { + GtkObject *cell = li->data; + + if (info->data.list.icon_color != NULL) + g_object_set (cell, "cell-background", + info->data.list.icon_color, NULL); + } + + list = gtk_tree_view_column_get_cell_renderers (column_two); + for (li = list; li != NULL; li = li->next) { + GtkObject *cell = li->data; + + if (info->data.list.label_color != NULL) + g_object_set (cell, "background", + info->data.list.label_color, NULL); + } + } + + /* we are done with the hash */ + g_hash_table_destroy (displays_hash); + displays_hash = NULL; +} + +static inline void +force_no_tree_separators (GtkWidget *widget) +{ + gboolean first_time = TRUE; + + if (first_time) { + gtk_rc_parse_string ("\n" + " style \"gdm-userlist-treeview-style\"\n" + " {\n" + " GtkTreeView::horizontal-separator=0\n" + " GtkTreeView::vertical-separator=0\n" + " }\n" + "\n" + " widget \"*.gdm-userlist-treeview\" style \"gdm-userlist-treeview-style\"\n" + "\n"); + first_time = FALSE; + } + + gtk_widget_set_name (widget, "gdm-userlist-treeview"); +} + +gboolean +greeter_item_ulist_setup (void) +{ + GreeterItemInfo *info; + + info = greeter_lookup_id ("user-pw-entry"); + if (info && info->item && + GNOME_IS_CANVAS_WIDGET (info->item) && + GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (info->item)->widget)) { + pam_entry = GNOME_CANVAS_WIDGET (info->item)->widget; + } + + info = greeter_lookup_id ("userlist"); + + if (info && info->item && + GNOME_IS_CANVAS_WIDGET (info->item)) { + GtkWidget *sw = GNOME_CANVAS_WIDGET (info->item)->widget; + + if (GTK_IS_SCROLLED_WINDOW (sw) && + GTK_IS_TREE_VIEW (GTK_BIN (sw)->child)) { + GtkRequisition req; + gdouble height; + + user_list = GTK_BIN (sw)->child; + + force_no_tree_separators (user_list); + + greeter_generate_userlist (user_list, info); + + /* Reset size of the widget canvas item so it + * is the same size as the userlist. This + * avoids the ugly white background displayed + * below the Face Browser when the list isn't + * as large as the rectangle defined in the + * GDM theme file. + */ + + gtk_widget_size_request (user_list, &req); + g_object_get (info->item, "height", &height, NULL); + + if (req.height < height) + g_object_set (info->item, "height", (double)req.height, NULL); + } + } + + return TRUE; +} + +void +greeter_item_ulist_enable (void) +{ + selecting_user = TRUE; + if (user_list != NULL) + gtk_widget_set_sensitive (user_list, TRUE); +} + +void +greeter_item_ulist_disable (void) +{ + selecting_user = FALSE; + if (user_list != NULL) + gtk_widget_set_sensitive (user_list, FALSE); +} + +void +greeter_item_ulist_set_user (const char *user) +{ + gboolean old_selecting_user = selecting_user; + GtkTreeSelection *selection; + GtkTreeIter iter = {0}; + GtkTreeModel *tm = NULL; + + if (user_list == NULL) + return; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_list)); + gtk_tree_selection_unselect_all (selection); + + if (ve_string_empty (user)) + return; + + /* Make sure we don't set the pam_entry and pam label stuff, + this is programatic selection, not user selection */ + selecting_user = FALSE; + + tm = gtk_tree_view_get_model (GTK_TREE_VIEW (user_list)); + + if (gtk_tree_model_get_iter_first (tm, &iter)) { + do { + char *login; + + gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN, + &login, -1); + if (login != NULL && strcmp (user, login) == 0) { + GtkTreePath *path = gtk_tree_model_get_path (tm, &iter); + + gtk_tree_selection_select_iter (selection, &iter); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (user_list), + path, NULL, + FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + break; + } + + } while (gtk_tree_model_iter_next (tm, &iter)); + } + selecting_user = old_selecting_user; +} diff --git a/trunk/gui/greeter/greeter_item_ulist.h b/trunk/gui/greeter/greeter_item_ulist.h new file mode 100644 index 00000000..8bf2b568 --- /dev/null +++ b/trunk/gui/greeter/greeter_item_ulist.h @@ -0,0 +1,32 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef GREETER_ITEM_ULIST_H +#define GREETER_ITEM_ULIST_H + +#include "greeter_item.h" + +gboolean greeter_item_ulist_setup (void); +void greeter_item_ulist_enable (void); +void greeter_item_ulist_disable (void); +void greeter_item_ulist_set_user (const char *user); +void greeter_item_ulist_unset_selected_user (void); +void greeter_item_ulist_select_user (gchar *login); +void greeter_item_ulist_check_show_userlist (void); + +#endif diff --git a/trunk/gui/greeter/greeter_parser.c b/trunk/gui/greeter/greeter_parser.c new file mode 100644 index 00000000..2a131fc0 --- /dev/null +++ b/trunk/gui/greeter/greeter_parser.c @@ -0,0 +1,1997 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <gtk/gtk.h> +#include <libxml/parser.h> +#include <string.h> +#include <stdlib.h> +#include <librsvg/rsvg.h> +#include <math.h> +#include <locale.h> +#include <glib/gi18n.h> +#include <gdk/gdkx.h> +#include <syslog.h> + +#include "gdmwm.h" +#include "gdmcommon.h" +#include "gdmconfig.h" + +#include "gdm-common.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter_configuration.h" +#include "greeter_parser.h" +#include "greeter_events.h" +#include "gdm.h" + +/* FIXME: hack */ +extern GreeterItemInfo *welcome_string_info; + +/* evil globals */ +static char *file_search_path = NULL; +static GList *button_stack = NULL; + +static GHashTable *pixbuf_hash = NULL; + +GHashTable *item_hash = NULL; +GList *custom_items = NULL; + +static gboolean parse_items (xmlNodePtr node, + GList **items_out, + GreeterItemInfo *parent, + GError **error); + +static GdkPixbuf * +load_pixbuf (const char *fname, GError **error) +{ + GdkPixbuf *pb; + + if (pixbuf_hash == NULL) + pixbuf_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)g_object_unref); + pb = g_hash_table_lookup (pixbuf_hash, fname); + if (pb != NULL) + return g_object_ref (pb); + + pb = gdk_pixbuf_new_from_file (fname, error); + if G_UNLIKELY (pb == NULL) + return NULL; + + g_hash_table_insert (pixbuf_hash, g_strdup (fname), g_object_ref (pb)); + + return pb; +} + +GQuark +greeter_parser_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("greeter_parser_error"); + + return quark; +} + + +GreeterItemInfo * +greeter_lookup_id (const char *id) +{ + GreeterItemInfo key; + GreeterItemInfo *info; + + key.id = (char *)id; + info = g_hash_table_lookup (item_hash, &key); + + return info; +} + +static void +parse_id (xmlNodePtr node, + GreeterItemInfo *info) +{ + xmlChar *prop; + + prop = xmlGetProp (node, (const xmlChar *) "id"); + + if (prop) + { + info->id = g_strdup ((char *) prop); + g_hash_table_insert (item_hash, info, info); + xmlFree (prop); + } +} + +/* Doesn't set the parts of rect that are not specified. + * If you want specific default values you need to fill them out + * in rect first + */ +static gboolean +parse_pos (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + char *p; + + prop = xmlGetProp (node, (const xmlChar *) "anchor"); + if (prop) + { + if (strcmp ((char *) prop, "center") == 0) + info->anchor = GTK_ANCHOR_CENTER; + else if (strcmp ((char *) prop, "c") == 0) + info->anchor = GTK_ANCHOR_CENTER; + else if (strcmp ((char *) prop, "nw") == 0) + info->anchor = GTK_ANCHOR_NW; + else if (strcmp ((char *) prop, "n") == 0) + info->anchor = GTK_ANCHOR_N; + else if (strcmp ((char *) prop, "ne") == 0) + info->anchor = GTK_ANCHOR_NE; + else if (strcmp ((char *) prop, "w") == 0) + info->anchor = GTK_ANCHOR_W; + else if (strcmp ((char *) prop, "e") == 0) + info->anchor = GTK_ANCHOR_E; + else if (strcmp ((char *) prop, "sw") == 0) + info->anchor = GTK_ANCHOR_SW; + else if (strcmp ((char *) prop, "s") == 0) + info->anchor = GTK_ANCHOR_S; + else if (strcmp ((char *) prop, "se") == 0) + info->anchor = GTK_ANCHOR_SE; + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Unknown anchor type %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + + prop = xmlGetProp (node,(const xmlChar *) "x"); + if (prop) + { + info->x = g_ascii_strtod ((char *) prop, &p); + + if ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad position specifier %s", prop); + xmlFree (prop); + return FALSE; + } + + if (prop[0] == '-' || info->x < 0) + info->x_negative = TRUE; + else + info->x_negative = FALSE; + + if (strchr ((char *) prop, '%') != NULL) + info->x_type = GREETER_ITEM_POS_RELATIVE; + else + info->x_type = GREETER_ITEM_POS_ABSOLUTE; + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "y"); + if (prop) + { + info->y = g_ascii_strtod ((char *) prop, &p); + + if ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad position specifier %s", prop); + xmlFree (prop); + return FALSE; + } + + if (prop[0] == '-' || info->y < 0) + info->y_negative = TRUE; + else + info->y_negative = FALSE; + + if (strchr ((char *) prop, '%') != NULL) + info->y_type = GREETER_ITEM_POS_RELATIVE; + else + info->y_type = GREETER_ITEM_POS_ABSOLUTE; + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "width"); + if (prop) + { + if (strcmp ((char *) prop, "box") == 0) + info->width_type = GREETER_ITEM_SIZE_BOX; + else if (strcmp ((char *) prop, "scale") == 0) + info->width_type = GREETER_ITEM_SIZE_SCALE; + else + { + info->width = g_ascii_strtod ((char *) prop, &p); + + if ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad size specifier %s", prop); + xmlFree (prop); + return FALSE; + } + + if (strchr ((char *) prop, '%') != NULL) + info->width_type = GREETER_ITEM_SIZE_RELATIVE; + else + info->width_type = GREETER_ITEM_SIZE_ABSOLUTE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "height"); + if (prop) + { + if (strcmp ((char *) prop, "box") == 0) + info->height_type = GREETER_ITEM_SIZE_BOX; + else if (strcmp ((char *) prop, "scale") == 0) + info->height_type = GREETER_ITEM_SIZE_SCALE; + else + { + info->height = g_ascii_strtod ((char *) prop, &p); + + if ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad size specifier %s", prop); + xmlFree (prop); + return FALSE; + } + + if (strchr ((char *) prop, '%') != NULL) + info->height_type = GREETER_ITEM_SIZE_RELATIVE; + else + info->height_type = GREETER_ITEM_SIZE_ABSOLUTE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "expand"); + if (prop) + { + if (strcmp ((char *) prop, "true") == 0) + { + info->expand = TRUE; + } + else if (strcmp ((char *) prop, "false") == 0) + { + info->expand = FALSE; + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad expand spec %s", prop); + xmlFree (prop); + return FALSE; + } + + xmlFree (prop); + } + + return TRUE; +} + +/* We pass the same arguments as to translated text, since we'll override it + * with translation score */ +static gboolean +parse_stock (xmlNodePtr node, + GreeterItemInfo *info, + char **translated_text, + gint *translation_score, + GError **error) +{ + xmlChar *prop; + + prop = xmlGetProp (node,(const xmlChar *) "type"); + if (prop) + { + if (g_ascii_strcasecmp ((char *) prop, "language") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Language")); + } + else if (g_ascii_strcasecmp ((char *) prop, "session") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Session")); + } + else if (g_ascii_strcasecmp ((char *) prop, "system") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Actions")); + } + else if (g_ascii_strcasecmp ((char *) prop, "disconnect") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("D_isconnect")); + } + else if (g_ascii_strcasecmp ((char *) prop, "quit") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Quit")); + } + else if (g_ascii_strcasecmp ((char *) prop, "halt") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Shut _Down")); + } + else if (g_ascii_strcasecmp ((char *) prop, "suspend") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Sus_pend")); + } + else if (g_ascii_strcasecmp ((char *) prop, "reboot") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Restart")); + } + else if (g_ascii_strcasecmp ((char *) prop, "chooser") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Remote Login via _XDMCP")); + } + else if (g_ascii_strcasecmp ((char *) prop, "config") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Confi_gure")); + } + else if (g_ascii_strcasecmp ((char *) prop, "options") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Op_tions")); + } + else if (g_ascii_strcasecmp ((char *) prop, "caps-lock-warning") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Caps Lock is on.")); + } + else if (g_ascii_strcasecmp ((char *) prop, "timed-label") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("User %u will login in %t")); + } + else if (g_ascii_strcasecmp ((char *) prop, "welcome-label") == 0) + { + /* FIXME: hack */ + welcome_string_info = info; + + g_free (*translated_text); + *translated_text = gdm_common_get_welcomemsg (); + } + /* FIXME: is this actually needed? */ + else if (g_ascii_strcasecmp ((char *) prop, "username-label") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("Username:")); + } + else if (g_ascii_strcasecmp ((char *) prop, "ok") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_OK")); + } + else if (g_ascii_strcasecmp ((char *) prop, "cancel") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Cancel")); + } + else if (g_ascii_strcasecmp ((char *) prop, "startagain") == 0) + { + g_free (*translated_text); + *translated_text = g_strdup (_("_Start Again")); + } + else + { + gboolean is_error = TRUE; + register int i = 0; + for (; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gchar * key_string = NULL; + key_string = g_strdup_printf ("custom_cmd%d", i); + if (g_ascii_strcasecmp ((char *) prop, key_string) == 0) { + g_free (*translated_text); + g_free (key_string); + key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i); + *translated_text = g_strdup(gdm_config_get_string (key_string)); + g_free (key_string); + is_error = FALSE; + break; + } + g_free (key_string); + } + + if (is_error) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad stock label type"); + xmlFree (prop); + return FALSE; + } + } + + /* This is the very very very best "translation" */ + *translation_score = -1; + + xmlFree (prop); + + return TRUE; + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Stock type not specified"); + return FALSE; + } +} + +static void +do_font_size_reduction (GreeterItemInfo *info) +{ + double size_reduction = 1.0; + int i; + + if (gdm_wm_screen.width <= 800 && + gdm_wm_screen.width > 640) + size_reduction = PANGO_SCALE_SMALL; + else if (gdm_wm_screen.width <= 640) + size_reduction = PANGO_SCALE_X_SMALL; + + if (size_reduction < 0.99) + { + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if (info->data.text.fonts[i] != NULL) + { + int old_size = pango_font_description_get_size (info->data.text.fonts[i]); + pango_font_description_set_size (info->data.text.fonts[i], old_size * size_reduction); + } + } + } +} + + +static gboolean +parse_canvasbutton (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + + prop = xmlGetProp (node,(const xmlChar *) "button"); + if (prop) + { + if (strcmp ((char *) prop, "true") == 0) + { + info->canvasbutton = TRUE; + } + else if (strcmp ((char *) prop, "false") == 0) + { + info->canvasbutton = FALSE; + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "bad button spec %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + return TRUE; +} + +static gboolean +parse_gtkbutton (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + char *translated_text = NULL; + gint translation_score = 1000; + + child = node->children; + + while (child) + { + if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + } + else if (child->type == XML_ELEMENT_NODE && + strcmp ((char *) child->name, "stock") == 0) + { + if G_UNLIKELY (!parse_stock (child, info, &translated_text, &translation_score, error)) + return FALSE; + } + + child = child->next; + } + + if (translated_text == NULL) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "A label must specify the text attribute"); + return FALSE; + } + + /* FIXME: evil hack to use internally translated strings */ + if (translation_score == 999 && + ! ve_string_empty (translated_text)) + { + char *foo = g_strdup (_(translated_text)); + g_free (translated_text); + translated_text = foo; + } + + info->data.text.orig_text = translated_text; + + return TRUE; +} + +static gboolean +parse_show (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + char **argv = NULL; + int i; + + prop = xmlGetProp (node,(const xmlChar *) "type"); + if (prop != NULL) + { + g_free (info->show_type); + info->show_type = g_strdup ((char *) prop); + xmlFree (prop); + } + + /* Note: subtype is deprecated, use type only */ + prop = xmlGetProp (node,(const xmlChar *) "subtype"); + if G_UNLIKELY (prop != NULL) + { + /* code for legacy uses of subtype only, are there any such + * themes out there? The Bluecurve was the one this was made + * for and bluecurve is NOT using it. */ + if (info->show_type == NULL || + strcmp (info->show_type, "system") == 0) { + g_free (info->show_type); + info->show_type = g_strdup ((char *) prop); + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "min-screen-width"); + if (prop != NULL) + { + g_warning ("minimum width is %d", info->minimum_required_screen_height); + info->minimum_required_screen_width = atoi ((char *) prop); + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "min-screen-height"); + if (prop != NULL) + { + info->minimum_required_screen_height = atoi ((char *) prop); + g_warning ("minimum height is %d", info->minimum_required_screen_height); + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "modes"); + if (prop != NULL) + { + if (strcmp ((char *) prop, "everywhere") == 0) + { + info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE; + xmlFree (prop); + return TRUE; + } + else if (strcmp ((char *) prop, "nowhere") == 0) + { + info->show_modes = GREETER_ITEM_SHOW_NOWHERE; + xmlFree (prop); + return TRUE; + } + + argv = g_strsplit ((char *) prop, ",", 0); + xmlFree (prop); + } + else + { + info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE; + return TRUE; + } + + info->show_modes = GREETER_ITEM_SHOW_NOWHERE; + + if (argv != NULL) + { + for (i = 0; argv[i] != NULL; i++) + { + if (strcmp (argv[i], "console") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_CONSOLE; + } + else if (strcmp (argv[i], "console-fixed") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_CONSOLE_FIXED; + } + else if (strcmp (argv[i], "console-flexi") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_CONSOLE_FLEXI; + } + else if (strcmp (argv[i], "remote-flexi") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_REMOTE_FLEXI; + } + else if (strcmp (argv[i], "flexi") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_FLEXI; + } + else if (strcmp (argv[i], "remote") == 0) + { + info->show_modes |= GREETER_ITEM_SHOW_REMOTE; + } + } + g_strfreev (argv); + } + return TRUE; +} + +static gboolean +parse_fixed (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + return parse_items (node, + &info->fixed_children, + info, + error); +} + +static gboolean +parse_box (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + char *p; + + prop = xmlGetProp (node,(const xmlChar *) "orientation"); + if (prop) + { + if (strcmp ((char *) prop, "horizontal") == 0) + { + info->box_orientation = GTK_ORIENTATION_HORIZONTAL; + } + else if (strcmp ((char *) prop, "vertical") == 0) + { + info->box_orientation = GTK_ORIENTATION_VERTICAL; + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad orientation %s", prop); + xmlFree (prop); + return FALSE; + } + + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "homogeneous"); + if (prop) + { + if (strcmp ((char *) prop, "true") == 0) + { + info->box_homogeneous = TRUE; + } + else if (strcmp ((char *) prop, "false") == 0) + { + info->box_homogeneous = FALSE; + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad homogenous spec %s", prop); + xmlFree (prop); + return FALSE; + } + + xmlFree (prop); + } + + + prop = xmlGetProp (node,(const xmlChar *) "xpadding"); + if (prop) + { + info->box_x_padding = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad padding specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "ypadding"); + if (prop) + { + info->box_y_padding = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad padding specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "min-width"); + if (prop) + { + info->box_min_width = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad min-width specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "min-height"); + if (prop) + { + info->box_min_height = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad min-height specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "spacing"); + if (prop) + { + info->box_spacing = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad spacing specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + return parse_items (node, + &info->box_children, + info, + error); + +} + + +static gboolean +parse_color (const char *str, + guint32 *col_out, + GError **error) +{ + guint32 col; + int i; + if G_UNLIKELY (str[0] != '#') + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "colors must start with #, %s is an invalid color", str); + return FALSE; + } + if G_UNLIKELY (strlen (str) != 7) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Colors must be on the format #xxxxxx, %s is an invalid color", str); + return FALSE; + } + + col = 0; + + for (i = 0; i < 6; i++) + col = (col << 4) | g_ascii_xdigit_value (str[i+1]); + + *col_out = col; + + return TRUE; +} + +static gboolean +parse_state_file_pixmap (xmlNodePtr node, + GreeterItemInfo *info, + GreeterItemState state, + GError **error) +{ + xmlChar *prop; + char *p; + + info->have_state |= (1<<state); + + prop = xmlGetProp (node,(const xmlChar *) "file"); + if (prop) + { + if (g_path_is_absolute ((char *) prop)) + info->data.pixmap.files[state] = g_strdup ((char *) prop); + else + info->data.pixmap.files[state] = g_build_filename (file_search_path, + (char *) prop, + NULL); + + xmlFree (prop); + } + + { + int i = 1; + char *altfile_prop_name = g_strdup_printf ("altfile%d", i); + + prop = xmlGetProp (node,(const xmlChar *) altfile_prop_name); + while (prop) + { + char *filename = NULL; + if (g_path_is_absolute ((char *) prop)) + filename = g_strdup ((char *) prop); + else + filename = g_build_filename (file_search_path, + (char *) prop, + NULL); + + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + { + if (info->data.pixmap.files[state]) + g_free (info->data.pixmap.files[state]); + info->data.pixmap.files[state] = filename; + } + xmlFree (prop); + g_free (altfile_prop_name); + + i++; + altfile_prop_name = g_strdup_printf ("altfile%d", i); + prop = xmlGetProp (node,(const xmlChar *) altfile_prop_name); + } + g_free (altfile_prop_name); + } + + prop = xmlGetProp (node,(const xmlChar *) "tint"); + if (prop) + { + if (!parse_color ((char *) prop, &info->data.pixmap.tints[state], error)) + return FALSE; + info->data.pixmap.have_tint |= (1<<state); + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "alpha"); + if (prop) + { + double alpha = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad alpha specifier format %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + + if (alpha >= 1.0) + info->data.pixmap.alphas[state] = 0xff; + else if (alpha < 0) + info->data.pixmap.alphas[state] = 0; + else + info->data.pixmap.alphas[state] = floor (alpha * 0xff); + } + + return TRUE; +} + +static gboolean +parse_state_color_rect (xmlNodePtr node, + GreeterItemInfo *info, + GreeterItemState state, + GError **error) +{ + xmlChar *prop; + char *p; + + info->have_state |= (1<<state); + + prop = xmlGetProp (node,(const xmlChar *) "color"); + if (prop) + { + if G_UNLIKELY (!parse_color ((char *) prop, &info->data.rect.colors[state], error)) + return FALSE; + info->data.rect.have_color |= (1<<state); + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "alpha"); + if (prop) + { + double alpha = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad alpha specifier format %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + + if (alpha >= 1.0) + info->data.rect.alphas[state] = 0xff; + else if (alpha < 0) + info->data.rect.alphas[state] = 0; + else + info->data.rect.alphas[state] = floor (alpha * 0xff); + } + + return TRUE; +} + +static gboolean +parse_color_list (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + guint32 color; + + prop = xmlGetProp (node,(const xmlChar *) "iconcolor"); + if (prop) + { + if G_UNLIKELY (!parse_color ((char *) prop, &color, error)) { + info->data.list.icon_color = NULL; + return FALSE; + } else { + info->data.list.icon_color = g_strdup ((char *) prop); + } + + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "labelcolor"); + if (prop) + { + if G_UNLIKELY (!parse_color ((char *) prop, &color, error)) { + info->data.list.label_color = NULL; + return FALSE; + } else { + info->data.list.label_color = g_strdup ((char *) prop); + } + + xmlFree (prop); + } + + return TRUE; +} + +static gboolean +parse_pixmap (xmlNodePtr node, + gboolean svg, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + int i; + + child = node->children; + + while (child) + { + if (strcmp ((char *) child->name, "normal") == 0) + { + if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_NORMAL, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "prelight") == 0) + { + if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_PRELIGHT, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "active") == 0) + { + if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_ACTIVE, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "fixed") == 0) + { + if G_UNLIKELY (!parse_fixed (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "box") == 0) + { + if G_UNLIKELY (!parse_box (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "show") == 0) + { + if G_UNLIKELY (!parse_show (child, info, error)) + return FALSE; + } + + child = child->next; + } + + if G_UNLIKELY (!info->data.pixmap.files[GREETER_ITEM_STATE_NORMAL]) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "No filename specified for normal state"); + return FALSE; + } + + if (!svg) + { + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if (info->data.pixmap.files[i] != NULL) + { + info->data.pixmap.pixbufs[i] = load_pixbuf (info->data.pixmap.files[i], error); + + if G_UNLIKELY (info->data.pixmap.pixbufs[i] == NULL) + return FALSE; + } + else + info->data.pixmap.pixbufs[i] = NULL; + } + } + + return TRUE; +} + +static gboolean +parse_rect (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + int i; + + child = node->children; + + while (child) + { + if (strcmp ((char *) child->name, "normal") == 0) + { + if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_NORMAL, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "prelight") == 0) + { + if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_PRELIGHT, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "active") == 0) + { + if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_ACTIVE, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "fixed") == 0) + { + if G_UNLIKELY (!parse_fixed (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "box") == 0) + { + if G_UNLIKELY (!parse_box (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "show") == 0) + { + if G_UNLIKELY (!parse_show (child, info, error)) + return FALSE; + } + + child = child->next; + } + + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if ( ! (info->data.rect.have_color & (1<<i))) + continue; + + info->data.rect.colors[i] = (info->data.rect.colors[i] << 8) | (guint) info->data.rect.alphas[i]; + } + + return TRUE; +} + + +static gboolean +parse_state_text (xmlNodePtr node, + GreeterItemInfo *info, + GreeterItemState state, + GError **error) +{ + xmlChar *prop; + char *p; + + info->have_state |= (1<<state); + + prop = xmlGetProp (node,(const xmlChar *) "font"); + if (prop) + { + info->data.text.fonts[state] = pango_font_description_from_string ((char *) prop); + if G_UNLIKELY (info->data.text.fonts[state] == NULL) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad font specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "color"); + if (prop) + { + if G_UNLIKELY (!parse_color ((char *) prop, &info->data.text.colors[state], error)) + return FALSE; + info->data.text.have_color |= (1<<state); + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "alpha"); + if (prop) + { + double alpha = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad alpha specifier format %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + + if (alpha >= 1.0) + info->data.rect.alphas[state] = 0xff; + else if (alpha < 0) + info->data.rect.alphas[state] = 0; + else + info->data.rect.alphas[state] = floor (alpha * 0xff); + } + + return TRUE; +} + +static gint +is_current_locale (const char *lang) +{ + const char * const *langs; + int score = 0; + int i; + + langs = g_get_language_names (); + + for (i = 0; langs[i] != NULL; i++) + { + if (strcmp (langs[i], lang) == 0) + return score; + + score++; + } + return 1000; +} + +static gboolean +parse_translated_text (xmlNodePtr node, + char **translated_text, + gint *translation_score, + GError **error) +{ + xmlChar *text; + xmlChar *prop; + gint score; + + prop = xmlNodeGetLang (node); + if (prop) + { + score = is_current_locale ((char *) prop); + xmlFree (prop); + } else + score = 999; + + if (score >= *translation_score) + return TRUE; + + text = xmlNodeGetContent (node); + if (text == NULL) + { + /* This is empty text */ + *translation_score = score; + if (*translated_text) + g_free (*translated_text); + *translated_text = g_strdup (""); + + return TRUE; + } + + *translation_score = score; + if (*translated_text) + g_free (*translated_text); + *translated_text = g_strdup ((char *) text); + + xmlFree (text); + + return TRUE; +} + +static gboolean +parse_label_pos_extras (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlChar *prop; + char *p; + + prop = xmlGetProp (node,(const xmlChar *) "max-width"); + if (prop) + { + info->data.text.max_width = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad max-width specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + prop = xmlGetProp (node,(const xmlChar *) "max-screen-percent-width"); + if (prop) + { + info->data.text.max_screen_percent_width = g_ascii_strtod ((char *) prop, &p); + + if G_UNLIKELY ((char *)prop == p) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad max-screen-percent-width specification %s", prop); + xmlFree (prop); + return FALSE; + } + xmlFree (prop); + } + + return TRUE; +} + + +static gboolean +parse_label (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + int i; + char *translated_text = NULL; + gint translation_score = 1000; + + child = node->children; + while (child) + { + if (strcmp ((char *) child->name, "normal") == 0) + { + if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_NORMAL, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "prelight") == 0) + { + if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_PRELIGHT, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "active") == 0) + { + if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_ACTIVE, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + if G_UNLIKELY (!parse_label_pos_extras (child, info, error)) + return FALSE; + } + else if (child->type == XML_ELEMENT_NODE && + strcmp ((char *) child->name, "text") == 0) + { + if G_UNLIKELY (!parse_translated_text (child, &translated_text, &translation_score, error)) + return FALSE; + } + else if (child->type == XML_ELEMENT_NODE && + strcmp ((char *) child->name, "stock") == 0) + { + if G_UNLIKELY (!parse_stock (child, info, &translated_text, &translation_score, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "show") == 0) + { + if G_UNLIKELY (!parse_show (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "fixed") == 0 || + strcmp ((char *) child->name, "box") == 0) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Label items cannot have children"); + return FALSE; + } + + child = child->next; + } + + if (translated_text == NULL) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "A label must specify the text attribute"); + return FALSE; + } + /* FIXME: evil hack to use internally translated strings */ + if (translation_score == 999 && + ! ve_string_empty (translated_text)) + { + char *foo = g_strdup (_(translated_text)); + g_free (translated_text); + translated_text = foo; + } + + for (i = 0; i < GREETER_ITEM_STATE_MAX; i++) + { + if ( ! (info->data.text.have_color & (1<<i))) + continue; + + info->data.text.colors[i] = (info->data.text.colors[i] << 8) | (guint) info->data.text.alphas[i]; + } + + if (info->data.text.fonts[GREETER_ITEM_STATE_NORMAL] == NULL) + info->data.text.fonts[GREETER_ITEM_STATE_NORMAL] = pango_font_description_from_string ("Sans"); + + do_font_size_reduction (info); + + info->data.text.orig_text = translated_text; + + return TRUE; +} + +static gboolean +parse_listitem (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + xmlChar *prop; + GreeterItemListItem *li; + char *translated_text = NULL; + gint translation_score = 1000; + + prop = xmlGetProp (node,(const xmlChar *) "id"); + + if G_LIKELY (prop) + { + li = g_new0 (GreeterItemListItem, 1); + li->id = g_strdup ((char *) prop); + xmlFree (prop); + } + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Listitem id not specified"); + return FALSE; + } + + child = node->children; + while (child) + { + if (child->type == XML_ELEMENT_NODE && + strcmp ((char *) child->name, "text") == 0) + { + if G_UNLIKELY ( ! parse_translated_text (child, &translated_text, &translation_score, error)) + { + g_free (li->id); + g_free (li); + return FALSE; + } + } + + child = child->next; + } + + if G_UNLIKELY (translated_text == NULL) + { + g_free (li->id); + g_free (li); + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "A list item must specify the text attribute"); + return FALSE; + } + li->text = translated_text; + + info->data.list.items = g_list_append (info->data.list.items, li); + + return TRUE; +} + +static gboolean +parse_list (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + xmlChar *prop; + + info->data.list.combo_type = FALSE; + prop = xmlGetProp (node,(const xmlChar *) "combo"); + if (prop) + { + if (strcmp ((char *) prop, "true") == 0) + { + info->data.list.combo_type = TRUE; + } + else if (strcmp ((char *) prop, "false") == 0) + { + info->data.list.combo_type = FALSE; + } + xmlFree (prop); + } + + child = node->children; + while (child) + { + if (strcmp ((char *) child->name, "color") == 0) + { + if G_UNLIKELY (!parse_color_list (child, info, error)) + return FALSE; + } + if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "show") == 0) + { + if G_UNLIKELY (!parse_show (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "listitem") == 0) + { + if G_UNLIKELY ( ! parse_listitem (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "fixed") == 0 || + strcmp ((char *) child->name, "box") == 0) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "List items cannot have children"); + return FALSE; + } + + child = child->next; + } + + if ((strcmp (info->id, "userlist") == 0) && (info->data.list.combo_type == TRUE)) { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "userlist doest not support combo style"); + return FALSE; + } else if (info->data.list.items != NULL) { + + if G_UNLIKELY (strcmp (info->id, "userlist") == 0 || + strcmp (info->id, "session") == 0 || + strcmp (info->id, "language") == 0) { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "List of id userlist, session, and language cannot have custom list items"); + return FALSE; + } + custom_items = g_list_append (custom_items, info); + + } else if (strcmp (info->id, "session") == 0 || + strcmp (info->id, "language") == 0) { + custom_items = g_list_append (custom_items, info); + } + + return TRUE; +} + +static gboolean +parse_entry (xmlNodePtr node, + GreeterItemInfo *info, + GError **error) +{ + xmlNodePtr child; + + child = node->children; + while (child) + { + if (strcmp ((char *) child->name, "normal") == 0) + { + if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_NORMAL, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "pos") == 0) + { + if G_UNLIKELY (!parse_pos (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "show") == 0) + { + if G_UNLIKELY (!parse_show (child, info, error)) + return FALSE; + } + else if (strcmp ((char *) child->name, "fixed") == 0 || + strcmp ((char *) child->name, "box") == 0) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Entry items cannot have children"); + return FALSE; + } + + child = child->next; + } + + do_font_size_reduction (info); + + return TRUE; +} + +static gboolean +parse_items (xmlNodePtr node, + GList **items_out, + GreeterItemInfo *parent, + GError **error) +{ + xmlNodePtr child; + GList *items; + gboolean res; + xmlChar *type; + xmlChar *background; + GreeterItemInfo *info; + GreeterItemType item_type; + + *items_out = NULL; + + items = NULL; + + child = node->children; + while (child) + { + if (child->type == XML_ELEMENT_NODE) + { + if G_UNLIKELY (strcmp ((char *) child->name, "item") != 0) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Found tag %s when looking for item", child->name); + return FALSE; + } + + type = xmlGetProp (child, (const xmlChar *) "type"); + if G_UNLIKELY (!type) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Items must specify their type"); + return FALSE; + } + + if (strcmp ((char *) type, "svg") == 0) + item_type = GREETER_ITEM_TYPE_SVG; + else if (strcmp ((char *) type, "pixmap") == 0) + item_type = GREETER_ITEM_TYPE_PIXMAP; + else if (strcmp ((char *) type, "rect") == 0) + item_type = GREETER_ITEM_TYPE_RECT; + else if (strcmp ((char *) type, "label") == 0) + item_type = GREETER_ITEM_TYPE_LABEL; + else if (strcmp ((char *) type, "entry") == 0) + item_type = GREETER_ITEM_TYPE_ENTRY; + else if (strcmp ((char *) type, "list") == 0) + item_type = GREETER_ITEM_TYPE_LIST; + else if (strcmp ((char *) type, "button") == 0) + item_type = GREETER_ITEM_TYPE_BUTTON; + else + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Unknown item type %s", type); + xmlFree (type); + return FALSE; + } + + xmlFree (type); + + info = greeter_item_info_new (parent, item_type); + + parse_id (child, info); + if G_UNLIKELY ( ! parse_canvasbutton (child, info, error)) + return FALSE; + + if (button_stack != NULL) + info->my_button = button_stack->data; + if (info->canvasbutton) + button_stack = g_list_prepend (button_stack, info); + + switch (item_type) + { + case GREETER_ITEM_TYPE_SVG: + res = parse_pixmap (child, TRUE, info, error); + break; + case GREETER_ITEM_TYPE_PIXMAP: + res = parse_pixmap (child, FALSE, info, error); + break; + case GREETER_ITEM_TYPE_RECT: + res = parse_rect (child, info, error); + break; + case GREETER_ITEM_TYPE_LABEL: + res = parse_label (child, info, error); + break; + case GREETER_ITEM_TYPE_ENTRY: + res = parse_entry (child, info, error); + break; + case GREETER_ITEM_TYPE_LIST: + res = parse_list (child, info, error); + break; + case GREETER_ITEM_TYPE_BUTTON: + res = parse_gtkbutton (child, info, error); + break; + default: + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_SPEC, + "Bad item type"); + res = FALSE; + } + + if (info->canvasbutton) + button_stack = g_list_remove (button_stack, info); + + background = xmlGetProp (child, (const xmlChar *) "background"); + if G_UNLIKELY (background) + { + if (strcmp ((char *) background, "true") == 0) + { + info->background = TRUE; + } + else if (strcmp ((char *) background, "false") == 0) + { + info->background = FALSE; + } + xmlFree (background); + } + + if G_UNLIKELY (!res) + return FALSE; + + items = g_list_prepend (items, info); + + } + child = child->next; + } + + *items_out = g_list_reverse (items); + return TRUE; +} + +static gboolean +greeter_info_id_equal (GreeterItemInfo *a, + GreeterItemInfo *b) +{ + return g_str_equal (a->id, b->id); +} + +static guint +greeter_info_id_hash (GreeterItemInfo *key) +{ + return g_str_hash (key->id); +} + +GreeterItemInfo * +greeter_parse (const char *file, const char *datadir, + GnomeCanvas *canvas, + int width, int height, GError **error) +{ + GreeterItemInfo *root; + xmlDocPtr doc; + xmlNodePtr node; + xmlChar *prop; + gboolean res; + GList *items; + + /* FIXME: EVIL! GLOBAL! */ + g_free (file_search_path); + file_search_path = g_strdup (datadir); + + if G_UNLIKELY (!g_file_test (file, G_FILE_TEST_EXISTS)) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_NO_FILE, + "Can't open file %s", file); + return NULL; + } + + + doc = xmlParseFile (file); + if G_UNLIKELY (doc == NULL) + { + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_XML, + "XML Parse error reading %s", file); + return NULL; + } + + node = xmlDocGetRootElement (doc); + if G_UNLIKELY (node == NULL) + { + xmlFreeDoc (doc); + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_BAD_XML, + "Can't find the xml root node in file %s", file); + return NULL; + } + + if G_UNLIKELY (strcmp ((char *) node->name, "greeter") != 0) + { + xmlFreeDoc (doc); + g_set_error (error, + GREETER_PARSER_ERROR, + GREETER_PARSER_ERROR_WRONG_TYPE, + "The file %s has the wrong xml type", file); + return NULL; + } + + /* + * The gtk-theme property specifies a theme specific gtk-theme to use + */ + prop = xmlGetProp (node, (const xmlChar *) "gtk-theme"); + if (prop) + { + gchar *theme_dir; + + /* + * It might be nice if we allowed this property to also supply a gtkrc file + * that could be included in the theme. Perhaps we should check first in + * the theme directory for a gtkrc file by the provided name and use that + * if found. + */ + theme_dir = g_strdup_printf ("%s/%s", gtk_rc_get_theme_dir (), (char *) prop); + if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR)) + gdm_set_theme ((char *) prop); + + xmlFree (prop); + } + + item_hash = g_hash_table_new ((GHashFunc)greeter_info_id_hash, + (GEqualFunc)greeter_info_id_equal); + + + root = greeter_item_info_new (NULL, GREETER_ITEM_TYPE_RECT); + res = parse_items (node, &items, root, error); + + /* Now we can whack the hash, we don't want to keep cached + pixbufs around anymore */ + if (pixbuf_hash != NULL) { + g_hash_table_destroy (pixbuf_hash); + pixbuf_hash = NULL; + } + + if G_UNLIKELY (!res) + { + welcome_string_info = NULL; + + g_hash_table_destroy (item_hash); + item_hash = NULL; + g_list_free (custom_items); + custom_items = NULL; + + g_list_free (button_stack); + button_stack = NULL; + + g_list_foreach (items, (GFunc) greeter_item_info_free, NULL); + g_list_free (items); + items = NULL; + + greeter_item_info_free (root); + + xmlFreeDoc (doc); + + return NULL; + } + + xmlFreeDoc (doc); + + root->fixed_children = items; + + root->x = 0; + root->y = 0; + root->x_type = GREETER_ITEM_POS_ABSOLUTE; + root->y_type = GREETER_ITEM_POS_ABSOLUTE; + + root->width = width; + root->height = height; + root->width_type = GREETER_ITEM_SIZE_ABSOLUTE; + root->width_type = GREETER_ITEM_SIZE_ABSOLUTE; + + root->group_item = gnome_canvas_root (canvas); + + return root; +} + +const GList * +greeter_custom_items (void) +{ + return custom_items; +} + +static void +hide_item (GreeterItemInfo *info, gpointer user_data) +{ + GnomeCanvasItem *item; + gboolean *found_background; + + found_background = user_data; + + if (info) + { + if (info->background) + { + *found_background = TRUE; + } + else { + item = info->item; + if (item) { + if (GNOME_IS_CANVAS_WIDGET (item)) { + gtk_widget_hide (GNOME_CANVAS_WIDGET (item)->widget); + } + else + gnome_canvas_item_hide (item); + } + if ((info->item_type == GREETER_ITEM_TYPE_ENTRY) && + (info->data.text.menubar != NULL)) { + gtk_widget_hide (info->data.text.menubar); + } + } + + g_list_foreach (info->fixed_children, (GFunc) hide_item, user_data); + g_list_foreach (info->box_children, (GFunc) hide_item, user_data); + } +} + +gboolean +greeter_show_only_background (GreeterItemInfo *root_item) +{ + gboolean found_background = FALSE; + + hide_item (root_item, &found_background); + + /* ensure root canvas is updated */ + while (gtk_events_pending ()) + gtk_main_iteration (); + + return found_background; +} diff --git a/trunk/gui/greeter/greeter_parser.h b/trunk/gui/greeter/greeter_parser.h new file mode 100644 index 00000000..b5021124 --- /dev/null +++ b/trunk/gui/greeter/greeter_parser.h @@ -0,0 +1,48 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_PARSER_H__ +#define __GREETER_PARSER_H__ + +#include <libgnomecanvas/libgnomecanvas.h> +#include "greeter_item.h" + + +typedef enum +{ + GREETER_PARSER_ERROR_NO_FILE, + GREETER_PARSER_ERROR_BAD_XML, + GREETER_PARSER_ERROR_WRONG_TYPE, + GREETER_PARSER_ERROR_BAD_SPEC +} GreeterParseError; + +#define GREETER_PARSER_ERROR greeter_parser_error_quark() +GQuark greeter_parser_error_quark (void); + +GreeterItemInfo *greeter_parse (const char *file, + const char *data_dir, + GnomeCanvas *canvas, + int width, + int height, + GError **error); + +GreeterItemInfo *greeter_lookup_id (const char *id); +const GList *greeter_custom_items (void); +gboolean greeter_show_only_background (GreeterItemInfo *root_item); + +#endif /* __GREETER_PARSER_H__ */ diff --git a/trunk/gui/greeter/greeter_session.c b/trunk/gui/greeter/greeter_session.c new file mode 100644 index 00000000..9820a119 --- /dev/null +++ b/trunk/gui/greeter/greeter_session.c @@ -0,0 +1,271 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <string.h> + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "gdm.h" +#include "gdmwm.h" +#include "gdmcommon.h" +#include "gdmconfig.h" +#include "gdmsession.h" + +#include "gdm-common.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter.h" +#include "greeter_session.h" +#include "greeter_item_pam.h" +#include "greeter_item_customlist.h" +#include "greeter_configuration.h" +#include "greeter_events.h" +#include "greeter_parser.h" + +static GtkWidget *session_dialog; +static GSList *session_group = NULL; +extern GList *sessions; +extern GHashTable *sessnames; +extern gchar *default_session; +extern char *current_session; +extern gboolean session_dir_whacked_out; + +void +greeter_set_session (char *session) +{ + g_free (current_session); + current_session = g_strdup (session); + greeter_custom_set_session (session); +} + +void +greeter_session_init (void) +{ + GtkWidget *w = NULL; + GtkWidget *hbox = NULL; + GtkWidget *main_vbox = NULL; + GtkWidget *vbox = NULL; + GtkWidget *cat_vbox = NULL; + GtkWidget *radio; + GtkWidget *dialog; + GtkWidget *button; + GList *tmp; + static GtkTooltips *tooltips = NULL; + GtkRequisition req; + char *s; + int num = 1; + char *label; + + greeter_set_session (NULL); + + session_dialog = dialog = gtk_dialog_new (); + if (tooltips == NULL) + tooltips = gtk_tooltips_new (); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + + button = gtk_button_new_with_mnemonic (_("Change _Session")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_show (button); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, + GTK_RESPONSE_OK); + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + + main_vbox = gtk_vbox_new (FALSE, 18); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + main_vbox, + FALSE, FALSE, 0); + + cat_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (main_vbox), + cat_vbox, + FALSE, FALSE, 0); + + s = g_strdup_printf ("<b>%s</b>", _("Sessions")); + w = gtk_label_new (s); + gtk_label_set_use_markup (GTK_LABEL (w), TRUE); + g_free (s); + gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (cat_vbox), w, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (cat_vbox), + hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), + gtk_label_new (" "), + FALSE, FALSE, 0); + vbox = gtk_vbox_new (FALSE, 6); + /* we will pack this later depending on size */ + + if (gdm_config_get_bool (GDM_KEY_SHOW_LAST_SESSION)) + { + greeter_set_session (LAST_SESSION); + + radio = gtk_radio_button_new_with_mnemonic (session_group, _("_Last session")); + g_object_set_data (G_OBJECT (radio), + SESSION_NAME, + LAST_SESSION); + session_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); + gtk_tooltips_set_tip (tooltips, radio, + _("Log in using the session that you have used " + "last time you logged in"), + NULL); + gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); + gtk_widget_show (radio); + } + + gdm_session_list_init (); + + for (tmp = sessions; tmp != NULL; tmp = tmp->next) + { + GdmSession *session; + char *file; + + file = (char *) tmp->data; + session = g_hash_table_lookup (sessnames, file); + + if (num < 10 && + (strcmp (file, GDM_SESSION_FAILSAFE_GNOME) != 0) && + (strcmp (file, GDM_SESSION_FAILSAFE_XTERM) != 0)) + label = g_strdup_printf ("_%d. %s", num, session->name); + else + label = g_strdup (session->name); + num++; + + radio = gtk_radio_button_new_with_mnemonic (session_group, label); + g_free (label); + g_object_set_data_full (G_OBJECT (radio), SESSION_NAME, + file, (GDestroyNotify) g_free); + session_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); + gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); + gtk_widget_show (radio); + + if (! ve_string_empty (session->comment)) + gtk_tooltips_set_tip + (tooltips, GTK_WIDGET (radio), session->comment, NULL); + } + + gtk_widget_show_all (vbox); + gtk_widget_size_request (vbox, &req); + + /* if too large */ + if (req.height > 0.7 * gdm_wm_screen.height) { + GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_size_request (sw, + req.width, + 0.7 * gdm_wm_screen.height); + gtk_scrolled_window_set_shadow_type + (GTK_SCROLLED_WINDOW (sw), + GTK_SHADOW_NONE); + gtk_scrolled_window_set_policy + (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport + (GTK_SCROLLED_WINDOW (sw), vbox); + gtk_widget_show (sw); + gtk_box_pack_start (GTK_BOX (hbox), + sw, + TRUE, TRUE, 0); + } else { + gtk_box_pack_start (GTK_BOX (hbox), + vbox, + TRUE, TRUE, 0); + } +} + +/* + * The button with this handler appears in the F10 menu, so it + * cannot depend on callback data being passed in. + */ +static void +greeter_session_handler (GreeterItemInfo *info, + gpointer user_data) +{ + GSList *tmp; + int ret; + + /* Select the proper session */ + tmp = session_group; + while (tmp != NULL) + { + GtkWidget *w = tmp->data; + const char *n; + + n = g_object_get_data (G_OBJECT (w), SESSION_NAME); + + if (n && strcmp (n, current_session) == 0) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), + TRUE); + break; + } + + tmp = tmp->next; + } + + gtk_widget_show_all (session_dialog); + + gdm_wm_center_window (GTK_WINDOW (session_dialog)); + + gdm_wm_no_login_focus_push (); + ret = gtk_dialog_run (GTK_DIALOG (session_dialog)); + gdm_wm_no_login_focus_pop (); + gtk_widget_hide (session_dialog); + + if (ret == GTK_RESPONSE_OK) + { + tmp = session_group; + while (tmp != NULL) + { + GtkWidget *w = tmp->data; + const char *n; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) + { + n = g_object_get_data (G_OBJECT (w), SESSION_NAME); + greeter_set_session ((char *)n); + break; + } + + tmp = tmp->next; + } + } +} + +void +greeter_item_session_setup () +{ + greeter_item_register_action_callback ("session_button", + (ActionFunc)greeter_session_handler, + NULL); +} diff --git a/trunk/gui/greeter/greeter_session.h b/trunk/gui/greeter/greeter_session.h new file mode 100644 index 00000000..43cf8f72 --- /dev/null +++ b/trunk/gui/greeter/greeter_session.h @@ -0,0 +1,26 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_SESSION_H__ +#define __GREETER_SESSION_H__ + +void greeter_session_init (void); +void greeter_item_session_setup (void); +void greeter_set_session (char *session); + +#endif /* __GREETER_SESSION_H__ */ diff --git a/trunk/gui/greeter/greeter_system.c b/trunk/gui/greeter/greeter_system.c new file mode 100644 index 00000000..65729c83 --- /dev/null +++ b/trunk/gui/greeter/greeter_system.c @@ -0,0 +1,594 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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" + +#include <unistd.h> +#include <string.h> + +#ifdef HAVE_CHKAUTHATTR +#include <auth_attr.h> +#include <secdb.h> +#endif + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "gdm.h" +#include "gdmcommon.h" +#include "gdmconfig.h" +#include "gdmwm.h" +#include "misc.h" + +#include "gdm-common.h" +#include "gdm-socket-protocol.h" +#include "gdm-daemon-config-keys.h" + +#include "greeter.h" +#include "greeter_configuration.h" +#include "greeter_system.h" +#include "greeter_item.h" +#include "greeter_item_ulist.h" +#include "greeter_parser.h" + +GtkWidget *dialog; +extern gboolean GdmHaltFound; +extern gboolean GdmRebootFound; +extern gboolean *GdmCustomCmdsFound; +extern gboolean GdmAnyCustomCmdsFound; +extern gboolean GdmSuspendFound; +extern gboolean GdmConfiguratorFound; + +/* doesn't check for executability, just for existance */ +static gboolean +bin_exists (const char *command) +{ + char *bin; + + if (ve_string_empty (command)) + return FALSE; + + /* Note, check only for existance, not for executability */ + bin = ve_first_word (command); + if (bin != NULL && + g_access (bin, F_OK) == 0) { + g_free (bin); + return TRUE; + } else { + g_free (bin); + return FALSE; + } +} + +/* + * The buttons with these handlers appear in the F10 menu, so they + * cannot depend on callback data being passed in. + */ +static void +query_greeter_restart_handler (void) +{ + if (gdm_wm_warn_dialog (_("Are you sure you want to restart the computer?"), "", + _("_Restart"), NULL, TRUE) == GTK_RESPONSE_YES) { + _exit (DISPLAY_REBOOT); + } +} + +static void +query_greeter_custom_cmd_handler (GtkWidget *widget, gpointer data) +{ + if (data) { + gint *cmd_id = (gint*)data; + gchar * key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, *cmd_id); + if (gdm_wm_warn_dialog (gdm_config_get_string (key_string) , "", + GTK_STOCK_OK, NULL, TRUE) == GTK_RESPONSE_YES) { + printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, *cmd_id); + fflush (stdout); + } + g_free (key_string); + } +} + +static void +query_greeter_halt_handler (void) +{ + if (gdm_wm_warn_dialog (_("Are you sure you want to Shut Down the computer?"), "", + _("Shut _Down"), NULL, TRUE) == GTK_RESPONSE_YES) { + _exit (DISPLAY_HALT); + } +} + +static void +query_greeter_suspend_handler (void) +{ + if (gdm_wm_warn_dialog (_("Are you sure you want to suspend the computer?"), "", + _("_Suspend"), NULL, TRUE) == GTK_RESPONSE_YES) { + /* suspend interruption */ + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_SUSPEND); + fflush (stdout); + } +} + +static void +greeter_restart_handler (void) +{ + _exit (DISPLAY_REBOOT); +} + +static void +greeter_custom_cmd_handler (gint cmd_id) +{ + printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, cmd_id); + fflush (stdout); +} + +static void +greeter_halt_handler (void) +{ + _exit (DISPLAY_HALT); +} + +static void +greeter_suspend_handler (void) +{ + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_SUSPEND); + fflush (stdout); +} + +static void +greeter_config_handler (void) +{ + greeter_item_ulist_disable (); + + /* Make sure to unselect the user */ + greeter_item_ulist_unset_selected_user (); + + /* we should be now fine for focusing new windows */ + gdm_wm_focus_new_windows (TRUE); + + /* configure interruption */ + printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_CONFIGURE); + fflush (stdout); +} + +static void +greeter_chooser_handler (void) +{ + _exit (DISPLAY_RUN_CHOOSER); +} + +static gboolean +is_action_available (gchar *action) +{ + gchar **allowsyscmd = NULL; + const gchar *allowsyscmdval; + gboolean ret = FALSE; + int i; + + allowsyscmdval = gdm_config_get_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU); + if (allowsyscmdval) + allowsyscmd = g_strsplit (allowsyscmdval, ";", 0); + + if (allowsyscmd) { + for (i = 0; allowsyscmd[i] != NULL; i++) { + if (strcmp (allowsyscmd[i], action) == 0) { + ret = TRUE; + break; + } + } + } + +#ifdef HAVE_CHKAUTHATTR + if (ret == TRUE) { + gchar **rbackeys = NULL; + const gchar *rbackeysval; + const char *gdmuser; + + gdmuser = gdm_config_get_string (GDM_KEY_USER); + rbackeysval = gdm_config_get_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS); + if (rbackeysval) + rbackeys = g_strsplit (rbackeysval, ";", 0); + + if (rbackeys) { + for (i = 0; rbackeys[i] != NULL; i++) { + gchar **rbackey = g_strsplit (rbackeys[i], ":", 2); + + if (! ve_string_empty (rbackey[0]) && + ! ve_string_empty (rbackey[1]) && + strcmp (rbackey[0], action) == 0) { + + if (!chkauthattr (rbackey[1], gdmuser)) { + g_strfreev (rbackey); + ret = FALSE; + break; + } + } + g_strfreev (rbackey); + } + } + g_strfreev (rbackeys); + } +#endif + g_strfreev (allowsyscmd); + + return ret; +} + +void +greeter_system_append_system_menu (GtkWidget *menu) +{ + GtkWidget *w, *sep; + gint i = 0; + + /* should never be allowed by the UI */ + if ( ! gdm_config_get_bool (GDM_KEY_SYSTEM_MENU) || + ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) + return; + + if (gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON)) { + w = gtk_menu_item_new_with_mnemonic (_("Remote Login via _XDMCP...")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (greeter_chooser_handler), + NULL); + } + + /* + * Disable Configuration if using accessibility (AddGtkModules) since + * using it with accessibility causes a hang. + */ + if (gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) && + !gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) && + bin_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR))) { + w = gtk_menu_item_new_with_mnemonic (_("Confi_gure Login Manager...")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (greeter_config_handler), + NULL); + } + + if (GdmRebootFound || GdmHaltFound || GdmSuspendFound || GdmAnyCustomCmdsFound) { + sep = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep); + gtk_widget_show (sep); + } + + if (GdmRebootFound && is_action_available ("REBOOT")) { + w = gtk_menu_item_new_with_mnemonic (_("_Restart")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (query_greeter_restart_handler), + NULL); + } + + if (GdmHaltFound && is_action_available ("HALT")) { + w = gtk_menu_item_new_with_mnemonic (_("Shut _Down")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (query_greeter_halt_handler), + NULL); + } + + if (GdmSuspendFound && is_action_available ("SUSPEND")) { + w = gtk_menu_item_new_with_mnemonic (_("Sus_pend")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (query_greeter_suspend_handler), + NULL); + } + + if (GdmAnyCustomCmdsFound && is_action_available ("CUSTOM_CMD")) { + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + if (GdmCustomCmdsFound[i]){ + gint * cmd_index = g_new0(gint, 1); + gchar * key_string = NULL; + *cmd_index = i; + key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i); + w = gtk_menu_item_new_with_mnemonic (gdm_config_get_string(key_string)); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + gtk_widget_show (GTK_WIDGET (w)); + g_signal_connect (G_OBJECT (w), "activate", + G_CALLBACK (query_greeter_custom_cmd_handler), + cmd_index); + g_free (key_string); + } + } + } + +} + +static gboolean +radio_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + if (event->type == GDK_2BUTTON_PRESS) { + gtk_dialog_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK); + } + return FALSE; +} + +static void +greeter_system_handler (GreeterItemInfo *info, + gpointer user_data) +{ + GtkWidget *w = NULL; + GtkWidget *hbox = NULL; + GtkWidget *main_vbox = NULL; + GtkWidget *vbox = NULL; + GtkWidget *cat_vbox = NULL; + GtkWidget *group_radio = NULL; + GtkWidget *halt_radio = NULL; + GtkWidget *suspend_radio = NULL; + GtkWidget *restart_radio = NULL; + GtkWidget **custom_cmds_radio = NULL; + GtkWidget *config_radio = NULL; + GtkWidget *chooser_radio = NULL; + gchar *s; + int ret; + gint i; + GSList *radio_group = NULL; + static GtkTooltips *tooltips = NULL; + + /* should never be allowed by the UI */ + if ( ! gdm_config_get_bool (GDM_KEY_SYSTEM_MENU) || + ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) + return; + + dialog = gtk_dialog_new (); + if (tooltips == NULL) + tooltips = gtk_tooltips_new (); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + + main_vbox = gtk_vbox_new (FALSE, 18); + gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + main_vbox, + FALSE, FALSE, 0); + + cat_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (main_vbox), + cat_vbox, + FALSE, FALSE, 0); + + s = g_strdup_printf ("<b>%s</b>", + _("Choose an Action")); + w = gtk_label_new (s); + gtk_label_set_use_markup (GTK_LABEL (w), TRUE); + g_free (s); + gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (cat_vbox), w, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (cat_vbox), + hbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), + gtk_label_new (" "), + FALSE, FALSE, 0); + vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), + vbox, + TRUE, TRUE, 0); + + if (GdmHaltFound) { + if (group_radio != NULL) + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + halt_radio = gtk_radio_button_new_with_mnemonic (radio_group, + _("Shut _down the computer")); + group_radio = halt_radio; + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (halt_radio), + _("Shut Down your computer so that " + "you may turn it off."), + NULL); + g_signal_connect (G_OBJECT(halt_radio), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + halt_radio, + FALSE, FALSE, 4); + gtk_widget_show (halt_radio); + } + + if (GdmRebootFound) { + if (group_radio != NULL) + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + restart_radio = gtk_radio_button_new_with_mnemonic (radio_group, + _("_Restart the computer")); + group_radio = restart_radio; + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (restart_radio), + _("Restart your computer"), + NULL); + g_signal_connect (G_OBJECT(restart_radio), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + restart_radio, + FALSE, FALSE, 4); + gtk_widget_show (restart_radio); + } + + if (GdmAnyCustomCmdsFound) { + custom_cmds_radio = g_new0 (GtkWidget*, GDM_CUSTOM_COMMAND_MAX); + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + custom_cmds_radio[i] = NULL; + if (GdmCustomCmdsFound[i]){ + gchar * key_string = NULL; + key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i); + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + custom_cmds_radio[i] = gtk_radio_button_new_with_mnemonic (radio_group, + gdm_config_get_string(key_string)); + group_radio = custom_cmds_radio[i]; + g_free (key_string); + key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i); + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (custom_cmds_radio[i]), + gdm_config_get_string(key_string), + NULL); + g_signal_connect (G_OBJECT(custom_cmds_radio[i]), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + custom_cmds_radio[i], + FALSE, FALSE, 4); + gtk_widget_show (custom_cmds_radio[i]); + g_free (key_string); + } + } + } + + if (GdmSuspendFound) { + if (group_radio != NULL) + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + suspend_radio = gtk_radio_button_new_with_mnemonic (radio_group, + _("Sus_pend the computer")); + group_radio = suspend_radio; + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (suspend_radio), + _("Suspend your computer"), + NULL); + g_signal_connect (G_OBJECT(suspend_radio), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + suspend_radio, + FALSE, FALSE, 4); + gtk_widget_show (suspend_radio); + } + + if (gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON)) { + if (group_radio != NULL) + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + chooser_radio = gtk_radio_button_new_with_mnemonic (radio_group, + _("Run _XDMCP chooser")); + group_radio = chooser_radio; + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (chooser_radio), + _("Run an XDMCP chooser which will allow " + "you to log into available remote " + "computers, if there are any."), + NULL); + g_signal_connect (G_OBJECT(chooser_radio), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + chooser_radio, + FALSE, FALSE, 4); + gtk_widget_show (chooser_radio); + } + + /* + * Disable Configuration if using accessibility (AddGtkModules) since + * using it with accessibility causes a hang. + */ + if (gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) && + !gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) && + bin_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR))) { + if (group_radio != NULL) + radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio)); + config_radio = gtk_radio_button_new_with_mnemonic (radio_group, + _("Confi_gure the login manager")); + group_radio = config_radio; + gtk_tooltips_set_tip (tooltips, GTK_WIDGET (config_radio), + _("Configure GDM (this login manager). " + "This will require the root password."), + NULL); + g_signal_connect (G_OBJECT(config_radio), "button_press_event", + G_CALLBACK(radio_button_press_event), NULL); + gtk_box_pack_start (GTK_BOX (vbox), + config_radio, + FALSE, FALSE, 4); + gtk_widget_show (config_radio); + } + + gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_OK); + + gtk_widget_show_all (dialog); + gdm_wm_center_window (GTK_WINDOW (dialog)); + + gdm_wm_no_login_focus_push (); + ret = gtk_dialog_run (GTK_DIALOG (dialog)); + gdm_wm_no_login_focus_pop (); + + if (ret != GTK_RESPONSE_OK) + { + gtk_widget_destroy (dialog); + return; + } + + if (halt_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (halt_radio))) + greeter_halt_handler (); + else if (restart_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (restart_radio))) + greeter_restart_handler (); + else if (suspend_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (suspend_radio))) + greeter_suspend_handler (); + else if (config_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (config_radio))) + greeter_config_handler (); + else if (chooser_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser_radio))) + greeter_chooser_handler (); + else + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + if (custom_cmds_radio[i] != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (custom_cmds_radio[i]))) + greeter_custom_cmd_handler (i); + } + + gtk_widget_destroy (dialog); +} + + +void +greeter_item_system_setup (void) +{ + gint i; + + greeter_item_register_action_callback ("reboot_button", + (ActionFunc)query_greeter_restart_handler, + NULL); + greeter_item_register_action_callback ("halt_button", + (ActionFunc)query_greeter_halt_handler, + NULL); + greeter_item_register_action_callback ("suspend_button", + (ActionFunc)query_greeter_suspend_handler, + NULL); + greeter_item_register_action_callback ("system_button", + (ActionFunc)greeter_system_handler, + NULL); + greeter_item_register_action_callback ("config_button", + (ActionFunc)greeter_config_handler, + NULL); + greeter_item_register_action_callback ("chooser_button", + (ActionFunc)greeter_chooser_handler, + NULL); + + for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) { + gint * cmd_index = g_new0(gint, 1); + gchar * key_string; + *cmd_index = i; + key_string = g_strdup_printf ("custom_cmd_button%d", i); + greeter_item_register_action_callback (key_string, + (ActionFunc)query_greeter_custom_cmd_handler, + cmd_index); + g_free (key_string); + } +} diff --git a/trunk/gui/greeter/greeter_system.h b/trunk/gui/greeter/greeter_system.h new file mode 100644 index 00000000..2349345c --- /dev/null +++ b/trunk/gui/greeter/greeter_system.h @@ -0,0 +1,29 @@ +/* GDM - The GNOME Display Manager + * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> + * + * 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 + */ + +#ifndef __GREETER_SYSTEM_H__ +#define __GREETER_SYSTEM_H__ + +#include "greeter_item.h" +#include "greeter_events.h" + +void greeter_item_system_setup (void); +void greeter_system_append_system_menu (GtkWidget *menu); + +#endif + diff --git a/trunk/gui/greeter/themes/.cvsignore b/trunk/gui/greeter/themes/.cvsignore new file mode 100644 index 00000000..22a4e729 --- /dev/null +++ b/trunk/gui/greeter/themes/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in + diff --git a/trunk/gui/greeter/themes/Makefile.am b/trunk/gui/greeter/themes/Makefile.am new file mode 100644 index 00000000..85df4a1b --- /dev/null +++ b/trunk/gui/greeter/themes/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = circles happygnome happygnome-list diff --git a/trunk/gui/greeter/themes/circles/.cvsignore b/trunk/gui/greeter/themes/circles/.cvsignore new file mode 100644 index 00000000..d09a03b4 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in new file mode 100644 index 00000000..b5699ab1 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in @@ -0,0 +1,11 @@ +# This is not really a .desktop file like the rest, but it's useful to treat +# it as such + +[GdmGreeterTheme] +Encoding=UTF-8 +Greeter=circles.xml +_Name=Circles +_Description=Theme with blue circles +_Author=Bond, James Bond +_Copyright=(c) 2002 Bond, James Bond +Screenshot=screenshot.png diff --git a/trunk/gui/greeter/themes/circles/Makefile.am b/trunk/gui/greeter/themes/circles/Makefile.am new file mode 100644 index 00000000..0e8fa065 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/Makefile.am @@ -0,0 +1,19 @@ +circlesdir = $(datadir)/gdm/themes/circles +circles_DATA = \ + GdmGreeterTheme.desktop \ + circles.xml \ + background.svg \ + flower.png \ + help.png \ + options.png \ + screenshot.png + +circles_in_files = \ + GdmGreeterTheme.desktop.in + +@INTLTOOL_DESKTOP_RULE@ + +EXTRA_DIST = $(circles_DATA) $(circles_in_files) + +clean-local: + /bin/rm -f GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/circles/background.svg b/trunk/gui/greeter/themes/circles/background.svg new file mode 100644 index 00000000..11abc4f4 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/background.svg @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/circles/circles.xml b/trunk/gui/greeter/themes/circles/circles.xml new file mode 100644 index 00000000..a39b6639 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/circles.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE greeter SYSTEM "greeter.dtd"> +<greeter> + <item type="svg" background="true"> + <normal file="background.svg"/> + <pos x="0" y="0" width="100%" height="-75"/> + </item> + <item type="rect" background="true"> + <normal color="#000000"/> + <pos x="0" y="-75" width="100%" height="75"/> + <fixed> + <item type="rect" background="true"> + <normal color="#ffffff"/> + <pos x="0" y="4" width="100%" height="100%"/> + <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10"> + <item type="button" id="options_button" button="true"> + <pos y="5" width="80" height="50"/> + <stock type="options"/> + </item> + <item type="list" id="language" combo="true"> + <pos x="25" y="10" height="40" width="300"/> + </item> + <item type="list" id="session" combo="true"> + <pos x="50" y="10" height="40" width="300"/> + </item> + </box> + </item> + </fixed> + </item> + <item type="rect" id="userlist-rect"> + <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/> + <pos anchor="nw" x="0" y="0" width="box" height="box"/> + <box orientation="vertical" min-width="440" max-width="440" min-height="100" + xpadding="4" ypadding="4" spacing="0"> + <item type="list" id="userlist"> + <pos anchor="nw" x="0" y="0" height="550" width="440"/> + <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/> + </item> + </box> + </item> + + <item type="pixmap" background="true"> + <normal file="flower.png"/> + <pos x="100%" y="100%" anchor="se"/> + </item> + <item type="label" id="clock"> + <normal color="#000000" font="Sans 12"/> + <pos x="-20" y="-37" anchor="e"/> + <text>%c</text> + </item> + + <item type="rect"> + <show type="timed"/> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="50%" y="25%" width="box" height="box"/> + <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0"> + <item type="label" id="timed-label"> + <normal color="#000000" font="Sans 12"/> + <pos x="50%" anchor="n"/> + <!-- Stock label for: User %s will login in %d seconds --> + <stock type="timed-label"/> + </item> + </box> + </item> + + <item type="rect"> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="50%" y="50%" width="box" height="box"/> + <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10"> + <item type="label"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 14"/> + <!-- Stock label for: Welcome to %h --> + <stock type="welcome-label"/> + </item> + <item type="label" id="pam-prompt"> + <pos anchor="nw" x="10%"/> + <normal color="#000000" font="Sans 12"/> + <!-- Stock label for: Username: --> + <stock type="username-label"/> + </item> + <item type="rect"> + <normal color="#000000"/> + <pos anchor="n" x="50%" height="24" width="80%"/> + <fixed> + <item type="entry" id="user-pw-entry"> + <normal color="#000000" font="Sans 12"/> + <pos anchor="nw" x="1" y="1" height="-2" width="-2"/> + </item> + </fixed> + </item> + <item type="button" id="ok_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="ok"/> + </item> + <item type="button" id="cancel_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="startagain"/> + </item> + <item type="label" id="pam-message"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </box> + <fixed> + <item type="label" id="pam-error"> + <pos anchor="n" x="50%" y="110%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </fixed> + </item> +</greeter> + + diff --git a/trunk/gui/greeter/themes/circles/flower.png b/trunk/gui/greeter/themes/circles/flower.png Binary files differnew file mode 100644 index 00000000..92d25f32 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/flower.png diff --git a/trunk/gui/greeter/themes/circles/help.png b/trunk/gui/greeter/themes/circles/help.png Binary files differnew file mode 100644 index 00000000..b38b48a6 --- /dev/null +++ b/trunk/gui/greeter/themes/circles/help.png diff --git a/trunk/gui/greeter/themes/circles/options.png b/trunk/gui/greeter/themes/circles/options.png Binary files differnew file mode 100644 index 00000000..3c08e02d --- /dev/null +++ b/trunk/gui/greeter/themes/circles/options.png diff --git a/trunk/gui/greeter/themes/circles/screenshot.png b/trunk/gui/greeter/themes/circles/screenshot.png Binary files differnew file mode 100644 index 00000000..7120b03d --- /dev/null +++ b/trunk/gui/greeter/themes/circles/screenshot.png diff --git a/trunk/gui/greeter/themes/happygnome-list/.cvsignore b/trunk/gui/greeter/themes/happygnome-list/.cvsignore new file mode 100644 index 00000000..d09a03b4 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in new file mode 100644 index 00000000..908c6c7e --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in @@ -0,0 +1,11 @@ +# This is not really a .desktop file like the rest, but it's useful to treat +# it as such + +[GdmGreeterTheme] +Encoding=UTF-8 +Greeter=happygnome.xml +_Name=Happy GNOME with Browser +_Description=GNOME Art variation of Circles with a Face Browser +_Author=GNOME Artists +_Copyright=(c) 2002 GNOME +Screenshot=screenshot.png diff --git a/trunk/gui/greeter/themes/happygnome-list/Makefile.am b/trunk/gui/greeter/themes/happygnome-list/Makefile.am new file mode 100644 index 00000000..42ba140f --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/Makefile.am @@ -0,0 +1,18 @@ +happygnomedir = $(datadir)/gdm/themes/happygnome-list +happygnome_DATA = \ + GdmGreeterTheme.desktop \ + happygnome.xml \ + background.svg \ + gnome-logo.svg \ + options.png \ + screenshot.png + +happygnome_in_files = \ + GdmGreeterTheme.desktop.in + +@INTLTOOL_DESKTOP_RULE@ + +EXTRA_DIST = $(happygnome_DATA) $(happygnome_in_files) + +clean-local: + /bin/rm -f GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/happygnome-list/background.svg b/trunk/gui/greeter/themes/happygnome-list/background.svg new file mode 100644 index 00000000..11abc4f4 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/background.svg @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg b/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg new file mode 100644 index 00000000..bdde1d1e --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="us-ascii" ?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st1 "stroke:none;">
+]>
+<svg width="95.991pt" height="150.915pt" viewBox="0 0 95.991 150.915" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st0;">
+ <g style="&st1;">
+ <g>
+ <g>
+ <path d="M86.068,0C61.466,0,56.851,35.041,70.691,35.041C84.529,35.041,110.671,0,86.068,0z"/>
+ <path d="M45.217,30.699c7.369,0.45,15.454-28.122,1.604-26.325c-13.845,1.797-8.976,25.875-1.604,26.325z"/>
+ <path d="M11.445,48.453c5.241-2.307,0.675-24.872-8.237-18.718c-8.908,6.155,2.996,21.024,8.237,18.718z"/>
+ <path d="M26.212,36.642c6.239-1.272,6.581-26.864-4.545-22.273c-11.128,4.592-1.689,23.547,4.545,22.273z"/>
+ <path id="newshape" d="M58.791,93.913c1.107,8.454-6.202,12.629-13.36,7.179C22.644,83.743,83.16,75.088,79.171,51.386c-3.311-19.674-63.676-13.617-70.55,17.167C3.968,89.374,27.774,118.26,52.614,118.26c12.22,0,26.315-11.034,28.952-25.012
+ c2.014-10.659-23.699-6.388-22.775,0.665z"/>
+ </g>
+ </g>
+ <g>
+ <path d="M17.718,132.165l-1.49,2.857c-0.418-0.374-1.064-0.746-1.937-1.115c-0.873-0.369-1.623-0.555-2.25-0.555c-1.964,0-3.514,0.668-4.65,2.004c-1.137,1.337-1.705,3.127-1.705,5.37c0,2.135,0.557,3.841,1.671,5.117c1.114,1.276,2.63,1.915,4.549,1.915
+ c1.264,0,2.305-0.346,3.124-1.037v-3.932h-2.781v-3.031h6.344v8.958c-0.847,0.692-1.938,1.231-3.271,1.618s-2.661,0.58-3.981,0.58c-2.868,0-5.142-0.941-6.822-2.824s-2.52-4.369-2.52-7.459c0-3.092,0.914-5.604,2.743-7.536c1.828-1.933,4.289-2.899,7.382-2.899
+ c2.192,0,4.057,0.656,5.594,1.969z"/>
+ <path d="M34.892,150.853l-9.719-12.688v12.406h-3.406V130.54h1.719l9.438,12.094V130.54h3.406v20.313h-1.438z"/>
+ <path d="M39.487,140.392c0-2.852,0.781-5.264,2.345-7.236c1.563-1.973,3.652-2.959,6.268-2.959c2.881,0,5.082,0.893,6.604,2.679c1.522,1.786,2.283,4.292,2.283,7.517c0,3.227-0.795,5.786-2.385,7.682c-1.592,1.895-3.85,2.842-6.775,2.842
+ c-2.688,0-4.75-0.938-6.186-2.814s-2.153-4.447-2.153-7.709z M43.175,140.392c0,2.342,0.396,4.155,1.19,5.439c0.793,1.285,1.947,1.928,3.461,1.928c1.779,0,3.136-0.629,4.07-1.887c0.936-1.257,1.402-3.084,1.402-5.48c0-4.692-1.732-7.039-5.199-7.039
+ c-1.587,0-2.805,0.636-3.653,1.906c-0.849,1.271-1.272,2.982-1.272,5.133z"/>
+ <path d="M78.831,150.571h-3.438l-2.094-10.781l-4.031,11.063h-1.281L63.94,139.79l-2.141,10.781h-3.438l4.031-20.031h1.875l4.359,13.5l4.234-13.5h1.875l4.094,20.031z"/>
+ <path d="M84.569,133.696v4.688h6.438v3.031h-6.438v6h9.063v3.156H81.006V130.54h12.625v3.156h-9.063z"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome-list/happygnome.xml b/trunk/gui/greeter/themes/happygnome-list/happygnome.xml new file mode 100644 index 00000000..ba92210c --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/happygnome.xml @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE greeter SYSTEM "greeter.dtd"> +<greeter> + <item type="svg" background="true"> + <normal file="background.svg"/> + <pos x="0" y="0" width="100%" height="-75"/> + </item> + <item type="rect" background="true"> + <normal color="#000000"/> + <pos x="0" y="-75" width="100%" height="75"/> + <fixed> + <item type="rect" background="true"> + <normal color="#ffffff"/> + <pos x="0" y="4" width="100%" height="100%"/> + <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10"> + <item type="button" id="options_button"> + <pos width="100" height="50" /> + <stock type="options"/> + </item> + <item type="list" id="language" combo="true"> + <pos x="25" y="5" height="40" width="300"/> + </item> + <item type="list" id="session" combo="true"> + <pos x="50" y="5" height="40" width="300"/> + </item> + </box> + </item> + </fixed> + </item> + <item type="svg" background="true"> + <normal file="gnome-logo.svg"/> + <pos x="-12" y="-12" width="30" height="47" anchor="se" /> + </item> + <item type="label" id="clock"> + <normal color="#000000" font="Sans 12"/> + <pos x="-80" y="-37" anchor="e"/> + <text>%c</text> + </item> + + <item type="rect" id="caps-lock-warning"> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="75%" y="75%" width="box" height="box"/> + <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0"> + <item type="label"> + <normal color="#000000" font="Sans 12"/> + <pos x="50%" anchor="n"/> + <!-- Stock label for: You've got capslock on! --> + <stock type="caps-lock-warning"/> + </item> + </box> + </item> + + <item type="rect"> + <show type="timed"/> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="75%" y="25%" width="box" height="box"/> + <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0"> + <item type="label" id="timed-label"> + <normal color="#000000" font="Sans 12"/> + <pos x="50%" anchor="n"/> + <!-- Stock label for: User %s will login in %d seconds --> + <stock type="timed-label"/> + </item> + </box> + </item> + + <item type="rect" id="userlist-rect"> + <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/> + <pos anchor="c" x="25%" y="50%" width="box" height="box"/> + <box orientation="vertical" min-width="440" max-width="440" min-height="100" xpadding="4" ypadding="4" spacing="0"> + <item type="list" id="userlist"> + <pos anchor="nw" x="0" y="0" height="550" width="440"/> + <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/> + </item> + </box> + </item> + + <item type="rect"> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="75%" y="50%" width="box" height="box"/> + <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10"> + <item type="label"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 18"/> + <!-- Stock label for: Welcome to %h --> + <stock type="welcome-label"/> + </item> + <item type="label" id="pam-prompt"> + <pos anchor="nw" x="10%"/> + <normal color="#000000" font="Sans 12"/> + <!-- Stock label for: Username: --> + <stock type="username-label"/> + </item> + <item type="rect"> + <normal color="#000000"/> + <pos anchor="n" x="50%" height="24" width="80%"/> + <fixed> + <item type="entry" id="user-pw-entry"> + <normal color="#000000" font="Sans 12"/> + <pos anchor="nw" x="1" y="1" height="-2" width="-2"/> + </item> + </fixed> + </item> + <item type="button" id="ok_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="ok"/> + </item> + <item type="button" id="cancel_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="startagain"/> + </item> + <item type="label" id="pam-message"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </box> + <fixed> + <item type="label" id="pam-error"> + <pos anchor="n" x="50%" y="110%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </fixed> + </item> +</greeter> + + diff --git a/trunk/gui/greeter/themes/happygnome-list/options.png b/trunk/gui/greeter/themes/happygnome-list/options.png Binary files differnew file mode 100644 index 00000000..431813fa --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/options.png diff --git a/trunk/gui/greeter/themes/happygnome-list/screenshot.png b/trunk/gui/greeter/themes/happygnome-list/screenshot.png Binary files differnew file mode 100644 index 00000000..0e9390fc --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome-list/screenshot.png diff --git a/trunk/gui/greeter/themes/happygnome/.cvsignore b/trunk/gui/greeter/themes/happygnome/.cvsignore new file mode 100644 index 00000000..d09a03b4 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in new file mode 100644 index 00000000..d95ac06d --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in @@ -0,0 +1,11 @@ +# This is not really a .desktop file like the rest, but it's useful to treat +# it as such + +[GdmGreeterTheme] +Encoding=UTF-8 +Greeter=happygnome.xml +_Name=Happy GNOME +_Description=GNOME Art variation of Circles +_Author=GNOME Artists +_Copyright=(c) 2002 GNOME +Screenshot=screenshot.png diff --git a/trunk/gui/greeter/themes/happygnome/Makefile.am b/trunk/gui/greeter/themes/happygnome/Makefile.am new file mode 100644 index 00000000..19981eb7 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/Makefile.am @@ -0,0 +1,18 @@ +happygnomedir = $(datadir)/gdm/themes/happygnome +happygnome_DATA = \ + GdmGreeterTheme.desktop \ + happygnome.xml \ + background.svg \ + gnome-logo.svg \ + options.png \ + screenshot.png + +happygnome_in_files = \ + GdmGreeterTheme.desktop.in + +@INTLTOOL_DESKTOP_RULE@ + +EXTRA_DIST = $(happygnome_DATA) $(happygnome_in_files) + +clean-local: + /bin/rm -f GdmGreeterTheme.desktop diff --git a/trunk/gui/greeter/themes/happygnome/background.svg b/trunk/gui/greeter/themes/happygnome/background.svg new file mode 100644 index 00000000..11abc4f4 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/background.svg @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome/gnome-logo.svg b/trunk/gui/greeter/themes/happygnome/gnome-logo.svg new file mode 100644 index 00000000..bdde1d1e --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/gnome-logo.svg @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="us-ascii" ?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st1 "stroke:none;">
+]>
+<svg width="95.991pt" height="150.915pt" viewBox="0 0 95.991 150.915" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st0;">
+ <g style="&st1;">
+ <g>
+ <g>
+ <path d="M86.068,0C61.466,0,56.851,35.041,70.691,35.041C84.529,35.041,110.671,0,86.068,0z"/>
+ <path d="M45.217,30.699c7.369,0.45,15.454-28.122,1.604-26.325c-13.845,1.797-8.976,25.875-1.604,26.325z"/>
+ <path d="M11.445,48.453c5.241-2.307,0.675-24.872-8.237-18.718c-8.908,6.155,2.996,21.024,8.237,18.718z"/>
+ <path d="M26.212,36.642c6.239-1.272,6.581-26.864-4.545-22.273c-11.128,4.592-1.689,23.547,4.545,22.273z"/>
+ <path id="newshape" d="M58.791,93.913c1.107,8.454-6.202,12.629-13.36,7.179C22.644,83.743,83.16,75.088,79.171,51.386c-3.311-19.674-63.676-13.617-70.55,17.167C3.968,89.374,27.774,118.26,52.614,118.26c12.22,0,26.315-11.034,28.952-25.012
+ c2.014-10.659-23.699-6.388-22.775,0.665z"/>
+ </g>
+ </g>
+ <g>
+ <path d="M17.718,132.165l-1.49,2.857c-0.418-0.374-1.064-0.746-1.937-1.115c-0.873-0.369-1.623-0.555-2.25-0.555c-1.964,0-3.514,0.668-4.65,2.004c-1.137,1.337-1.705,3.127-1.705,5.37c0,2.135,0.557,3.841,1.671,5.117c1.114,1.276,2.63,1.915,4.549,1.915
+ c1.264,0,2.305-0.346,3.124-1.037v-3.932h-2.781v-3.031h6.344v8.958c-0.847,0.692-1.938,1.231-3.271,1.618s-2.661,0.58-3.981,0.58c-2.868,0-5.142-0.941-6.822-2.824s-2.52-4.369-2.52-7.459c0-3.092,0.914-5.604,2.743-7.536c1.828-1.933,4.289-2.899,7.382-2.899
+ c2.192,0,4.057,0.656,5.594,1.969z"/>
+ <path d="M34.892,150.853l-9.719-12.688v12.406h-3.406V130.54h1.719l9.438,12.094V130.54h3.406v20.313h-1.438z"/>
+ <path d="M39.487,140.392c0-2.852,0.781-5.264,2.345-7.236c1.563-1.973,3.652-2.959,6.268-2.959c2.881,0,5.082,0.893,6.604,2.679c1.522,1.786,2.283,4.292,2.283,7.517c0,3.227-0.795,5.786-2.385,7.682c-1.592,1.895-3.85,2.842-6.775,2.842
+ c-2.688,0-4.75-0.938-6.186-2.814s-2.153-4.447-2.153-7.709z M43.175,140.392c0,2.342,0.396,4.155,1.19,5.439c0.793,1.285,1.947,1.928,3.461,1.928c1.779,0,3.136-0.629,4.07-1.887c0.936-1.257,1.402-3.084,1.402-5.48c0-4.692-1.732-7.039-5.199-7.039
+ c-1.587,0-2.805,0.636-3.653,1.906c-0.849,1.271-1.272,2.982-1.272,5.133z"/>
+ <path d="M78.831,150.571h-3.438l-2.094-10.781l-4.031,11.063h-1.281L63.94,139.79l-2.141,10.781h-3.438l4.031-20.031h1.875l4.359,13.5l4.234-13.5h1.875l4.094,20.031z"/>
+ <path d="M84.569,133.696v4.688h6.438v3.031h-6.438v6h9.063v3.156H81.006V130.54h12.625v3.156h-9.063z"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome/happygnome.xml b/trunk/gui/greeter/themes/happygnome/happygnome.xml new file mode 100644 index 00000000..2d0d539f --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/happygnome.xml @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE greeter SYSTEM "greeter.dtd"> +<greeter> + <item type="svg" background="true"> + <normal file="background.svg"/> + <pos x="0" y="0" width="100%" height="-75"/> + </item> + <item type="rect" background="true"> + <normal color="#000000"/> + <pos x="0" y="-75" width="100%" height="75"/> + <fixed> + <item type="rect" background="true"> + <normal color="#ffffff"/> + <pos x="0" y="4" width="100%" height="100%"/> + <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10"> + <item type="button" id="options_button"> + <pos width="100" height="50" /> + <stock type="options"/> + </item> + <item type="list" id="language" combo="true"> + <pos x="25" y="5" height="40" width="300"/> + </item> + <item type="list" id="session" combo="true"> + <pos x="50" y="5" height="40" width="300"/> + </item> + </box> + </item> + </fixed> + </item> + <item type="rect" id="userlist-rect"> + <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/> + <pos anchor="nw" x="0" y="0" width="box" height="box"/> + <box orientation="vertical" min-width="440" max-width="440" min-height="100" + xpadding="4" ypadding="4" spacing="0"> + <item type="list" id="userlist"> + <pos anchor="nw" x="0" y="0" height="550" width="440"/> + <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/> + </item> + </box> + </item> + <item type="svg" background="true"> + <normal file="gnome-logo.svg"/> + <pos x="-12" y="-12" width="30" height="47" anchor="se" /> + </item> + <item type="label" id="clock"> + <normal color="#000000" font="Sans 12"/> + <pos x="-80" y="-37" anchor="e"/> + <text>%c</text> + </item> + + <item type="rect" id="caps-lock-warning"> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="50%" y="75%" width="box" height="box"/> + <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0"> + <item type="label"> + <normal color="#000000" font="Sans 12"/> + <pos x="50%" anchor="n"/> + <!-- Stock label for: You've got capslock on! --> + <stock type="caps-lock-warning"/> + </item> + </box> + </item> + + <item type="rect"> + <show type="timed"/> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="50%" y="25%" width="box" height="box"/> + <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0"> + <item type="label" id="timed-label"> + <normal color="#000000" font="Sans 12"/> + <pos x="50%" anchor="n"/> + <!-- Stock label for: User %s will login in %d seconds --> + <stock type="timed-label"/> + </item> + </box> + </item> + + <item type="rect"> + <normal color="#FFFFFF" alpha="0.5"/> + <pos anchor="c" x="50%" y="50%" width="box" height="box"/> + <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10"> + <item type="label"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 14"/> + <!-- Stock label for: Welcome to %h --> + <stock type="welcome-label"/> + </item> + <item type="label" id="pam-prompt"> + <pos anchor="nw" x="10%"/> + <normal color="#000000" font="Sans 12"/> + <!-- Stock label for: Username: --> + <stock type="username-label"/> + </item> + <item type="rect"> + <normal color="#000000"/> + <pos anchor="n" x="50%" height="24" width="80%"/> + <fixed> + <item type="entry" id="user-pw-entry"> + <normal color="#000000" font="Sans 12"/> + <pos anchor="nw" x="1" y="1" height="-2" width="-2"/> + </item> + </fixed> + </item> + <item type="button" id="ok_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="ok"/> + </item> + <item type="button" id="cancel_button"> + <pos anchor="n" x="50%" height="32" width="50%"/> + <stock type="startagain"/> + </item> + <item type="label" id="pam-message"> + <pos anchor="n" x="50%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </box> + <fixed> + <item type="label" id="pam-error"> + <pos anchor="n" x="50%" y="110%"/> + <normal color="#000000" font="Sans 12"/> + <text></text> + </item> + </fixed> + </item> +</greeter> + + diff --git a/trunk/gui/greeter/themes/happygnome/options.png b/trunk/gui/greeter/themes/happygnome/options.png Binary files differnew file mode 100644 index 00000000..431813fa --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/options.png diff --git a/trunk/gui/greeter/themes/happygnome/screenshot.png b/trunk/gui/greeter/themes/happygnome/screenshot.png Binary files differnew file mode 100644 index 00000000..a31c9875 --- /dev/null +++ b/trunk/gui/greeter/themes/happygnome/screenshot.png |