xenocara/app/xdm/greeter/Login.c
2006-11-25 20:07:29 +00:00

1412 lines
40 KiB
C

/* $XdotOrg: app/xdm/greeter/Login.c,v 1.5 2006/04/14 02:52:02 alanc Exp $ */
/* $Xorg: Login.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
/*
Copyright 1988, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
/* $XFree86: xc/programs/xdm/greeter/Login.c,v 3.17tsi Exp $ */
/*
* xdm - display manager daemon
* Author: Keith Packard, MIT X Consortium
*
* Login.c
*/
# include <X11/IntrinsicP.h>
# include <X11/StringDefs.h>
# include <X11/keysym.h>
# include <X11/DECkeysym.h>
# include <X11/Xfuncs.h>
# include <stdio.h>
#ifdef XPM
# include <time.h>
#endif /* XPM */
# include "dm.h"
# include "dm_error.h"
# include "greet.h"
# include "LoginP.h"
#ifdef XPM
#include <sys/stat.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <X11/cursorfont.h>
#endif /* XPM */
#ifdef USE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
static void RedrawFail (LoginWidget w);
static void ResetLogin (LoginWidget w);
static void failTimeout (XtPointer client_data, XtIntervalId * id);
#define offset(field) XtOffsetOf(LoginRec, login.field)
#define goffset(field) XtOffsetOf(WidgetRec, core.field)
static XtResource resources[] = {
{XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
goffset(width), XtRImmediate, (XtPointer) 0},
{XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
goffset(height), XtRImmediate, (XtPointer) 0},
{XtNx, XtCX, XtRPosition, sizeof (Position),
goffset(x), XtRImmediate, (XtPointer) -1},
{XtNy, XtCY, XtRPosition, sizeof (Position),
goffset(y), XtRImmediate, (XtPointer) -1},
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(textpixel), XtRString, XtDefaultForeground},
{XtNpromptColor, XtCForeground, XtRPixel, sizeof(Pixel),
offset(promptpixel), XtRString, XtDefaultForeground},
{XtNgreetColor, XtCForeground, XtRPixel, sizeof(Pixel),
offset(greetpixel), XtRString, XtDefaultForeground},
{XtNfailColor, XtCForeground, XtRPixel, sizeof (Pixel),
offset(failpixel), XtRString, XtDefaultForeground},
#ifdef XPM
/* added by Caolan McNamara */
{XtNlastEventTime, XtCLastEventTime, XtRInt , sizeof (int),
offset(lastEventTime), XtRImmediate, (XtPointer)0},
/* end (caolan) */
/* added by Ivan Griffin (ivan.griffin@ul.ie) */
{XtNlogoFileName, XtCLogoFileName, XtRString, sizeof(char*),
offset(logoFileName), XtRImmediate, (XtPointer)0},
{XtNuseShape, XtCUseShape, XtRBoolean, sizeof(Boolean),
offset(useShape), XtRImmediate, (XtPointer) True},
{XtNlogoPadding, XtCLogoPadding, XtRInt, sizeof(int),
offset(logoPadding), XtRImmediate, (XtPointer) 5},
/* end (ivan) */
/* added by Amit Margalit */
{XtNhiColor, XtCForeground, XtRPixel, sizeof (Pixel),
offset(hipixel), XtRString, XtDefaultForeground},
{XtNshdColor, XtCForeground, XtRPixel, sizeof (Pixel),
offset(shdpixel), XtRString, XtDefaultForeground},
{XtNframeWidth, XtCFrameWidth, XtRInt, sizeof(int),
offset(outframewidth), XtRImmediate, (XtPointer) 1},
{XtNinnerFramesWidth, XtCFrameWidth, XtRInt, sizeof(int),
offset(inframeswidth), XtRImmediate, (XtPointer) 1},
{XtNsepWidth, XtCFrameWidth, XtRInt, sizeof(int),
offset(sepwidth), XtRImmediate, (XtPointer) 1},
/* end (amit) */
#endif /* XPM */
{XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
offset (font), XtRString, "*-new century schoolbook-medium-r-normal-*-180-*"},
{XtNpromptFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
offset (promptFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"},
{XtNgreetFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
offset (greetFont), XtRString, "*-new century schoolbook-bold-i-normal-*-240-*"},
{XtNfailFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
offset (failFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"},
{XtNgreeting, XtCGreeting, XtRString, sizeof (char *),
offset(greeting), XtRString, "X Window System"},
{XtNunsecureGreeting, XtCGreeting, XtRString, sizeof (char *),
offset(unsecure_greet), XtRString, "This is an unsecure session"},
{XtNnamePrompt, XtCNamePrompt, XtRString, sizeof (char *),
offset(namePrompt), XtRString, "Login: "},
{XtNpasswdPrompt, XtCPasswdPrompt, XtRString, sizeof (char *),
offset(passwdPrompt), XtRString, "Password: "},
{XtNfail, XtCFail, XtRString, sizeof (char *),
offset(fail), XtRString,
#if defined(sun) && defined(SVR4)
"Login incorrect or not on system console if root"},
#else
"Login incorrect"},
#endif
{XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int),
offset(failTimeout), XtRImmediate, (XtPointer) 10},
{XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer),
offset(notify_done), XtRFunction, (XtPointer) 0},
{XtNsessionArgument, XtCSessionArgument, XtRString, sizeof (char *),
offset(sessionArg), XtRString, (XtPointer) 0 },
{XtNsecureSession, XtCSecureSession, XtRBoolean, sizeof (Boolean),
offset(secure_session), XtRImmediate, False },
{XtNallowAccess, XtCAllowAccess, XtRBoolean, sizeof (Boolean),
offset(allow_access), XtRImmediate, False },
{XtNallowNullPasswd, XtCAllowNullPasswd, XtRBoolean, sizeof (Boolean),
offset(allow_null_passwd), XtRImmediate, False},
{XtNallowRootLogin, XtCAllowRootLogin, XtRBoolean, sizeof(Boolean),
offset(allow_root_login), XtRImmediate, (XtPointer) True}
};
#undef offset
#undef goffset
# define TEXT_X_INC(w) ((w)->login.font->max_bounds.width)
# define TEXT_Y_INC(w) ((w)->login.font->max_bounds.ascent +\
(w)->login.font->max_bounds.descent)
# define PROMPT_X_INC(w) ((w)->login.promptFont->max_bounds.width)
# define PROMPT_Y_INC(w) ((w)->login.promptFont->max_bounds.ascent +\
(w)->login.promptFont->max_bounds.descent)
# define GREET_X_INC(w) ((w)->login.greetFont->max_bounds.width)
# define GREET_Y_INC(w) ((w)->login.greetFont->max_bounds.ascent +\
(w)->login.greetFont->max_bounds.descent)
# define FAIL_X_INC(w) ((w)->login.failFont->max_bounds.width)
# define FAIL_Y_INC(w) ((w)->login.failFont->max_bounds.ascent +\
(w)->login.failFont->max_bounds.descent)
# define Y_INC(w) max (TEXT_Y_INC(w), PROMPT_Y_INC(w))
#ifndef XPM
# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
w->login.namePrompt,\
strlen (w->login.namePrompt)))
#else
# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
w->login.namePrompt,\
strlen (w->login.namePrompt)) + \
w->login.inframeswidth)
#endif /* XPM */
#ifndef XPM
# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
w->login.passwdPrompt,\
strlen (w->login.passwdPrompt)))
#else
# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
w->login.passwdPrompt,\
strlen (w->login.passwdPrompt)) + \
w->login.inframeswidth)
#endif /* XPM */
# define PROMPT_W(w) (max(LOGIN_PROMPT_W(w), PASS_PROMPT_W(w)))
# define GREETING(w) ((w)->login.secure_session && !(w)->login.allow_access ?\
(w)->login.greeting : (w)->login.unsecure_greet)
# define GREET_X(w) ((int)(w->core.width - XTextWidth (w->login.greetFont,\
GREETING(w), strlen (GREETING(w)))) / 2)
# define GREET_Y(w) (GREETING(w)[0] ? 2 * GREET_Y_INC (w) : 0)
#ifndef XPM
# define GREET_W(w) (max (XTextWidth (w->login.greetFont,\
w->login.greeting, strlen (w->login.greeting)), \
XTextWidth (w->login.greetFont,\
w->login.unsecure_greet, strlen (w->login.unsecure_greet))))
#else
# define GREET_W(w) (max (XTextWidth (w->login.greetFont,\
w->login.greeting, strlen (w->login.greeting)), \
XTextWidth (w->login.greetFont,\
w->login.unsecure_greet, strlen (w->login.unsecure_greet)))) + w->login.logoWidth + (2*w->login.logoPadding)
#endif /* XPM */
# define LOGIN_X(w) (2 * PROMPT_X_INC(w))
# define LOGIN_Y(w) (GREET_Y(w) + GREET_Y_INC(w) +\
w->login.greetFont->max_bounds.ascent + Y_INC(w))
# define LOGIN_W(w) (w->core.width - 6 * TEXT_X_INC(w))
# define LOGIN_H(w) (3 * Y_INC(w) / 2)
# define LOGIN_TEXT_X(w)(LOGIN_X(w) + PROMPT_W(w))
# define PASS_X(w) (LOGIN_X(w))
#ifndef XPM
# define PASS_Y(w) (LOGIN_Y(w) + 8 * Y_INC(w) / 5)
#else
# define PASS_Y(w) (LOGIN_Y(w) + 10 * Y_INC(w) / 5)
#endif /* XPM */
# define PASS_W(w) (LOGIN_W(w))
# define PASS_H(w) (LOGIN_H(w))
# define PASS_TEXT_X(w) (PASS_X(w) + PROMPT_W(w))
# define FAIL_X(w) ((int)(w->core.width - XTextWidth (w->login.failFont,\
w->login.fail, strlen (w->login.fail))) / 2)
# define FAIL_Y(w) (PASS_Y(w) + 2 * FAIL_Y_INC (w) +\
w->login.failFont->max_bounds.ascent)
#ifndef XPM
# define FAIL_W(w) (XTextWidth (w->login.failFont,\
w->login.fail, strlen (w->login.fail)))
#else
# define FAIL_W(w) (XTextWidth (w->login.failFont,\
w->login.fail, strlen (w->login.fail))) + w->login.logoWidth + (2*w->login.logoPadding)
#endif /* XPM */
# define PAD_X(w) (2 * (LOGIN_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w))))
# define PAD_Y(w) (max (max (Y_INC(w), GREET_Y_INC(w)),\
FAIL_Y_INC(w)))
#ifndef max
static inline int max (int a, int b) { return a > b ? a : b; }
#endif
static void
EraseName (LoginWidget w, int cursor)
{
int x;
x = LOGIN_TEXT_X (w);
if (cursor > 0)
x += XTextWidth (w->login.font, w->login.data.name, cursor);
XDrawString (XtDisplay(w), XtWindow (w), w->login.bgGC, x, LOGIN_Y(w),
w->login.data.name + cursor, strlen (w->login.data.name + cursor));
}
static void
DrawName (LoginWidget w, int cursor)
{
int x;
x = LOGIN_TEXT_X (w);
if (cursor > 0)
x += XTextWidth (w->login.font, w->login.data.name, cursor);
XDrawString (XtDisplay(w), XtWindow (w), w->login.textGC, x, LOGIN_Y(w),
w->login.data.name + cursor, strlen (w->login.data.name + cursor));
#ifdef XPM
/*as good a place as any Caolan begin*/
w->login.lastEventTime = time(NULL);
/*as good a place as any Caolan end*/
#endif /* XPM */
}
static void
realizeCursor (LoginWidget w, GC gc)
{
int x, y;
int height, width;
switch (w->login.state) {
case GET_NAME:
x = LOGIN_TEXT_X (w);
y = LOGIN_Y (w);
height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent;
width = 1;
if (w->login.cursor > 0)
x += XTextWidth (w->login.font, w->login.data.name, w->login.cursor);
break;
case GET_PASSWD:
x = PASS_TEXT_X (w);
y = PASS_Y (w);
height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent;
width = 1;
break;
default:
return;
}
XFillRectangle (XtDisplay (w), XtWindow (w), gc,
#ifndef XPM
x, y - w->login.font->max_bounds.ascent, width, height);
#else
x, y+1 - w->login.font->max_bounds.ascent, width, height-1);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x-1 , y - w->login.font->max_bounds.ascent);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x+1 , y - w->login.font->max_bounds.ascent);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x-1 , y - w->login.font->max_bounds.ascent+height);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x+1 , y - w->login.font->max_bounds.ascent+height);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x-2 , y - w->login.font->max_bounds.ascent);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x+2 , y - w->login.font->max_bounds.ascent);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x-2 , y - w->login.font->max_bounds.ascent+height);
XDrawPoint (XtDisplay (w), XtWindow (w), gc,
x+2 , y - w->login.font->max_bounds.ascent+height);
#endif /* XPM */
}
static void
EraseFail (LoginWidget w)
{
int x = FAIL_X(w);
int y = FAIL_Y(w);
XSetForeground (XtDisplay (w), w->login.failGC,
w->core.background_pixel);
XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC,
x, y,
w->login.fail, strlen (w->login.fail));
w->login.failUp = 0;
XSetForeground (XtDisplay (w), w->login.failGC,
w->login.failpixel);
}
static void
XorCursor (LoginWidget w)
{
realizeCursor (w, w->login.xorGC);
}
static void
RemoveFail (LoginWidget w)
{
if (w->login.failUp)
EraseFail (w);
}
static void
EraseCursor (LoginWidget w)
{
realizeCursor (w, w->login.bgGC);
}
/*ARGSUSED*/
static void failTimeout (XtPointer client_data, XtIntervalId * id)
{
LoginWidget w = (LoginWidget)client_data;
Debug ("failTimeout\n");
EraseFail (w);
}
void
DrawFail (Widget ctx)
{
LoginWidget w;
w = (LoginWidget) ctx;
XorCursor (w);
ResetLogin (w);
XorCursor (w);
w->login.failUp = 1;
RedrawFail (w);
if (w->login.failTimeout > 0) {
Debug ("failTimeout: %d\n", w->login.failTimeout);
XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w),
w->login.failTimeout * 1000,
failTimeout, (XtPointer) w);
}
}
static void
RedrawFail (LoginWidget w)
{
int x = FAIL_X(w);
int y = FAIL_Y(w);
if (w->login.failUp)
XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC,
x, y,
w->login.fail, strlen (w->login.fail));
}
static void
draw_it (LoginWidget w)
{
#ifdef XPM
int i,in_frame_x,in_login_y,in_pass_y,in_width,in_height;
int gr_line_x, gr_line_y, gr_line_w;
#endif /* XPM */
EraseCursor (w);
#ifdef XPM
if( (w->login.outframewidth) < 1 )
w->login.outframewidth = 1;
for(i=1;i<=(w->login.outframewidth);i++)
{
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
i-1,i-1,w->core.width-i,i-1);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
i-1,i-1,i-1,w->core.height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
w->core.width-i,i-1,w->core.width-i,w->core.height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
i-1,w->core.height-i,w->core.width-i,w->core.height-i);
}
/* make separator line */
gr_line_x = w->login.outframewidth + w->login.logoPadding;
gr_line_y = GREET_Y(w) + GREET_Y_INC(w);
gr_line_w = w->core.width - 2*(w->login.outframewidth) -
(w->login.logoWidth + 3*(w->login.logoPadding));
for(i=1;i<=(w->login.sepwidth);i++)
{
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
gr_line_x, gr_line_y + i-1,
gr_line_x+gr_line_w, gr_line_y + i-1);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
gr_line_x, gr_line_y + 2*(w->login.inframeswidth) -i,
gr_line_x+gr_line_w, gr_line_y + 2*(w->login.inframeswidth) -i);
}
in_frame_x = LOGIN_TEXT_X(w) - w->login.inframeswidth - 3;
in_login_y = LOGIN_Y(w) - w->login.inframeswidth - 1 - TEXT_Y_INC(w);
in_pass_y = PASS_Y(w) - w->login.inframeswidth - 1 - TEXT_Y_INC(w);
in_width = LOGIN_W(w) - PROMPT_W(w) -
(w->login.logoWidth + 2*(w->login.logoPadding));
in_height = LOGIN_H(w) + w->login.inframeswidth + 2;
for(i=1;i<=(w->login.inframeswidth);i++)
{
/* Make top/left sides */
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
in_frame_x + i-1, in_login_y + i-1,
in_frame_x + in_width-i, in_login_y + i-1);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
in_frame_x + i-1, in_login_y + i-1,
in_frame_x + i-1, in_login_y + in_height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
in_frame_x + in_width-i, in_login_y + i-1,
in_frame_x + in_width-i, in_login_y + in_height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
in_frame_x + i-1, in_login_y + in_height-i,
in_frame_x + in_width-i, in_login_y + in_height-i);
/* Make bottom/right sides */
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
in_frame_x + i-1, in_pass_y + i-1,
in_frame_x + in_width-i, in_pass_y + i-1);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
in_frame_x + i-1, in_pass_y + i-1,
in_frame_x + i-1, in_pass_y + in_height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
in_frame_x + in_width-i, in_pass_y + i-1,
in_frame_x + in_width-i, in_pass_y + in_height-i);
XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
in_frame_x + i-1, in_pass_y + in_height-i,
in_frame_x + in_width-i, in_pass_y + in_height-i);
}
#endif /* XPM */
if (GREETING(w)[0])
XDrawString (XtDisplay (w), XtWindow (w), w->login.greetGC,
#ifndef XPM
GREET_X(w), GREET_Y(w),
#else
GREET_X(w) -
((w->login.logoWidth/2) + w->login.logoPadding),
GREET_Y(w),
#endif /* XPM */
GREETING(w), strlen (GREETING(w)));
XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC,
LOGIN_X(w), LOGIN_Y(w),
w->login.namePrompt, strlen (w->login.namePrompt));
XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC,
PASS_X(w), PASS_Y(w),
w->login.passwdPrompt, strlen (w->login.passwdPrompt));
RedrawFail (w);
DrawName (w, 0);
XorCursor (w);
/*
* The GrabKeyboard here is needed only because of
* a bug in the R3 server -- the keyboard is grabbed on
* the root window, and the server won't dispatch events
* to the focus window unless the focus window is a ancestor
* of the grab window. Bug in server already found and fixed,
* compatibility until at least R4.
*/
if (XGrabKeyboard (XtDisplay (w), XtWindow (w), False, GrabModeAsync,
GrabModeAsync, CurrentTime) != GrabSuccess)
{
XSetInputFocus (XtDisplay (w), XtWindow (w),
RevertToPointerRoot, CurrentTime);
}
}
/*ARGSUSED*/
static void
DeleteBackwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
if (ctx->login.cursor > 0) {
ctx->login.cursor--;
switch (ctx->login.state) {
case GET_NAME:
EraseName (ctx, ctx->login.cursor);
strcpy (ctx->login.data.name + ctx->login.cursor,
ctx->login.data.name + ctx->login.cursor + 1);
DrawName (ctx, ctx->login.cursor);
break;
case GET_PASSWD:
strcpy (ctx->login.data.passwd + ctx->login.cursor,
ctx->login.data.passwd + ctx->login.cursor + 1);
break;
}
}
XorCursor (ctx);
}
/*ARGSUSED*/
static void
DeleteForwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
if (ctx->login.cursor < (int)strlen (ctx->login.data.name)) {
EraseName (ctx, ctx->login.cursor);
strcpy (ctx->login.data.name + ctx->login.cursor,
ctx->login.data.name + ctx->login.cursor + 1);
DrawName (ctx, ctx->login.cursor);
}
break;
case GET_PASSWD:
if (ctx->login.cursor < (int)strlen (ctx->login.data.passwd)) {
strcpy (ctx->login.data.passwd + ctx->login.cursor,
ctx->login.data.passwd + ctx->login.cursor + 1);
}
break;
}
XorCursor (ctx);
}
/*ARGSUSED*/
static void
MoveBackwardChar (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
if (ctx->login.cursor > 0)
ctx->login.cursor--;
XorCursor (ctx);
}
/*ARGSUSED*/
static void
MoveForwardChar (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
if (ctx->login.cursor < (int)strlen(ctx->login.data.name))
++ctx->login.cursor;
break;
case GET_PASSWD:
if (ctx->login.cursor < (int)strlen(ctx->login.data.passwd))
++ctx->login.cursor;
break;
}
XorCursor (ctx);
}
/*ARGSUSED*/
static void
MoveToBegining (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
ctx->login.cursor = 0;
XorCursor (ctx);
}
/*ARGSUSED*/
static void
MoveToEnd (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
ctx->login.cursor = strlen (ctx->login.data.name);
break;
case GET_PASSWD:
ctx->login.cursor = strlen (ctx->login.data.passwd);
break;
}
XorCursor (ctx);
}
/*ARGSUSED*/
static void
EraseToEndOfLine (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
EraseName (ctx, ctx->login.cursor);
bzero (ctx->login.data.name, NAME_LEN);
break;
case GET_PASSWD:
bzero (ctx->login.data.passwd, PASSWORD_LEN);
break;
}
XorCursor (ctx);
}
/*ARGSUSED*/
static void
EraseLine (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
MoveToBegining (ctxw, event, params, num_params);
EraseToEndOfLine (ctxw, event, params, num_params);
}
/*ARGSUSED*/
static void
FinishField (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
ctx->login.state = GET_PASSWD;
ctx->login.cursor = 0;
break;
case GET_PASSWD:
ctx->login.state = DONE;
ctx->login.cursor = 0;
(*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_OK);
break;
}
XorCursor (ctx);
}
#ifdef XPM
/*ARGSUSED*/
static void
TabField(Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
ctx->login.state = GET_PASSWD;
ctx->login.cursor = 0;
break;
case GET_PASSWD:
ctx->login.state = GET_NAME;
ctx->login.cursor = 0;
break;
}
XorCursor (ctx);
}
#endif /* XPM */
/*ARGSUSED*/
static void
AllowAccess (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
Arg arglist[1];
Boolean allow;
RemoveFail (ctx);
XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
XtGetValues ((Widget) ctx, arglist, 1);
XtSetArg (arglist[0], XtNallowAccess, !allow);
XtSetValues ((Widget) ctx, arglist, 1);
}
/*ARGSUSED*/
static void
SetSessionArgument (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
RemoveFail (ctx);
if (ctx->login.sessionArg)
XtFree (ctx->login.sessionArg);
ctx->login.sessionArg = 0;
if (*num_params > 0) {
ctx->login.sessionArg = XtMalloc (strlen (params[0]) + 1);
if (ctx->login.sessionArg)
strcpy (ctx->login.sessionArg, params[0]);
else
LogOutOfMem ("set session argument");
}
}
/*ARGSUSED*/
static void
RestartSession (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
ctx->login.state = DONE;
ctx->login.cursor = 0;
(*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_RESTART);
XorCursor (ctx);
}
/*ARGSUSED*/
static void
AbortSession (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
ctx->login.state = DONE;
ctx->login.cursor = 0;
(*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT);
XorCursor (ctx);
}
/*ARGSUSED*/
static void
AbortDisplay (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
XorCursor (ctx);
RemoveFail (ctx);
ctx->login.state = DONE;
ctx->login.cursor = 0;
(*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT_DISPLAY);
XorCursor (ctx);
}
static void
ResetLogin (LoginWidget w)
{
EraseName (w, 0);
w->login.cursor = 0;
bzero (w->login.data.name, NAME_LEN);
bzero (w->login.data.passwd, PASSWORD_LEN);
w->login.state = GET_NAME;
}
static void
InitI18N(Widget ctxw)
{
LoginWidget ctx = (LoginWidget)ctxw;
XIM xim = (XIM) NULL;
char *p;
ctx->login.xic = (XIC) NULL;
if ((p = XSetLocaleModifiers("@im=none")) != NULL && *p)
xim = XOpenIM(XtDisplay(ctx), NULL, NULL, NULL);
if (!xim) {
LogError("Failed to open input method\n");
return;
}
ctx->login.xic = XCreateIC(xim,
XNInputStyle, (XIMPreeditNothing|XIMStatusNothing),
XNClientWindow, ctx->core.window,
XNFocusWindow, ctx->core.window, NULL);
if (!ctx->login.xic) {
LogError("Failed to create input context\n");
XCloseIM(xim);
}
return;
}
/* ARGSUSED */
static void
InsertChar (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
LoginWidget ctx = (LoginWidget)ctxw;
char strbuf[128];
#ifndef XPM
int len;
#else
int len,pixels;
#endif /* XPM */
KeySym keysym = 0;
if (ctx->login.xic) {
static Status status;
len = XmbLookupString(ctx->login.xic, &event->xkey, strbuf,
sizeof (strbuf), &keysym, &status);
} else {
static XComposeStatus compose_status = {NULL, 0};
len = XLookupString (&event->xkey, strbuf, sizeof (strbuf),
&keysym, &compose_status);
}
strbuf[len] = '\0';
#ifdef XPM
pixels = 3 + ctx->login.font->max_bounds.width * len +
XTextWidth(ctx->login.font,
ctx->login.data.name,
strlen(ctx->login.data.name));
/* pixels to be added */
#endif /* XPM */
/*
* Note: You can override this default key handling
* by the settings in the translation table
* loginActionsTable at the end of this file.
*/
switch (keysym) {
case XK_Return:
case XK_KP_Enter:
case XK_Linefeed:
case XK_Execute:
FinishField(ctxw, event, params, num_params);
return;
case XK_BackSpace:
DeleteBackwardChar(ctxw, event, params, num_params);
return;
case XK_Delete:
case XK_KP_Delete:
case DXK_Remove:
/* Sorry, it's not a telex machine, it's a terminal */
DeleteForwardChar(ctxw, event, params, num_params);
return;
case XK_Left:
case XK_KP_Left:
MoveBackwardChar(ctxw, event, params, num_params);
return;
case XK_Right:
case XK_KP_Right:
MoveForwardChar(ctxw, event, params, num_params);
return;
case XK_End:
case XK_KP_End:
MoveToEnd(ctxw, event, params, num_params);
return;
case XK_Home:
case XK_KP_Home:
MoveToBegining(ctxw, event, params, num_params);
return;
default:
if (len == 0) {
if (!IsModifierKey(keysym)) /* it's not a modifier */
XBell(XtDisplay(ctxw), 60);
return;
} else
break;
}
switch (ctx->login.state) {
case GET_NAME:
#ifndef XPM
if (len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1)
#else
if (
(len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1)/* &&
(pixels <= LOGIN_W(ctx) - PROMPT_W(ctx))*/
)
#endif /* XPM */
len = NAME_LEN - strlen(ctx->login.data.name) - 2;
case GET_PASSWD:
if (len + (int)strlen(ctx->login.data.passwd) >= PASSWORD_LEN - 1)
len = PASSWORD_LEN - strlen(ctx->login.data.passwd) - 2;
}
#ifndef XPM
if (len == 0)
#else
if (len == 0 || pixels >= LOGIN_W(ctx) - PROMPT_W(ctx))
#endif /* XPM */
return;
XorCursor (ctx);
RemoveFail (ctx);
switch (ctx->login.state) {
case GET_NAME:
EraseName (ctx, ctx->login.cursor);
memmove( ctx->login.data.name + ctx->login.cursor + len,
ctx->login.data.name + ctx->login.cursor,
strlen (ctx->login.data.name + ctx->login.cursor) + 1);
memmove( ctx->login.data.name + ctx->login.cursor, strbuf, len);
DrawName (ctx, ctx->login.cursor);
ctx->login.cursor += len;
break;
case GET_PASSWD:
memmove( ctx->login.data.passwd + ctx->login.cursor + len,
ctx->login.data.passwd + ctx->login.cursor,
strlen (ctx->login.data.passwd + ctx->login.cursor) + 1);
memmove( ctx->login.data.passwd + ctx->login.cursor, strbuf, len);
ctx->login.cursor += len;
#ifdef XPM
/*as good a place as any Caolan begin*/
ctx->login.lastEventTime = time(NULL);
/*as good a place as any Caolan end*/
#endif /* XPM */
break;
}
XorCursor (ctx);
}
/* ARGSUSED */
static void Initialize (
Widget greq,
Widget gnew,
ArgList args,
Cardinal *num_args)
{
LoginWidget w = (LoginWidget)gnew;
XtGCMask valuemask, xvaluemask;
XGCValues myXGCV;
Arg position[2];
Position x, y;
#ifdef USE_XINERAMA
XineramaScreenInfo *screens;
int s_num;
#endif
#ifdef XPM
int rv = 0;
myXGCV.foreground = w->login.hipixel;
myXGCV.background = w->core.background_pixel;
valuemask = GCForeground | GCBackground;
w->login.hiGC = XtGetGC(gnew, valuemask, &myXGCV);
myXGCV.foreground = w->login.shdpixel;
myXGCV.background = w->core.background_pixel;
valuemask = GCForeground | GCBackground;
w->login.shdGC = XtGetGC(gnew, valuemask, &myXGCV);
#endif /* XPM */
myXGCV.foreground = w->login.textpixel;
myXGCV.background = w->core.background_pixel;
valuemask = GCForeground | GCBackground;
if (w->login.font) {
myXGCV.font = w->login.font->fid;
valuemask |= GCFont;
}
w->login.textGC = XtGetGC(gnew, valuemask, &myXGCV);
myXGCV.foreground = w->core.background_pixel;
w->login.bgGC = XtGetGC(gnew, valuemask, &myXGCV);
myXGCV.foreground = w->login.textpixel ^ w->core.background_pixel;
myXGCV.function = GXxor;
xvaluemask = valuemask | GCFunction;
w->login.xorGC = XtGetGC (gnew, xvaluemask, &myXGCV);
/*
* Note that the second argument is a GCid -- QueryFont accepts a GCid and
* returns the curently contained font.
*/
if (w->login.font == NULL)
w->login.font = XQueryFont (XtDisplay (w),
XGContextFromGC (XDefaultGCOfScreen (XtScreen (w))));
xvaluemask = valuemask;
if (w->login.promptFont == NULL)
w->login.promptFont = w->login.font;
else
xvaluemask |= GCFont;
myXGCV.foreground = w->login.promptpixel;
myXGCV.font = w->login.promptFont->fid;
w->login.promptGC = XtGetGC (gnew, xvaluemask, &myXGCV);
xvaluemask = valuemask;
if (w->login.greetFont == NULL)
w->login.greetFont = w->login.font;
else
xvaluemask |= GCFont;
myXGCV.foreground = w->login.greetpixel;
myXGCV.font = w->login.greetFont->fid;
w->login.greetGC = XtGetGC (gnew, xvaluemask, &myXGCV);
xvaluemask = valuemask;
if (w->login.failFont == NULL)
w->login.failFont = w->login.font;
else
xvaluemask |= GCFont;
myXGCV.foreground = w->login.failpixel;
myXGCV.font = w->login.failFont->fid;
w->login.failGC = XtGetGC (gnew, xvaluemask, &myXGCV);
#ifdef XPM
w->login.logoValid = False;
if (NULL != w->login.logoFileName)
{
XpmAttributes myAttributes = { 0 };
Window tmpWindow = { 0 };
struct stat myBuffer = { 0 };
unsigned int myPixmapDepth = 0;
if (0 != stat(w->login.logoFileName, &myBuffer))
{
LogError("Unable to stat() pixmap file %s\n",
w->login.logoFileName);
w->login.logoValid = False;
goto SkipXpmLoad;
}
myAttributes.valuemask |= XpmReturnPixels;
myAttributes.valuemask |= XpmReturnExtensions;
rv = XpmReadFileToPixmap(XtDisplay(w), /* display */
RootWindowOfScreen(XtScreen(w)), /* window */
w->login.logoFileName, /* XPM filename */
&(w->login.logoPixmap), /* pixmap */
&(w->login.logoMask), /* pixmap mask */
&myAttributes); /* XPM attributes */
if ( rv < 0 )
{
LogError("Cannot load xpm file %s: %s.\n", w->login.logoFileName,
XpmGetErrorString(rv));
goto SkipXpmLoad;
}
w->login.logoValid = True;
XGetGeometry(XtDisplay(w), w->login.logoPixmap,
&tmpWindow,
&(w->login.logoX),
&(w->login.logoY),
&(w->login.logoWidth),
&(w->login.logoHeight),
&(w->login.logoBorderWidth),
&myPixmapDepth);
} else {
w->login.logoX = 0;
w->login.logoY = 0;
w->login.logoWidth = 0;
w->login.logoHeight = 0;
w->login.logoBorderWidth = 0;
}
SkipXpmLoad:
#endif /* XPM */
bzero (w->login.data.name, NAME_LEN);
bzero (w->login.data.passwd, PASSWORD_LEN);
w->login.state = GET_NAME;
w->login.cursor = 0;
w->login.failUp = 0;
if (w->core.width == 0)
w->core.width = max (GREET_W(w), FAIL_W(w)) + PAD_X(w);
if (w->core.height == 0) {
int fy = FAIL_Y(w);
int pady = PAD_Y(w);
#ifndef XPM
w->core.height = fy + pady; /* for stupid compilers */
#else
/* w->core.height = fy + pady; * for stupid compilers */
w->core.height = max(fy + pady,
(w->login.logoHeight + (2*w->login.logoPadding)) + pady);
#endif /* XPM */
}
#ifdef USE_XINERAMA
if (
XineramaIsActive(XtDisplay(w)) &&
(screens = XineramaQueryScreens(XtDisplay(w), &s_num)) != NULL
)
{
if ((x = w->core.x) == -1)
x = screens[0].x_org + (int)(screens[0].width - w->core.width) / 2;
if ((y = w->core.y) == -1)
y = screens[0].y_org + (int)(screens[0].height - w->core.height) / 3;
XFree(screens);
}
else
#endif
{
if ((x = w->core.x) == -1)
x = (int)(XWidthOfScreen (XtScreen (w)) - w->core.width) / 2;
if ((y = w->core.y) == -1)
y = (int)(XHeightOfScreen (XtScreen (w)) - w->core.height) / 3;
}
XtSetArg (position[0], XtNx, x);
XtSetArg (position[1], XtNy, y);
XtSetValues (XtParent (w), position, (Cardinal) 2);
}
static void Realize (
Widget gw,
XtValueMask *valueMask,
XSetWindowAttributes *attrs)
{
#ifdef XPM
LoginWidget w = (LoginWidget) gw;
Cursor cursor;
#endif /* XPM */
XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
*valueMask, attrs );
InitI18N(gw);
#ifdef XPM
cursor = XCreateFontCursor(XtDisplay(gw), XC_left_ptr);
XDefineCursor(XtDisplay(gw), XtWindow(gw), cursor);
/*
* Check if Pixmap was valid
*/
if (True == w->login.logoValid)
{
/*
* Create pixmap window
*/
{
unsigned long valueMask = CWBackPixel | CWBackPixmap;
XSetWindowAttributes windowAttributes = { 0 };
windowAttributes.background_pixel = w->core.background_pixel;
windowAttributes.background_pixmap = None;
w->login.logoWindow = XCreateWindow(XtDisplay(w),
XtWindow(w),
w->core.width - w->login.outframewidth -
w->login.logoWidth - w->login.logoPadding,
(w->core.height - w->login.logoHeight) /2,
w->login.logoWidth, w->login.logoHeight, 0,
CopyFromParent, InputOutput, CopyFromParent,
valueMask, &windowAttributes);
}
/*
* check if we can use shape extension
*/
if (True == w->login.useShape)
{
int foo, bar;
if (XShapeQueryExtension(XtDisplay(w), &foo, &bar) == TRUE)
{
XShapeCombineMask(XtDisplay(w), w->login.logoWindow,
ShapeBounding, w->login.logoX, w->login.logoY,
w->login.logoMask, ShapeSet);
}
}
XSetWindowBackgroundPixmap(XtDisplay(w), w->login.logoWindow,
w->login.logoPixmap);
XMapWindow(XtDisplay(w), w->login.logoWindow);
}
#endif /* XPM */
}
static void Destroy (Widget gw)
{
LoginWidget w = (LoginWidget)gw;
bzero (w->login.data.name, NAME_LEN);
bzero (w->login.data.passwd, PASSWORD_LEN);
XtReleaseGC(gw, w->login.textGC);
XtReleaseGC(gw, w->login.bgGC);
XtReleaseGC(gw, w->login.xorGC);
XtReleaseGC(gw, w->login.promptGC);
XtReleaseGC(gw, w->login.greetGC);
XtReleaseGC(gw, w->login.failGC);
#ifdef XPM
XtReleaseGC(gw, w->login.hiGC);
XtReleaseGC(gw, w->login.shdGC);
if (True == w->login.logoValid)
{
if (w->login.logoPixmap != 0)
XFreePixmap(XtDisplay(w), w->login.logoPixmap);
if (w->login.logoMask != 0)
XFreePixmap(XtDisplay(w), w->login.logoMask);
}
#endif /* XPM */
}
/* ARGSUSED */
static void Redisplay(
Widget gw,
XEvent *event,
Region region)
{
draw_it ((LoginWidget) gw);
}
/*ARGSUSED*/
static Boolean SetValues (
Widget current,
Widget request,
Widget new,
ArgList args,
Cardinal *num_args)
{
LoginWidget currentL, newL;
currentL = (LoginWidget) current;
newL = (LoginWidget) new;
if (GREETING (currentL) != GREETING (newL))
return True;
return False;
}
char defaultLoginTranslations [] =
"Ctrl<Key>H: delete-previous-character() \n"
"Ctrl<Key>D: delete-character() \n"
"Ctrl<Key>B: move-backward-character() \n"
"Ctrl<Key>F: move-forward-character() \n"
"Ctrl<Key>A: move-to-begining() \n"
"Ctrl<Key>E: move-to-end() \n"
"Ctrl<Key>K: erase-to-end-of-line() \n"
"Ctrl<Key>U: erase-line() \n"
"Ctrl<Key>X: erase-line() \n"
"Ctrl<Key>C: restart-session() \n"
"Ctrl<Key>\\\\: abort-session() \n"
":Ctrl<Key>plus: allow-all-access() \n"
"<Key>BackSpace: delete-previous-character() \n"
#ifdef linux
"<Key>Delete: delete-character() \n"
#else
"<Key>Delete: delete-previous-character() \n"
#endif
"<Key>Return: finish-field() \n"
#ifndef XPM
"<KeyPress>: insert-char()"
#else
"<Key>Tab: tab-field() \n"
"<KeyPress>: insert-char()"
#endif /* XPM */
;
XtActionsRec loginActionsTable [] = {
{"delete-previous-character", DeleteBackwardChar},
{"delete-character", DeleteForwardChar},
{"move-backward-character", MoveBackwardChar},
{"move-forward-character", MoveForwardChar},
{"move-to-begining", MoveToBegining},
{"move-to-end", MoveToEnd},
{"erase-to-end-of-line", EraseToEndOfLine},
{"erase-line", EraseLine},
{"finish-field", FinishField},
#ifdef XPM
{"tab-field", TabField},
#endif /* XPM */
{"abort-session", AbortSession},
{"abort-display", AbortDisplay},
{"restart-session", RestartSession},
{"insert-char", InsertChar},
{"set-session-argument", SetSessionArgument},
{"allow-all-access", AllowAccess},
};
LoginClassRec loginClassRec = {
{ /* core fields */
/* superclass */ &widgetClassRec,
/* class_name */ "Login",
/* size */ sizeof(LoginRec),
/* class_initialize */ NULL,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ loginActionsTable,
/* num_actions */ XtNumber (loginActionsTable),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ NULL,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
#ifndef XPM
/* set_values_almost */ NULL,
#else
/* set_values_almost */ XtInheritSetValuesAlmost,
#endif /* XPM */
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultLoginTranslations,
/* query_geometry */ XtInheritQueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
}
};
WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec;