123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- /* SLiM - Simple Login Manager
- Copyright (C) 1997, 1998 Per Liden
- Copyright (C) 2004-06 Simone Rota <sip@varlock.com>
- Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.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.
- */
- #include <sstream>
- #include "panel.h"
- using namespace std;
- Panel::Panel(Display* dpy, int scr, Window root, Cfg* config,
- const string& themedir) {
- // Set display
- Dpy = dpy;
- Scr = scr;
- Root = root;
- cfg = config;
- session = "";
- // Init GC
- XGCValues gcv;
- unsigned long gcm;
- gcm = GCForeground|GCBackground|GCGraphicsExposures;
- gcv.foreground = GetColor("black");
- gcv.background = GetColor("white");
- gcv.graphics_exposures = False;
- TextGC = XCreateGC(Dpy, Root, gcm, &gcv);
- font = XftFontOpenName(Dpy, Scr, cfg->getOption("input_font").c_str());
- welcomefont = XftFontOpenName(Dpy, Scr, cfg->getOption("welcome_font").c_str());
- introfont = XftFontOpenName(Dpy, Scr, cfg->getOption("intro_font").c_str());
- enterfont = XftFontOpenName(Dpy, Scr, cfg->getOption("username_font").c_str());
- msgfont = XftFontOpenName(Dpy, Scr, cfg->getOption("msg_font").c_str());
- Visual* visual = DefaultVisual(Dpy, Scr);
- Colormap colormap = DefaultColormap(Dpy, Scr);
- // NOTE: using XftColorAllocValue() would be a better solution. Lazy me.
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_color").c_str(), &inputcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("input_shadow_color").c_str(), &inputshadowcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_color").c_str(), &welcomecolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("welcome_shadow_color").c_str(), &welcomeshadowcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_color").c_str(), &entercolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("username_shadow_color").c_str(), &entershadowcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_color").c_str(), &msgcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("msg_shadow_color").c_str(), &msgshadowcolor);
- XftColorAllocName(Dpy, visual, colormap, cfg->getOption("intro_color").c_str(), &introcolor);
- // Load properties from config / theme
- input_name_x = Cfg::string2int(cfg->getOption("input_name_x").c_str());
- input_name_y = Cfg::string2int(cfg->getOption("input_name_y").c_str());
- input_pass_x = Cfg::string2int(cfg->getOption("input_pass_x").c_str());
- input_pass_y = Cfg::string2int(cfg->getOption("input_pass_y").c_str());
- inputShadowXOffset =
- Cfg::string2int(cfg->getOption("input_shadow_xoffset").c_str());
- inputShadowYOffset =
- Cfg::string2int(cfg->getOption("input_shadow_yoffset").c_str());
- if (input_pass_x < 0 || input_pass_y < 0){ // single inputbox mode
- input_pass_x = input_name_x;
- input_pass_y = input_name_y;
- }
- // Load panel and background image
- string panelpng = "";
- panelpng = panelpng + themedir +"/panel.png";
- image = new Image;
- bool loaded = image->Read(panelpng.c_str());
- if (!loaded) { // try jpeg if png failed
- panelpng = themedir + "/panel.jpg";
- loaded = image->Read(panelpng.c_str());
- if (!loaded) {
- cerr << APPNAME
- << ": could not load panel image for theme '"
- << basename((char*)themedir.c_str()) << "'"
- << endl;
- exit(ERR_EXIT);
- }
- }
- Image* bg = new Image();
- string bgstyle = cfg->getOption("background_style");
- if (bgstyle != "color") {
- panelpng = themedir +"/background.png";
- loaded = bg->Read(panelpng.c_str());
- if (!loaded) { // try jpeg if png failed
- panelpng = themedir + "/background.jpg";
- loaded = bg->Read(panelpng.c_str());
- if (!loaded){
- cerr << APPNAME
- << ": could not load background image for theme '"
- << basename((char*)themedir.c_str()) << "'"
- << endl;
- exit(ERR_EXIT);
- }
- }
- }
- if (bgstyle == "stretch") {
- bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));
- } else if (bgstyle == "tile") {
- bg->Tile(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));
- } else if (bgstyle == "center") {
- string hexvalue = cfg->getOption("background_color");
- hexvalue = hexvalue.substr(1,6);
- bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
- XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
- hexvalue.c_str());
- } else { // plain color or error
- string hexvalue = cfg->getOption("background_color");
- hexvalue = hexvalue.substr(1,6);
- bg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),
- XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),
- hexvalue.c_str());
- }
- string cfgX = cfg->getOption("input_panel_x");
- string cfgY = cfg->getOption("input_panel_y");
- X = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Width());
- Y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Height());
- // Merge image into background
- image->Merge(bg, X, Y);
- delete bg;
- PanelPixmap = image->createPixmap(Dpy, Scr, Root);
- // Read (and substitute vars in) the welcome message
- welcome_message = cfg->getWelcomeMessage();
- intro_message = cfg->getOption("intro_msg");
- }
- Panel::~Panel() {
- XftColorFree (Dpy, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr), &inputcolor);
- XftColorFree (Dpy, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr), &msgcolor);
- XftColorFree (Dpy, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr), &welcomecolor);
- XftColorFree (Dpy, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr), &entercolor);
- XFreeGC(Dpy, TextGC);
- XftFontClose(Dpy, font);
- XftFontClose(Dpy, msgfont);
- XftFontClose(Dpy, introfont);
- XftFontClose(Dpy, welcomefont);
- XftFontClose(Dpy, enterfont);
- delete image;
- }
- void Panel::OpenPanel() {
- // Create window
- Win = XCreateSimpleWindow(Dpy, Root, X, Y,
- image->Width(),
- image->Height(),
- 0, GetColor("white"), GetColor("white"));
- // Events
- XSelectInput(Dpy, Win, ExposureMask | KeyPressMask);
- // Set background
- XSetWindowBackgroundPixmap(Dpy, Win, PanelPixmap);
- // Show window
- XMapWindow(Dpy, Win);
- XMoveWindow(Dpy, Win, X, Y); // override wm positioning (for tests)
- // Grab keyboard
- XGrabKeyboard(Dpy, Win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
- XFlush(Dpy);
- }
- void Panel::ClosePanel() {
- XUngrabKeyboard(Dpy, CurrentTime);
- XUnmapWindow(Dpy, Win);
- XDestroyWindow(Dpy, Win);
- XFlush(Dpy);
- }
- void Panel::ClearPanel() {
- session = "";
- Reset();
- XClearWindow(Dpy, Root);
- XClearWindow(Dpy, Win);
- Cursor(SHOW);
- ShowText();
- XFlush(Dpy);
- }
- void Panel::Message(const string& text) {
- string cfgX, cfgY;
- XGlyphInfo extents;
- XftDraw *draw = XftDrawCreate(Dpy, Root,
- DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
- XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(text.c_str()),
- text.length(), &extents);
- cfgX = cfg->getOption("msg_x");
- cfgY = cfg->getOption("msg_y");
- int shadowXOffset =
- Cfg::string2int(cfg->getOption("msg_shadow_xoffset").c_str());
- int shadowYOffset =
- Cfg::string2int(cfg->getOption("msg_shadow_yoffset").c_str());
- int msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
- int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);
- SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,
- text,
- &msgshadowcolor,
- shadowXOffset, shadowYOffset);
- XFlush(Dpy);
- XftDrawDestroy(draw);
- }
- void Panel::Error(const string& text) {
- ClosePanel();
- Message(text);
- sleep(ERROR_DURATION);
- OpenPanel();
- ClearPanel();
- }
- unsigned long Panel::GetColor(const char* colorname) {
- XColor color;
- XWindowAttributes attributes;
- XGetWindowAttributes(Dpy, Root, &attributes);
- color.pixel = 0;
- if(!XParseColor(Dpy, attributes.colormap, colorname, &color))
- cerr << APPNAME << ": can't parse color " << colorname << endl;
- else if(!XAllocColor(Dpy, attributes.colormap, &color))
- cerr << APPNAME << ": can't allocate color " << colorname << endl;
- return color.pixel;
- }
- void Panel::Cursor(int visible) {
- const char* text;
- int xx, yy, y2, cheight;
- char* txth = "Wj"; // used to get cursor height
- switch(field) {
- case Get_Passwd:
- text = HiddenPasswdBuffer.c_str();
- xx = input_pass_x;
- yy = input_pass_y;
- break;
- case Get_Name:
- text = NameBuffer.c_str();
- xx = input_name_x;
- yy = input_name_y;
- break;
- }
- XGlyphInfo extents;
- XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);
- cheight = extents.height;
- y2 = yy - extents.y + extents.height;
- XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents);
- xx += extents.width;
- if(visible == SHOW) {
- XSetForeground(Dpy, TextGC,
- GetColor(cfg->getOption("input_color").c_str()));
- XDrawLine(Dpy, Win, TextGC,
- xx+1, yy-cheight,
- xx+1, y2);
- } else {
- XClearArea(Dpy, Win, xx+1, yy-cheight,
- 1, y2-(yy-cheight)+1, false);
- }
- }
- void Panel::EventHandler(const Panel::FieldType& curfield) {
- XEvent event;
- field=curfield;
- bool loop = true;
- OnExpose();
- while(loop) {
- XNextEvent(Dpy, &event);
- switch(event.type) {
- case Expose:
- OnExpose();
- break;
- case KeyPress:
- loop=OnKeyPress(event);
- break;
- }
- }
- return;
- }
- void Panel::OnExpose(void) {
- XftDraw *draw = XftDrawCreate(Dpy, Win,
- DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
- XClearWindow(Dpy, Win);
- if (input_pass_x != input_name_x || input_pass_y != input_name_y){
- SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,
- NameBuffer,
- &inputshadowcolor,
- inputShadowXOffset, inputShadowYOffset);
- SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,
- HiddenPasswdBuffer,
- &inputshadowcolor,
- inputShadowXOffset, inputShadowYOffset);
- } else { //single input mode
- switch(field) {
- case Get_Passwd:
- SlimDrawString8 (draw, &inputcolor, font,
- input_pass_x, input_pass_y,
- HiddenPasswdBuffer,
- &inputshadowcolor,
- inputShadowXOffset, inputShadowYOffset);
- break;
- case Get_Name:
- SlimDrawString8 (draw, &inputcolor, font,
- input_name_x, input_name_y,
- NameBuffer,
- &inputshadowcolor,
- inputShadowXOffset, inputShadowYOffset);
- break;
- }
- }
- XftDrawDestroy (draw);
- Cursor(SHOW);
- ShowText();
- }
- bool Panel::OnKeyPress(XEvent& event) {
- char ascii;
- KeySym keysym;
- XComposeStatus compstatus;
- int xx;
- int yy;
- string text;
- string formerString = "";
-
- XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);
- switch(keysym){
- case XK_F1:
- SwitchSession();
- return true;
- case XK_F11:
- // Take a screenshot
- system(cfg->getOption("screenshot_cmd").c_str());
- return true;
- case XK_Return:
- case XK_KP_Enter:
- if (field==Get_Name){
- // Don't allow an empty username
- if (NameBuffer.empty()) return true;
- if (NameBuffer==CONSOLE_STR){
- action = Console;
- } else if (NameBuffer==HALT_STR){
- action = Halt;
- } else if (NameBuffer==REBOOT_STR){
- action = Reboot;
- } else if (NameBuffer==SUSPEND_STR){
- action = Suspend;
- } else if (NameBuffer==EXIT_STR){
- action = Exit;
- } else{
- action = Login;
- }
- };
- return false;
- default:
- break;
- };
- Cursor(HIDE);
- switch(keysym){
- case XK_Delete:
- case XK_BackSpace:
- switch(field) {
- case GET_NAME:
- if (! NameBuffer.empty()){
- formerString=NameBuffer;
- NameBuffer.erase(--NameBuffer.end());
- };
- break;
- case GET_PASSWD:
- if (! PasswdBuffer.empty()){
- formerString=HiddenPasswdBuffer;
- PasswdBuffer.erase(--PasswdBuffer.end());
- HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end());
- };
- break;
- };
- break;
- case XK_w:
- case XK_u:
- if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
- switch(field) {
- case Get_Passwd:
- formerString = HiddenPasswdBuffer;
- HiddenPasswdBuffer.clear();
- PasswdBuffer.clear();
- break;
- case Get_Name:
- formerString = NameBuffer;
- NameBuffer.clear();
- break;
- };
- break;
- }
- // Deliberate fall-through
-
- default:
- if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){
- switch(field) {
- case GET_NAME:
- formerString=NameBuffer;
- if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){
- NameBuffer.append(&ascii,1);
- };
- break;
- case GET_PASSWD:
- formerString=HiddenPasswdBuffer;
- if (PasswdBuffer.length() < INPUT_MAXLENGTH_NAME-1){
- PasswdBuffer.append(&ascii,1);
- HiddenPasswdBuffer.append("*");
- };
- break;
- };
- };
- break;
- };
- XGlyphInfo extents;
- XftDraw *draw = XftDrawCreate(Dpy, Win,
- DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
- switch(field) {
- case Get_Name:
- text = NameBuffer;
- xx = input_name_x;
- yy = input_name_y;
- break;
- case Get_Passwd:
- text = HiddenPasswdBuffer;
- xx = input_pass_x;
- yy = input_pass_y;
- break;
- }
- if (!formerString.empty()){
- char* txth = "Wj"; // get proper maximum height ?
- XftTextExtents8(Dpy, font, reinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);
- int maxHeight = extents.height;
- XftTextExtents8(Dpy, font, reinterpret_cast<const XftChar8*>(formerString.c_str()),
- formerString.length(), &extents);
- int maxLength = extents.width;
- XClearArea(Dpy, Win, xx-3, yy-maxHeight-3,
- maxLength+6, maxHeight+6, false);
- }
- if (!text.empty()) {
- SlimDrawString8 (draw, &inputcolor, font, xx, yy,
- text,
- &inputshadowcolor,
- inputShadowXOffset, inputShadowYOffset);
- }
- XftDrawDestroy (draw);
- Cursor(SHOW);
- return true;
- }
- // Draw welcome and "enter username" message
- void Panel::ShowText(){
- string cfgX, cfgY;
- XGlyphInfo extents;
- bool singleInputMode =
- input_name_x == input_pass_x &&
- input_name_y == input_pass_y;
- XftDraw *draw = XftDrawCreate(Dpy, Win,
- DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
- /* welcome message */
- XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(),
- strlen(welcome_message.c_str()), &extents);
- cfgX = cfg->getOption("welcome_x");
- cfgY = cfg->getOption("welcome_y");
- int shadowXOffset =
- Cfg::string2int(cfg->getOption("welcome_shadow_xoffset").c_str());
- int shadowYOffset =
- Cfg::string2int(cfg->getOption("welcome_shadow_yoffset").c_str());
- welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
- welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
- if (welcome_x >= 0 && welcome_y >= 0) {
- SlimDrawString8 (draw, &welcomecolor, welcomefont,
- welcome_x, welcome_y,
- welcome_message,
- &welcomeshadowcolor, shadowXOffset, shadowYOffset);
- }
- /* Enter username-password message */
- string msg;
- if (!singleInputMode|| field == Get_Passwd ) {
- msg = cfg->getOption("password_msg");
- XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
- strlen(msg.c_str()), &extents);
- cfgX = cfg->getOption("password_x");
- cfgY = cfg->getOption("password_y");
- int shadowXOffset =
- Cfg::string2int(cfg->getOption("username_shadow_xoffset").c_str());
- int shadowYOffset =
- Cfg::string2int(cfg->getOption("username_shadow_yoffset").c_str());
- password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
- password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
- if (password_x >= 0 && password_y >= 0){
- SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y,
- msg, &entershadowcolor, shadowXOffset, shadowYOffset);
- }
- }
- if (!singleInputMode|| field == Get_Name ) {
- msg = cfg->getOption("username_msg");
- XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),
- strlen(msg.c_str()), &extents);
- cfgX = cfg->getOption("username_x");
- cfgY = cfg->getOption("username_y");
- int shadowXOffset =
- Cfg::string2int(cfg->getOption("username_shadow_xoffset").c_str());
- int shadowYOffset =
- Cfg::string2int(cfg->getOption("username_shadow_yoffset").c_str());
- username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);
- username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);
- if (username_x >= 0 && username_y >= 0){
- SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y,
- msg, &entershadowcolor, shadowXOffset, shadowYOffset);
- }
- }
- XftDrawDestroy(draw);
- }
- string Panel::getSession() {
- return session;
- }
- // choose next available session type
- void Panel::SwitchSession() {
- session = cfg->nextSession(session);
- if (session.size() > 0) {
- ShowSession();
- }
- }
- // Display session type on the screen
- void Panel::ShowSession() {
- XClearWindow(Dpy, Root);
- string currsession = "Session: " + session;
- XGlyphInfo extents;
- XftDraw *draw = XftDrawCreate(Dpy, Root,
- DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));
- XftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
- currsession.length(), &extents);
- int msg_x = Cfg::absolutepos("50%", XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);
- int msg_y = XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)) - extents.height -100;
- int shadowXOffset =
- Cfg::string2int(cfg->getOption("msg_shadow_xoffset").c_str());
- int shadowYOffset =
- Cfg::string2int(cfg->getOption("msg_shadow_yoffset").c_str());
- SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y,
- currsession,
- &msgshadowcolor,
- shadowXOffset, shadowYOffset);
- XFlush(Dpy);
- XftDrawDestroy(draw);
- }
- void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,
- int x, int y, const string& str,
- XftColor* shadowColor,
- int xOffset, int yOffset)
- {
- if (xOffset && yOffset) {
- XftDrawString8(d, shadowColor, font, x+xOffset, y+yOffset,
- reinterpret_cast<const FcChar8*>(str.c_str()), str.length());
- }
- XftDrawString8(d, color, font, x, y, reinterpret_cast<const FcChar8*>(str.c_str()), str.length());
- }
- Panel::ActionType Panel::getAction(void) const{
- return action;
- };
- void Panel::Reset(void){
- ResetName();
- ResetPasswd();
- };
- void Panel::ResetName(void){
- NameBuffer.clear();
- };
- void Panel::ResetPasswd(void){
- PasswdBuffer.clear();
- HiddenPasswdBuffer.clear();
- };
- void Panel::SetName(const string& name){
- NameBuffer=name;
- return;
- };
- const string& Panel::GetName(void) const{
- return NameBuffer;
- };
- const string& Panel::GetPasswd(void) const{
- return PasswdBuffer;
- };
|