421 lines
13 KiB
C++
421 lines
13 KiB
C++
#ifdef __cplusplus
|
|
#include <cstdlib>
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef __APPLE__
|
|
#include <SDL/SDL.h>
|
|
#else
|
|
#include "SDL.h"
|
|
#endif
|
|
#include "SDL_ttf.h"
|
|
#include "SDL_syswm.h"
|
|
#include "SDL_gfxPrimitives.h"
|
|
#include <sys/time.h>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <X11/Xlib.h>
|
|
#include <signal.h>
|
|
using namespace std;
|
|
int past_m=0;
|
|
|
|
bool twentyfourh = true;
|
|
bool fullscreen = false;
|
|
|
|
SDL_Surface *screen;
|
|
|
|
|
|
TTF_Font *FONT_TIME = NULL;
|
|
TTF_Font *FONT_MODE = NULL;
|
|
SDL_Color FONT_COLOR_WHITE = {176,176,176};
|
|
|
|
SDL_Rect hourBackground;
|
|
SDL_Rect minBackground;
|
|
int spacing = 0;
|
|
|
|
int customHeight = 0;
|
|
int customWidth = 0;
|
|
int screenWidth = 0;
|
|
int screenHeight = 0;
|
|
const int DEFAULT_WIDTH = 640;
|
|
const int DEFAULT_HEIGHT = 480;
|
|
|
|
const char* FONT_FILE_BOLD = "/usr/share/fonts/truetype/droid/DroidSans-Bold.ttf";
|
|
const char* FONT_FILE_FALLBACK = "/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf";
|
|
const char* FONT_CUSTOM_FILE = "";
|
|
|
|
const Uint32 COLOR_FONT_RGB = 0xb7b7b7;
|
|
const Uint32 COLOR_BACKGROUND_RGB = 0x0a0a0a;
|
|
|
|
Uint32 COLOR_FONT;
|
|
Uint32 COLOR_BACKGROUND;
|
|
|
|
|
|
void checkTime(struct tm **time_i, Uint32 *ms_to_next_minute) {
|
|
timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
*time_i = localtime(&tv.tv_sec);
|
|
|
|
Uint32 seconds_to_next_minute = 60 - (*time_i)->tm_sec;
|
|
*ms_to_next_minute = seconds_to_next_minute*1000 - tv.tv_usec/1000;
|
|
}
|
|
|
|
Uint32 checkEmit(Uint32 interval, void *param) {
|
|
struct tm * time_i;
|
|
Uint32 ms_to_next_minute;
|
|
|
|
checkTime(&time_i, &ms_to_next_minute);
|
|
|
|
if ( time_i->tm_min != past_m) {
|
|
SDL_Event e;
|
|
e.type = SDL_USEREVENT;
|
|
e.user.code = 0;
|
|
e.user.data1 = NULL;
|
|
e.user.data2 = NULL;
|
|
SDL_PushEvent(&e);
|
|
#ifdef DEBUG
|
|
printf("Time is: %d : %d\n", time_i->tm_hour, time_i->tm_min);
|
|
#endif
|
|
past_m = time_i->tm_min;
|
|
}
|
|
|
|
// Don't wake up until the next minute.
|
|
interval = ms_to_next_minute;
|
|
// Make sure interval is positive.
|
|
// Should only matter for leap seconds.
|
|
if ( interval <= 0 ) {
|
|
interval = 500;
|
|
}
|
|
return (interval);
|
|
}
|
|
int initSDL() {
|
|
if ( SDL_Init( SDL_INIT_VIDEO|SDL_INIT_TIMER ) < 0 ) {
|
|
printf( "Unable to init SDL: %s\n", SDL_GetError() );
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Uint32 mapRGB24(const SDL_PixelFormat* format, Uint32 rgb) {
|
|
return SDL_MapRGB(format,
|
|
rgb >> 16,
|
|
(rgb >> 8) & 0xff,
|
|
rgb & 0xff);
|
|
}
|
|
|
|
int initResources() {
|
|
try {
|
|
screen = SDL_SetVideoMode(0,0,32, SDL_FULLSCREEN);
|
|
screenHeight = screen->h;
|
|
screenWidth = screen->w;
|
|
#ifdef DEBUG
|
|
printf("Full Screen Resolution : %dx%d\n", screenWidth, screenHeight);
|
|
#endif
|
|
if (fullscreen) {
|
|
customHeight = screenHeight;
|
|
customWidth = screenWidth;
|
|
}
|
|
if (strcmp("", FONT_CUSTOM_FILE) == 0) {
|
|
FONT_TIME = TTF_OpenFont(FONT_FILE_BOLD, customHeight / 2);
|
|
FONT_MODE = TTF_OpenFont(FONT_FILE_BOLD, customHeight/ 15);
|
|
} else {
|
|
FONT_TIME = TTF_OpenFont(FONT_CUSTOM_FILE, customHeight / 2);
|
|
FONT_TIME = TTF_OpenFont(FONT_CUSTOM_FILE, customHeight / 15);
|
|
}
|
|
|
|
if (!screen)
|
|
throw 2;
|
|
if (!FONT_TIME)
|
|
throw 1;
|
|
} catch (int param) {
|
|
if (param == 1)
|
|
printf("TTF_OpenFont: %s\n", TTF_GetError());
|
|
else if (param == 2)
|
|
printf("Couldn't initialize video mode to check native, fullscreen resolution.\n");
|
|
|
|
return param;
|
|
}
|
|
|
|
// Get colors in proper format.
|
|
COLOR_FONT = mapRGB24(screen->format, COLOR_FONT_RGB);
|
|
COLOR_BACKGROUND = mapRGB24(screen->format, COLOR_BACKGROUND_RGB);
|
|
|
|
/* CALCULATE BACKGROUND COORDINATES */
|
|
hourBackground.y = 0.2 * customHeight;
|
|
hourBackground.x = 0.5 * (customWidth - ((0.031)*customWidth) - (1.2 * customHeight));
|
|
hourBackground.w = customHeight * 0.6;
|
|
hourBackground.h = hourBackground.w;
|
|
#ifdef DEBUG
|
|
printf(" Hour x coordinate %d\n Hour y coordinate %d\n", hourBackground.y, hourBackground.x);
|
|
#endif
|
|
spacing = 0.031 * customWidth;
|
|
minBackground.x = hourBackground.x + (0.6*customHeight) + spacing;
|
|
minBackground.y = hourBackground.y;
|
|
minBackground.h = hourBackground.h;
|
|
minBackground.w = hourBackground.w;
|
|
#ifdef DEBUG
|
|
printf (" Minute x coordinate %d\n Minute y coordinate %d\n", minBackground.x, minBackground.y);
|
|
#endif
|
|
SDL_AddTimer(500, checkEmit, NULL);
|
|
return 0;
|
|
}
|
|
|
|
void set_pixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {
|
|
Uint8 *target_pixel = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
|
|
*(Uint32 *)target_pixel = pixel;
|
|
|
|
}
|
|
|
|
void fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel) {
|
|
static const int BPP = 4;
|
|
double r = (double)radius;
|
|
for (double dy = 1; dy <= r; dy += 1.0) {
|
|
double dx = floor(sqrt((2.0 * r * dy) - (dy * dy)));
|
|
int x = cx - dx;
|
|
Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP;
|
|
Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP;
|
|
|
|
for (; x <= cx + dx; x++) {
|
|
*(Uint32 *)target_pixel_a = pixel;
|
|
*(Uint32 *)target_pixel_b = pixel;
|
|
target_pixel_a += BPP;
|
|
target_pixel_b += BPP;
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawRoundedBackground(SDL_Surface * surface, SDL_Rect * coordinates) {
|
|
int backgroundSize = customHeight * 0.6;
|
|
int radius = 10;
|
|
#ifdef DEBUG
|
|
printf("Background size %d\n", backgroundSize);
|
|
#endif
|
|
for (int i=0; i<backgroundSize-radius; i++) {
|
|
for (int j=0; j<backgroundSize-radius; j++) {
|
|
fill_circle(surface, coordinates->x + j, coordinates->y + i, radius, COLOR_BACKGROUND);
|
|
}
|
|
}
|
|
}
|
|
|
|
SDL_Rect getCoordinates(SDL_Rect * background, SDL_Surface * foreground) {
|
|
SDL_Rect cord;
|
|
int dx = (background->w - foreground->w) * 0.5;
|
|
cord.x = background->x + dx;
|
|
int dy = (background->h - foreground->h) * 0.5;
|
|
cord.y = background->y + dy;
|
|
#ifdef DEBUG
|
|
printf("dx = %d : dy = %d\n", dx, dy);
|
|
printf("Text Coordinates x %d : y %d\n", cord.x, cord.y);
|
|
#endif
|
|
return cord;
|
|
}
|
|
|
|
void drawAMPM(SDL_Surface * surface, tm * _time) {
|
|
SDL_Rect cords;
|
|
cords.x = (hourBackground.h * 0.024) + hourBackground.x;
|
|
cords.y = (hourBackground.h * 0.071) + hourBackground.y;
|
|
#ifdef DEBUG
|
|
printf("AM/PM position\n\tx %d\n\ty %d\n", cords.x, cords.y);
|
|
#endif
|
|
char mode[3];
|
|
strftime(mode, 3, "%p", _time);
|
|
SDL_Surface *AMPM = TTF_RenderText_Blended(FONT_MODE, (const char *)mode, FONT_COLOR_WHITE);
|
|
SDL_BlitSurface(AMPM, 0, surface, &cords);
|
|
SDL_Flip(surface);
|
|
}
|
|
|
|
void drawTime(SDL_Surface *surface, tm * _time) {
|
|
try {
|
|
char hour[3];
|
|
if (twentyfourh)
|
|
strftime(hour, 3, "%H", _time);
|
|
else
|
|
strftime(hour, 3, "%I", _time);
|
|
char minutes[3];
|
|
strftime(minutes, 3, "%M", _time);
|
|
int h = atoi(hour);
|
|
#ifdef DEBUG
|
|
printf("Current time is %s : %s\n stripped hour ? %d\n", hour, minutes,h);
|
|
#endif
|
|
SDL_Rect coordinates;
|
|
SDL_Surface *text = TTF_RenderText_Blended(FONT_TIME, hour, FONT_COLOR_WHITE);
|
|
coordinates = getCoordinates(&hourBackground, text);
|
|
SDL_BlitSurface(text, 0, screen, &coordinates);
|
|
text = TTF_RenderText_Blended(FONT_TIME, (const char *) minutes, FONT_COLOR_WHITE);
|
|
coordinates = getCoordinates(&minBackground, text);
|
|
SDL_BlitSurface(text, 0, screen, &coordinates);
|
|
SDL_Flip(surface);
|
|
} catch (...) {
|
|
printf ("Problem drawing time");
|
|
}
|
|
}
|
|
|
|
void drawAll(void) {
|
|
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
time_t rawTime;
|
|
struct tm * _time;
|
|
time(&rawTime);
|
|
_time = localtime(&rawTime);
|
|
drawRoundedBackground(screen, &hourBackground);
|
|
drawRoundedBackground(screen, &minBackground);
|
|
drawTime(screen, _time);
|
|
if (!twentyfourh)
|
|
drawAMPM(screen, _time);
|
|
}
|
|
|
|
void exitImmediately(int sig) {
|
|
exit(0);
|
|
}
|
|
|
|
int main (int argc, char** argv ) {
|
|
signal(SIGINT, exitImmediately);
|
|
signal(SIGTERM, exitImmediately);
|
|
|
|
char *wid_env;
|
|
static char sdlwid[100];
|
|
Uint32 wid = 0;
|
|
Display *display;
|
|
XWindowAttributes windowAttributes;
|
|
windowAttributes.height = 0;
|
|
windowAttributes.width =0;
|
|
|
|
/* If no window argument, check environment */
|
|
if (wid == 0) {
|
|
if ((wid_env = getenv("XSCREENSAVER_WINDOW")) != NULL ) {
|
|
wid = strtol(wid_env, (char **) NULL, 0); /* Base 0 autodetects hex/dec */
|
|
}
|
|
}
|
|
|
|
/* Get win attrs if we've been given a window, otherwise we'll use our own */
|
|
if (wid != 0 ) {
|
|
if ((display = XOpenDisplay(NULL)) != NULL) { /* Use the default display */
|
|
XGetWindowAttributes(display, (Window) wid, &windowAttributes);
|
|
XCloseDisplay(display);
|
|
snprintf(sdlwid, 100, "SDL_WINDOWID=0x%X", wid);
|
|
putenv(sdlwid); /* Tell SDL to use this window */
|
|
}
|
|
}
|
|
|
|
for(int i=1; i<argc; i++) {
|
|
if(strcmp("--help",argv[i])==0 || strcmp("-h", argv[i]) == 0) {
|
|
printf("Usage: [OPTION...]\nOptions:\n");
|
|
printf(" --help\t\t\t\tDisplay this\n");
|
|
printf(" -root,--fullscreen,--root\tFullscreen\n");
|
|
printf(" -ampm, --ampm\t\t\tTurn off 24 h system and use 12 h system instead\n");
|
|
printf(" -w\t\t\t\tCustom Width\n");
|
|
printf(" -h\t\t\t\tCustom Height\n");
|
|
printf(" -r, --resolution\t\tCustom resolution in a format [Width]x[Height]\n");
|
|
printf(" -f, --font\t\t\tPath to custom file font. Has to be Truetype font.");
|
|
return 0;
|
|
} else if (strcmp("-root",argv[i]) == 0 || strcmp("--root", argv[i]) == 0 || strcmp("--fullscreen", argv[i]) == 0) {
|
|
fullscreen=true;
|
|
} else if (strcmp("-ampm",argv[i]) == 0 || strcmp("--ampm", argv[i]) == 0) {
|
|
twentyfourh=false;
|
|
} else if (strcmp("-r", argv[i]) == 0 || strcmp("--resolution", argv[i]) == 0) {
|
|
char* resolution;
|
|
resolution = argv[i+1];
|
|
char * value;
|
|
value = strtok(resolution,"x");
|
|
int i = atoi(value);
|
|
#ifdef DEBUG
|
|
printf("Value : %d\n", i );
|
|
#endif
|
|
value = strtok(NULL, "x");
|
|
i = atoi(value);
|
|
#ifdef DEBUG
|
|
printf("Value : %d\n", i );
|
|
#endif
|
|
} else if (strcmp("-w", argv[i]) == 0) {
|
|
customWidth = atoi(argv[i+1]);
|
|
#ifdef DEBUG
|
|
printf ("Width : %d\n", customWidth);
|
|
#endif
|
|
} else if (strcmp("-h", argv[i]) == 0) {
|
|
customHeight = atoi(argv[i+1]);
|
|
#ifdef DEBUG
|
|
printf ("Height: %d\n", customHeight);
|
|
#endif
|
|
} else if (strcmp("-f", argv[i]) == 0 || strcmp("--font", argv[i]) == 0) {
|
|
FONT_CUSTOM_FILE = argv[i+1];
|
|
#ifdef DEBUG
|
|
printf("Custom font:%s", FONT_CUSTOM_FILE);
|
|
#endif
|
|
} else {
|
|
printf("Invalid option -- %s\n", argv[i]);
|
|
printf("Try --help for more information.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
int width = DEFAULT_WIDTH;
|
|
int height = DEFAULT_HEIGHT;
|
|
if (customHeight > 0) {
|
|
height = customHeight;
|
|
width = customWidth;
|
|
} else {
|
|
customHeight = DEFAULT_HEIGHT;
|
|
customWidth = DEFAULT_WIDTH;
|
|
}
|
|
|
|
initSDL();
|
|
TTF_Init();
|
|
initResources();
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
atexit(SDL_Quit);
|
|
atexit(TTF_Quit);
|
|
|
|
try {
|
|
if(fullscreen) {
|
|
screen = SDL_SetVideoMode(windowAttributes.width, windowAttributes.height,32,SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN);
|
|
} else {
|
|
screen = SDL_SetVideoMode(width, height, 32,SDL_HWSURFACE|SDL_DOUBLEBUF);
|
|
}
|
|
if (!screen) {
|
|
throw 2;
|
|
}
|
|
} catch (int param) {
|
|
if (param == 2)
|
|
printf("Unable to set video mode: %s\n", SDL_GetError());
|
|
return 2;
|
|
}
|
|
|
|
// Initial draw.
|
|
drawAll();
|
|
bool done = false;
|
|
while (!done) {
|
|
SDL_Event event;
|
|
while(SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_USEREVENT:
|
|
drawAll();
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
if (event.key.keysym.sym == SDLK_ESCAPE)
|
|
done = true;
|
|
break;
|
|
case SDL_QUIT:
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct tm * time_i;
|
|
Uint32 ms_to_next_minute;
|
|
|
|
checkTime(&time_i, &ms_to_next_minute);
|
|
if(ms_to_next_minute > 100) {
|
|
// Wait a bit less to make sure event fires at the right time.
|
|
SDL_Delay(ms_to_next_minute - 100);
|
|
} else {
|
|
SDL_Delay(30);
|
|
}
|
|
}
|
|
SDL_FreeSurface(screen);
|
|
TTF_CloseFont(FONT_TIME);
|
|
TTF_CloseFont(FONT_MODE);
|
|
#ifdef DEBUG
|
|
printf("Exited cleanly\n");
|
|
#endif
|
|
return 0;
|
|
}
|