# 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
# 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
#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
{XtNlastEventTime, XtCLastEventTime, XtRInt , sizeof (int),
offset(lastEventTime), XtRImmediate, (XtPointer)0},
{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},
{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},
#endif
{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
#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
# 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
# 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
# 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
# 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 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
w->login.lastEventTime = time(NULL);
#endif
}
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
}
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);
}
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
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);
}
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++)
{
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);
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
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
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);
if (XGrabKeyboard (XtDisplay (w), XtWindow (w), False, GrabModeAsync,
GrabModeAsync, CurrentTime) != GrabSuccess)
{
XSetInputFocus (XtDisplay (w), XtWindow (w),
RevertToPointerRoot, CurrentTime);
}
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
ctx->login.data.name[ctx->login.cursor] = '\0';
break;
case GET_PASSWD:
ctx->login.data.passwd[ctx->login.cursor] = '\0';
break;
}
XorCursor (ctx);
}
static void
EraseLine (
Widget ctxw,
XEvent *event,
String *params,
Cardinal *num_params)
{
MoveToBegining (ctxw, event, params, num_params);
EraseToEndOfLine (ctxw, event, params, num_params);
}
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
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
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);
}
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");
}
}
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);
}
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);
}
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;
w->login.data.name[0] = '\0';
w->login.data.passwd[0] = '\0';
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;
}
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
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));
#endif
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:
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))
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)
)
#endif
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
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
ctx->login.lastEventTime = time(NULL);
#endif
break;
}
XorCursor (ctx);
}
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
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
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);
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;
XpmReadFileToPixmap(XtDisplay(w),
RootWindowOfScreen(XtScreen(w)),
w->login.logoFileName,
&(w->login.logoPixmap),
&(w->login.logoMask),
&myAttributes);
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
w->login.data.name[0] = '\0';
w->login.data.passwd[0] = '\0';
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;
#else
w->core.height = max(fy + pady,
(w->login.logoHeight + (2*w->login.logoPadding)) + pady);
#endif
}
#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
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);
if (True == w->login.logoValid)
{
{
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);
}
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
}
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
}
static void Redisplay(
Widget gw,
XEvent *event,
Region region)
{
draw_it ((LoginWidget) gw);
}
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
;
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
{"abort-session", AbortSession},
{"abort-display", AbortDisplay},
{"restart-session", RestartSession},
{"insert-char", InsertChar},
{"set-session-argument", SetSessionArgument},
{"allow-all-access", AllowAccess},
};
LoginClassRec loginClassRec = {
{
&widgetClassRec,
"Login",
sizeof(LoginRec),
NULL,
NULL,
FALSE,
Initialize,
NULL,
Realize,
loginActionsTable,
XtNumber (loginActionsTable),
resources,
XtNumber(resources),
NULLQUARK,
TRUE,
TRUE,
TRUE,
FALSE,
Destroy,
NULL,
Redisplay,
SetValues,
NULL,
#ifndef XPM
NULL,
#else
XtInheritSetValuesAlmost,
#endif
NULL,
NULL,
XtVersion,
NULL,
defaultLoginTranslations,
XtInheritQueryGeometry,
XtInheritDisplayAccelerator,
NULL
}
};
WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec;