Schlimm is an attempt to create a fork of the SLiM desktop manager.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1111 lines
37 KiB

/* 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 "Panel.h"
using namespace Schlimm;
Panel::Panel(
Display* dpy,
int scr,
Window root,
Schlimm::Config* config,
const std::string& themedir,
PanelType panel_mode
)
{
/* Set display */
this->display = dpy;
this->screen = scr;
this->root_window = root;
this->config = config;
mode = panel_mode;
session_name = "";
session_exec = "";
if (mode == Mode_Lock) {
this->window = root;
viewport = this->getPrimaryViewport();
}
/* Init GC */
XGCValues gcv;
unsigned long gcm;
gcm = GCForeground|GCBackground|GCGraphicsExposures;
gcv.foreground = this->getColor("black");
gcv.background = this->getColor("white");
gcv.graphics_exposures = False;
if (mode == Mode_Lock) {
this->text_gc = XCreateGC(this->display, this->window, gcm, &gcv);
} else {
this->text_gc = XCreateGC(this->display, this->root_window, gcm, &gcv);
}
if (mode == Mode_Lock) {
gcm = GCGraphicsExposures;
gcv.graphics_exposures = False;
this->win_gc = XCreateGC(this->display, this->window, gcm, &gcv);
if (this->win_gc < 0) {
Log::log("Failed to create pixmap!");
exit(ERR_EXIT);
}
}
font = XftFontOpenName(this->display, this->screen, this->config->getOption("input_font").c_str());
welcomefont = XftFontOpenName(this->display, this->screen, this->config->getOption("welcome_font").c_str());
introfont = XftFontOpenName(this->display, this->screen, this->config->getOption("intro_font").c_str());
enterfont = XftFontOpenName(this->display, this->screen, this->config->getOption("username_font").c_str());
msgfont = XftFontOpenName(this->display, this->screen, this->config->getOption("msg_font").c_str());
Visual* visual = DefaultVisual(this->display, this->screen);
Colormap colormap = DefaultColormap(this->display, this->screen);
/* NOTE: using XftColorAllocValue() would be a better solution. Lazy me. */
XftColorAllocName(this->display, visual, colormap, this->config->getOption("input_color").c_str(), &inputcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("input_shadow_color").c_str(), &inputshadowcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("welcome_color").c_str(), &welcomecolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("welcome_shadow_color").c_str(), &welcomeshadowcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("username_color").c_str(), &entercolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("username_shadow_color").c_str(), &entershadowcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("msg_color").c_str(), &msgcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("msg_shadow_color").c_str(), &msgshadowcolor);
XftColorAllocName(this->display, visual, colormap, this->config->getOption("intro_color").c_str(), &introcolor);
XftColorAllocName(this->display, visual, colormap,
this->config->getOption("session_color").c_str(), &sessioncolor);
XftColorAllocName(this->display, visual, colormap,
this->config->getOption("session_shadow_color").c_str(), &sessionshadowcolor);
/* Load properties from config / theme */
input_name_x = this->config->getIntOption("input_name_x");
input_name_y = this->config->getIntOption("input_name_y");
input_pass_x = this->config->getIntOption("input_pass_x");
input_pass_y = this->config->getIntOption("input_pass_y");
inputShadowXOffset = this->config->getIntOption("input_shadow_xoffset");
inputShadowYOffset = this->config->getIntOption("input_shadow_yoffset");
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 */
std::string panelpng = "";
panelpng = panelpng + themedir +"/panel.png";
image = new Schlimm::Image;
bool panel_image_loaded = image->Read(panelpng.c_str());
if (!panel_image_loaded) { /* try jpeg if png failed */
panelpng = themedir + "/panel.jpg";
panel_image_loaded = image->Read(panelpng.c_str());
if (!panel_image_loaded) {
Log::log(
fmt::format(
"Could not load the panel image file from directory {}!",
themedir
)
);
}
}
std::unique_ptr<Schlimm::Image> bg = std::make_unique<Schlimm::Image>();
if (bg == nullptr) {
Log::log(
"Error initialising image reading module!"
);
} else {
std::string bgstyle = this->config->getOption("background_style");
bool background_image_loaded = false;
if (bgstyle != "color") {
panelpng = themedir +"/background.png";
background_image_loaded = bg->Read(panelpng.c_str());
if (!background_image_loaded) { /* try jpeg if png failed */
panelpng = themedir + "/background.jpg";
background_image_loaded = bg->Read(panelpng.c_str());
if (!background_image_loaded) {
Log::log(
fmt::format(
"Could not load the background image file from directory '{}'!",
themedir
)
);
}
}
}
if (background_image_loaded) {
if (mode == Mode_Lock) {
if (bgstyle == "stretch") {
bg->Resize(viewport.width, viewport.height);
//bg->Resize(XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
// XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)));
} else if (bgstyle == "tile") {
bg->Tile(viewport.width, viewport.height);
} else if (bgstyle == "center") {
std::string hexvalue = this->config->getOption("background_color");
hexvalue = hexvalue.substr(1,6);
bg->Center(
viewport.width,
viewport.height,
hexvalue.c_str()
);
} else { // plain color or error
std::string hexvalue = this->config->getOption("background_color");
hexvalue = hexvalue.substr(1,6);
bg->Center(
viewport.width,
viewport.height,
hexvalue.c_str()
);
}
} else {
if (bgstyle == "stretch") {
bg->Resize(
XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
XHeightOfScreen(ScreenOfDisplay(this->display, this->screen))
);
} else if (bgstyle == "tile") {
bg->Tile(
XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
XHeightOfScreen(ScreenOfDisplay(this->display, this->screen))
);
} else if (bgstyle == "center") {
std::string hexvalue = this->config->getOption("background_color");
hexvalue = hexvalue.substr(1,6);
bg->Center(
XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)),
hexvalue.c_str()
);
} else { /* plain color or error */
std::string hexvalue = this->config->getOption("background_color");
hexvalue = hexvalue.substr(1,6);
bg->Center(
XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)),
hexvalue.c_str()
);
}
}
}
std::string cfgX = this->config->getOption("input_panel_x");
std::string cfgY = this->config->getOption("input_panel_y");
if (panel_image_loaded) {
if (mode == Mode_Lock) {
X = Schlimm::Config::absolutepos(cfgX, viewport.width, image->Width());
Y = Schlimm::Config::absolutepos(cfgY, viewport.height, image->Height());
input_name_x += X;
input_name_y += Y;
input_pass_x += X;
input_pass_y += Y;
} else {
X = Schlimm::Config::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), image->Width());
Y = Schlimm::Config::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), image->Height());
}
if (mode == Mode_Lock) {
/* Merge image into background without crop */
image->Merge_non_crop(bg.get(), X, Y);
this->panel_pixmap = image->createPixmap(this->display, this->screen, this->window);
} else {
/* Merge image into background */
image->Merge(bg.get(), X, Y);
this->panel_pixmap = image->createPixmap(this->display, this->screen, this->root_window);
}
}
}
/* Read (and substitute vars in) the welcome message */
welcome_message = this->config->getWelcomeMessage();
intro_message = this->config->getOption("intro_msg");
if (mode == Mode_Lock) {
this->setName(getenv("USER"));
field = Get_Passwd;
this->onExpose();
}
}
Panel::~Panel()
{
Visual* visual = DefaultVisual(this->display, this->screen);
Colormap colormap = DefaultColormap(this->display, this->screen);
XftColorFree(this->display, visual, colormap, &inputcolor);
XftColorFree(this->display, visual, colormap, &inputshadowcolor);
XftColorFree(this->display, visual, colormap, &welcomecolor);
XftColorFree(this->display, visual, colormap, &welcomeshadowcolor);
XftColorFree(this->display, visual, colormap, &entercolor);
XftColorFree(this->display, visual, colormap, &entershadowcolor);
XftColorFree(this->display, visual, colormap, &msgcolor);
XftColorFree(this->display, visual, colormap, &msgshadowcolor);
XftColorFree(this->display, visual, colormap, &introcolor);
XftColorFree(this->display, visual, colormap, &sessioncolor);
XftColorFree(this->display, visual, colormap, &sessionshadowcolor);
XFreeGC(this->display, this->text_gc);
XftFontClose(this->display, font);
XftFontClose(this->display, msgfont);
XftFontClose(this->display, introfont);
XftFontClose(this->display, welcomefont);
XftFontClose(this->display, enterfont);
if (mode == Mode_Lock) {
XFreeGC(this->display, this->win_gc);
}
delete image;
}
void Panel::openPanel()
{
if (image->imageLoaded()) {
/* Create window */
this->window = XCreateSimpleWindow(
this->display,
this->root_window,
X,
Y,
image->Width(),
image->Height(),
0,
this->getColor("white"),
this->getColor("white")
);
} else {
this->window = XCreateSimpleWindow(
this->display,
this->root_window,
X,
Y,
XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)),
XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)),
0,
this->getColor("white"),
this->getColor("white")
);
}
/* Events */
XSelectInput(this->display, this->window, ExposureMask | KeyPressMask);
/* Set background */
XSetWindowBackgroundPixmap(this->display, this->window, this->panel_pixmap);
/* Show window */
XMapWindow(this->display, this->window);
XMoveWindow(this->display, this->window, X, Y); /* override wm positioning (for tests) */
/* Grab keyboard */
XGrabKeyboard(this->display, this->window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
XFlush(this->display);
}
void Panel::closePanel()
{
XUngrabKeyboard(this->display, CurrentTime);
XUnmapWindow(this->display, this->window);
XDestroyWindow(this->display, this->window);
XFlush(this->display);
}
void Panel::clearPanel()
{
session_name = "";
session_exec = "";
this->reset();
XClearWindow(this->display, this->root_window);
XClearWindow(this->display, this->window);
Cursor(SHOW);
this->showText();
XFlush(this->display);
}
void Panel::wrongPassword(int timeout)
{
std::string message;
XGlyphInfo extents;
#if 0
if (CapsLockOn)
message = this->config->getOption("passwd_feedback_capslock");
else
#endif
message = this->config->getOption("passwd_feedback_msg");
XftDraw *draw = XftDrawCreate(
this->display,
this->window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen)
);
XftTextExtents8(
this->display,
msgfont,
reinterpret_cast<const XftChar8*>(message.c_str()),
message.length(),
&extents
);
std::string cfgX = this->config->getOption("passwd_feedback_x");
std::string cfgY = this->config->getOption("passwd_feedback_y");
int shadowXOffset = this->config->getIntOption("msg_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("msg_shadow_yoffset");
int msg_x = Schlimm::Config::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.width);
int msg_y = Schlimm::Config::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.height);
this->onExpose();
this->slimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
&msgshadowcolor, shadowXOffset, shadowYOffset);
if (this->config->getOption("bell") == "1")
XBell(this->display, 100);
XFlush(this->display);
sleep(timeout);
this->resetPasswd();
this->onExpose();
// The message should stay on the screen even after the password field is
// cleared, methinks. I don't like this solution, but it works.
this->slimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,
&msgshadowcolor, shadowXOffset, shadowYOffset);
XSync(this->display, True);
XftDrawDestroy(draw);
}
void Panel::message(const std::string& text)
{
std::string cfgX, cfgY;
XGlyphInfo extents;
XftDraw *draw;
if (mode == Mode_Lock)
draw = XftDrawCreate(this->display, this->window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
else
draw = XftDrawCreate(this->display, this->root_window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
XftTextExtents8(this->display, msgfont,
reinterpret_cast<const XftChar8*>(text.c_str()),
text.length(), &extents);
cfgX = this->config->getOption("msg_x");
cfgY = this->config->getOption("msg_y");
int shadowXOffset = this->config->getIntOption("msg_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("msg_shadow_yoffset");
int msg_x, msg_y;
if (mode == Mode_Lock) {
msg_x = Schlimm::Config::absolutepos(cfgX, viewport.width, extents.width);
msg_y = Schlimm::Config::absolutepos(cfgY, viewport.height, extents.height);
} else {
msg_x = Schlimm::Config::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.width);
msg_y = Schlimm::Config::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.height);
}
this->slimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,
text,
&msgshadowcolor,
shadowXOffset, shadowYOffset);
XFlush(this->display);
XftDrawDestroy(draw);
}
void Panel::error(const std::string& text)
{
this->closePanel();
this->message(text);
sleep(ERROR_DURATION);
this->openPanel();
this->clearPanel();
}
unsigned long Panel::getColor(const char* colorname)
{
XColor color;
XWindowAttributes attributes;
if (mode == Mode_Lock) {
XGetWindowAttributes(this->display, this->window, &attributes);
} else {
XGetWindowAttributes(this->display, this->root_window, &attributes);
}
color.pixel = 0;
if (!XParseColor(this->display, attributes.colormap, colorname, &color)) {
Log::log(std::string(APPNAME) + ": can't parse color " + colorname);
} else if(!XAllocColor(this->display, attributes.colormap, &color)) {
Log::log(std::string(APPNAME) + ": can't allocate color " + colorname);
}
return color.pixel;
}
void Panel::cursor(int visible)
{
const char* text = NULL;
int xx = 0, yy = 0, y2 = 0, cheight = 0;
const char* txth = "Wj"; /* used to get cursor height */
if (mode == Mode_Lock) {
text = HiddenPasswdBuffer.c_str();
xx = input_pass_x;
yy = input_pass_y;
} else {
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(this->display, font, (XftChar8*)txth, strlen(txth), &extents);
cheight = extents.height;
y2 = yy - extents.y + extents.height;
XftTextExtents8(this->display, font, (XftChar8*)text, strlen(text), &extents);
xx += extents.width;
if(visible == SHOW) {
if (mode == Mode_Lock) {
xx += viewport.x;
yy += viewport.y;
y2 += viewport.y;
}
XSetForeground(this->display, this->text_gc,
this->getColor(this->config->getOption("input_color").c_str()));
XDrawLine(this->display, this->window, this->text_gc,
xx+1, yy-cheight,
xx+1, y2);
} else {
if (mode == Mode_Lock)
this->applyBackground(Rectangle(xx+1, yy-cheight,
1, y2-(yy-cheight)+1));
else
XClearArea(this->display, this->window, xx+1, yy-cheight,
1, y2-(yy-cheight)+1, false);
}
}
void Panel::eventHandler(const Panel::FieldType& curfield)
{
XEvent event;
field = curfield;
bool loop = true;
if (mode == Mode_DM)
this->onExpose();
struct pollfd x11_pfd = {0};
x11_pfd.fd = ConnectionNumber(this->display);
x11_pfd.events = POLLIN;
while (loop) {
if (XPending(this->display) || poll(&x11_pfd, 1, -1) > 0) {
while(XPending(this->display)) {
XNextEvent(this->display, &event);
switch(event.type) {
case Expose:
this->onExpose();
break;
case KeyPress:
loop = this->onKeyPress(event);
break;
}
}
}
}
return;
}
void Panel::onExpose(void)
{
XftDraw *draw = XftDrawCreate(this->display, this->window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
if (mode == Mode_Lock)
this->applyBackground();
else
XClearWindow(this->display, this->window);
if (input_pass_x != input_name_x || input_pass_y != input_name_y){
this->slimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,
NameBuffer,
&inputshadowcolor,
inputShadowXOffset, inputShadowYOffset);
this->slimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,
HiddenPasswdBuffer,
&inputshadowcolor,
inputShadowXOffset, inputShadowYOffset);
} else { /*single input mode */
switch(field) {
case Get_Passwd:
this->slimDrawString8 (draw, &inputcolor, font,
input_pass_x, input_pass_y,
HiddenPasswdBuffer,
&inputshadowcolor,
inputShadowXOffset, inputShadowYOffset);
break;
case Get_Name:
this->slimDrawString8 (draw, &inputcolor, font,
input_name_x, input_name_y,
NameBuffer,
&inputshadowcolor,
inputShadowXOffset, inputShadowYOffset);
break;
}
}
XftDrawDestroy (draw);
Cursor(SHOW);
this->showText();
}
void Panel::eraseLastChar(std::string& formerString)
{
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;
}
}
}
bool Panel::onKeyPress(XEvent& event)
{
char ascii;
KeySym keysym;
XComposeStatus compstatus;
int xx = 0;
int yy = 0;
std::string text;
std::string formerString = "";
XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);
switch(keysym){
case XK_F1:
this->switchSession();
return true;
case XK_F11:
/* Take a screenshot */
system(this->config->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{
if (mode == Mode_DM)
action = Login;
else
action = Lock;
}
};
return false;
default:
break;
};
Cursor(HIDE);
switch(keysym){
case XK_Delete:
case XK_BackSpace:
this->eraseLastChar(formerString);
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;
}
case XK_h:
if (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {
this->eraseLastChar(formerString);
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_PASSWD-1){
PasswdBuffer.append(&ascii,1);
HiddenPasswdBuffer.append("*");
};
break;
};
}
else {
return true; //nodraw if notchange
};
break;
};
XGlyphInfo extents;
XftDraw *draw = XftDrawCreate(this->display, this->window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
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()){
const char* txth = "Wj"; /* get proper maximum height ? */
XftTextExtents8(this->display, font,
reinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);
int maxHeight = extents.height;
XftTextExtents8(this->display, font,
reinterpret_cast<const XftChar8*>(formerString.c_str()),
formerString.length(), &extents);
int maxLength = extents.width;
if (mode == Mode_Lock)
this->applyBackground(Rectangle(input_pass_x - 3,
input_pass_y - maxHeight - 3,
maxLength + 6, maxHeight + 6));
else
XClearArea(this->display, this->window, xx - 3, yy-maxHeight - 3,
maxLength + 6, maxHeight + 6, false);
}
if (!text.empty()) {
this->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()
{
std::string cfgX, cfgY;
XGlyphInfo extents;
bool singleInputMode =
input_name_x == input_pass_x &&
input_name_y == input_pass_y;
XftDraw *draw = XftDrawCreate(this->display, this->window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
/* welcome message */
XftTextExtents8(this->display, welcomefont, (XftChar8*)welcome_message.c_str(),
strlen(welcome_message.c_str()), &extents);
cfgX = this->config->getOption("welcome_x");
cfgY = this->config->getOption("welcome_y");
int shadowXOffset = this->config->getIntOption("welcome_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("welcome_shadow_yoffset");
if (image->imageLoaded()) {
welcome_x = Schlimm::Config::absolutepos(cfgX, image->Width(), extents.width);
welcome_y = Schlimm::Config::absolutepos(cfgY, image->Height(), extents.height);
} else {
//Use somewhere in the middle of the screen.
welcome_x = Schlimm::Config::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.width);
welcome_y = Schlimm::Config::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.height);
}
if (welcome_x >= 0 && welcome_y >= 0) {
this->slimDrawString8(
draw,
&welcomecolor,
welcomefont,
welcome_x,
welcome_y,
welcome_message,
&welcomeshadowcolor,
shadowXOffset,
shadowYOffset
);
}
/* Enter username-password message */
std::string msg;
if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) {
msg = this->config->getOption("password_msg");
XftTextExtents8(this->display, enterfont, (XftChar8*)msg.c_str(),
strlen(msg.c_str()), &extents);
cfgX = this->config->getOption("password_x");
cfgY = this->config->getOption("password_y");
int shadowXOffset = this->config->getIntOption("username_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("username_shadow_yoffset");
if (image->imageLoaded()) {
password_x = Schlimm::Config::absolutepos(cfgX, image->Width(), extents.width);
password_y = Schlimm::Config::absolutepos(cfgY, image->Height(), extents.height);
} else {
//Use somewhere in the middle of the screen.
password_x = Schlimm::Config::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.width);
password_y = Schlimm::Config::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.height);
}
if (password_x >= 0 && password_y >= 0){
this->slimDrawString8(
draw,
&entercolor,
enterfont,
password_x,
password_y,
msg,
&entershadowcolor,
shadowXOffset,
shadowYOffset
);
}
}
if (!singleInputMode || (field == Get_Name)) {
msg = this->config->getOption("username_msg");
XftTextExtents8(
this->display,
enterfont,
(XftChar8*)msg.c_str(),
strlen(msg.c_str()),
&extents
);
cfgX = this->config->getOption("username_x");
cfgY = this->config->getOption("username_y");
int shadowXOffset = this->config->getIntOption("username_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("username_shadow_yoffset");
if (image->imageLoaded()) {
username_x = Schlimm::Config::absolutepos(cfgX, image->Width(), extents.width);
username_y = Schlimm::Config::absolutepos(cfgY, image->Height(), extents.height);
} else {
username_x = Schlimm::Config::absolutepos(cfgX, viewport.width, extents.width);
username_y = Schlimm::Config::absolutepos(cfgY, viewport.height, extents.height);
}
if (username_x >= 0 && username_y >= 0){
this->slimDrawString8(
draw,
&entercolor,
enterfont,
username_x,
username_y,
msg,
&entershadowcolor,
shadowXOffset,
shadowYOffset
);
}
}
XftDrawDestroy(draw);
if (mode == Mode_Lock) {
// If only the password box is visible, draw the user name somewhere too
std::string user_msg = fmt::format("User: {}", this->getName());
int show_username = this->config->getIntOption("show_username");
if (singleInputMode && show_username) {
this->message(user_msg);
}
}
}
std::string Panel::getSession()
{
return session_exec;
}
/* choose next available session type */
void Panel::switchSession()
{
if (this->config->hasSessions()) {
std::pair<std::string, std::string> ses = this->config->nextSession();
session_name = ses.first;
session_exec = ses.second;
if (session_name.size() > 0) {
this->showSession();
}
}
}
/* Display session type on the screen */
void Panel::showSession()
{
std::string msg_x, msg_y;
XClearWindow(this->display, this->root_window);
std::string currsession = this->config->getOption("session_msg") + " " + session_name;
XGlyphInfo extents;
sessionfont = XftFontOpenName(this->display, this->screen, this->config->getOption("session_font").c_str());
XftDraw *draw = XftDrawCreate(this->display, this->root_window,
DefaultVisual(this->display, this->screen), DefaultColormap(this->display, this->screen));
XftTextExtents8(this->display, sessionfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),
currsession.length(), &extents);
msg_x = this->config->getOption("session_x");
msg_y = this->config->getOption("session_y");
int x = Schlimm::Config::absolutepos(msg_x, XWidthOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.width);
int y = Schlimm::Config::absolutepos(msg_y, XHeightOfScreen(ScreenOfDisplay(this->display, this->screen)), extents.height);
int shadowXOffset = this->config->getIntOption("session_shadow_xoffset");
int shadowYOffset = this->config->getIntOption("session_shadow_yoffset");
this->slimDrawString8(draw, &sessioncolor, sessionfont, x, y,
currsession,
&sessionshadowcolor,
shadowXOffset, shadowYOffset);
XFlush(this->display);
XftDrawDestroy(draw);
}
void Panel::slimDrawString8(
XftDraw *d,
XftColor *color,
XftFont *font,
int x,
int y,
const std::string& str,
XftColor* shadowColor,
int xOffset,
int yOffset
)
{
int calc_x = 0;
int calc_y = 0;
if (mode == Mode_Lock) {
calc_x = viewport.x;
calc_y = viewport.y;
}
if (xOffset && yOffset) {
XftDrawStringUtf8(d, shadowColor, font,
x + xOffset + calc_x,
y + yOffset + calc_y,
reinterpret_cast<const FcChar8*>(str.c_str()),
str.length());
}
XftDrawStringUtf8(d, color, font,
x + calc_x,
y + calc_y,
reinterpret_cast<const FcChar8*>(str.c_str()),
str.length());
}
Panel::ActionType Panel::getAction(void) const
{
return action;
}
void Panel::reset(void)
{
this->resetName();
this->resetPasswd();
}
void Panel::resetName(void)
{
NameBuffer.clear();
}
void Panel::resetPasswd(void)
{
PasswdBuffer.clear();
HiddenPasswdBuffer.clear();
}
void Panel::setName(const std::string& name)
{
NameBuffer=name;
if (mode == Mode_DM)
action = Login;
else
action = Lock;
}
const std::string& Panel::getName(void) const
{
return this->NameBuffer;
}
const std::string& Panel::getPasswd(void) const
{
return this->PasswdBuffer;
}
Rectangle Panel::getPrimaryViewport()
{
Rectangle fallback;
Rectangle result;
RROutput primary;
XRROutputInfo *primary_info;
XRRScreenResources *resources;
XRRCrtcInfo *crtc_info;
int crtc;
fallback.x = 0;
fallback.y = 0;
fallback.width = DisplayWidth(this->display, this->screen);
fallback.height = DisplayHeight(this->display, this->screen);
primary = XRRGetOutputPrimary(this->display, this->window);
if (!primary) {
return fallback;
}
resources = XRRGetScreenResources(this->display, this->window);
if (!resources)
return fallback;
primary_info = XRRGetOutputInfo(this->display, resources, primary);
if (!primary_info) {
XRRFreeScreenResources(resources);
return fallback;
}
// Fixes bug with multiple monitors. Just pick first monitor if
// XRRGetOutputInfo gives returns bad into for crtc.
if (primary_info->crtc < 1) {
if (primary_info->ncrtc > 0) {
crtc = primary_info->crtcs[0];
} else {
Log::log("Cannot get crtc from xrandr!");
exit(EXIT_FAILURE);
}
} else {
crtc = primary_info->crtc;
}
crtc_info = XRRGetCrtcInfo(this->display, resources, crtc);
if (!crtc_info) {
XRRFreeOutputInfo(primary_info);
XRRFreeScreenResources(resources);
return fallback;
}
result.x = crtc_info->x;
result.y = crtc_info->y;
result.width = crtc_info->width;
result.height = crtc_info->height;
XRRFreeCrtcInfo(crtc_info);
XRRFreeOutputInfo(primary_info);
XRRFreeScreenResources(resources);
return result;
}
void Panel::applyBackground(Rectangle rect)
{
int ret = 0;
if (rect.is_empty()) {
rect.x = 0;
rect.y = 0;
rect.width = viewport.width;
rect.height = viewport.height;
}
ret = XCopyArea(this->display, this->panel_pixmap, this->window, this->win_gc,
rect.x, rect.y, rect.width, rect.height,
viewport.x + rect.x, viewport.y + rect.y);
if (!ret) {
Log::log("Failed to put pixmap on the screen!");
}
}