I compiled the fixed sClockx.c code . Runs but can't be shutdown easily. Needed to pkill sClockx
which worked.
Simple Clock
Moderator: Forum moderators
- rockedge
- Site Admin
- Posts: 6561
- Joined: Mon Dec 02, 2019 1:38 am
- Location: Connecticut,U.S.A.
- Has thanked: 2770 times
- Been thanked: 2646 times
- Contact:
Re: Simple Clock
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
rockedge wrote: Thu Jun 30, 2022 2:06 amI compiled the fixed sClockx.c code . Runs but can't be shutdown easily. Needed to
pkill sClockx
which worked.Screenshot(21).jpg
Here it shuts down when right clicked.
Did the left click change the clock?
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
Re: Simple Clock
Tried it on Fossapup. Occasionally it reacts on mouse but most often it doesn't. I don't know c and simply removed ret > 0 because it's almost always 0. It works now but maybe I messed up something else that way.
Code: Select all
if (XPending(disp)) {
XNextEvent(disp, &ev);
if (XFilterEvent(&ev, w))
continue;
else {
...
}
}
- rockedge
- Site Admin
- Posts: 6561
- Joined: Mon Dec 02, 2019 1:38 am
- Location: Connecticut,U.S.A.
- Has thanked: 2770 times
- Been thanked: 2646 times
- Contact:
Re: Simple Clock
@misko_2083 No reactions from mouse clicks left or right. Pressing and holding the Alt
key I can move it with the mouse
UPDATE: I compiled this version from misko_2083 in KLV-Airedale and this sClockx will shutdown on a right mouse click and changes format and color on a right click
sClockx.c
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
/* gcc sclockx.c -o sclockx $(pkg-config --cflags --libs cairo-xlib-xrender x11) */
void draw(cairo_t *g, char *date);
int main (int argc, char *argv[]) {
Display *disp = XOpenDisplay(NULL);
if(disp == NULL) {
printf("Display open failed.\n");
return 1;
}
cairo_t *g, *bg;
cairo_surface_t *ximg,*img;
int s;
img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,180,26);
bg = cairo_create(img);
s = DefaultScreen(disp);
XVisualInfo vinfo;
XMatchVisualInfo(disp, DefaultScreen(disp), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.override_redirect = False;
attr.event_mask = ExposureMask | KeyPressMask |
VisibilityChangeMask | ButtonPressMask;
attr.colormap = XCreateColormap(disp, DefaultRootWindow(disp), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
int w = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, 180, 26, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWEventMask | CWColormap | CWBorderPixel | CWBackPixel , &attr);
XStoreName(disp, w, "sclockx");
XSelectInput(disp, w,
ExposureMask | KeyPressMask | ClientMessage |
ButtonPressMask | ButtonReleaseMask);
XSizeHints sh;
sh.width = sh.min_width = 150;
sh.height = sh.min_height = 24;
sh.max_width = 220;
sh.max_height = 40;
sh.win_gravity = 0;
sh.flags = PSize | PMinSize | PMaxSize | PWinGravity;
XSetWMNormalHints(disp, w, &sh);
Atom motif_hints;
long hints[5] = {2, 0, 0, 0, 0};
motif_hints = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
XChangeProperty(disp, w, motif_hints, motif_hints, 32, PropModeReplace, (unsigned char *)&hints, 5);
Atom window_state = XInternAtom(disp, "_NET_WM_STATE", False);
long wmStateBelow = XInternAtom(disp, "_NET_WM_STATE_BELOW", False);
long wmStateSticky = XInternAtom(disp, "_NET_WM_STATE_STICKY", False);
long wmStateSkipTaskbar = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
long wmStateSkipPager = XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeReplace, (unsigned char *) &wmStateBelow, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSticky, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSkipTaskbar, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSkipPager, 1);
XFlush(disp);
XMapWindow(disp,w);
Atom wm_delete_window = XInternAtom(disp,"WM_DELETE_WINDOW",False);
XSetWMProtocols(disp,w,&wm_delete_window,1);
ximg = cairo_xlib_surface_create(disp,w,vinfo.visual,180,26);
cairo_xlib_surface_set_size(ximg,180,26);
g = cairo_create(ximg);
cairo_set_source_surface(g,img,0,0);
int x11_fd;
fd_set in_fds;
int nfds = x11_fd + 1;
struct timeval tv;
XEvent ev;
x11_fd = ConnectionNumber(disp);
static char *date = "%r";
for(;;) {
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);
// Set timer to one second
tv.tv_usec = 0;
tv.tv_sec = 1;
// Wait for X Event or a Timer
int ret;
if (!XPending(disp))
ret = select(nfds, &in_fds, NULL, NULL, &tv);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
goto shutdown;
if (ret == 0)
draw(g, date);
if (XPending(disp)) {
XNextEvent(disp, &ev);
if (XFilterEvent(&ev, w))
continue;
if (ret > 0) {
switch (ev.type) {
case ClientMessage:
if (ev.xclient.data.l[0] == wm_delete_window)
goto shutdown;
case ButtonPress:
switch(ev.xbutton.button){
case Button1:
if (date == "%r")
date = "%R:%S";
else if (date == "%R:%S")
date = "%a %d %b";
else if (date == "%a %d %b")
date = " %Y";
else
date = "%r";
continue;
case Button3:
goto shutdown;
}
default:
break;
}
}
else if (ret == 0)
draw(g, date);
else
printf("An error occured!\n");
}
}
shutdown: printf("Exit\n");
cairo_destroy(g);
cairo_surface_destroy(ximg);
cairo_destroy(bg);
cairo_surface_destroy(img);
XDestroyWindow(disp,w);
XCloseDisplay(disp);
return 1;
}
void draw(cairo_t *g, char *date) {
char buffer[64];
time_t timer;
struct tm* tm_info;
time (&timer);
tm_info = localtime (&timer);
strftime (buffer, 64, date, tm_info);
cairo_save (g);
cairo_set_source_rgba (g,0,0,0,1);
cairo_set_operator (g, CAIRO_OPERATOR_CLEAR);
cairo_paint (g);
cairo_restore (g);
cairo_set_operator (g, CAIRO_OPERATOR_OVER);
cairo_save (g);
if (date == "%r")
cairo_set_source_rgb (g, 0.0, 1.0, 0.0);
else if (date == "%R:%S")
cairo_set_source_rgb (g, 1.0, 0.0, 0.0);
else if (date == "%a %d %b")
cairo_set_source_rgb (g, 1.0, 1.0, 1.0);
else
cairo_set_source_rgb (g, 0.9, 0.7, 0.0);
cairo_select_font_face(g,"Sans",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(g,24);
cairo_move_to (g, 0.0, 20.0);
cairo_show_text(g,buffer);
cairo_restore (g);
cairo_paint (g);
}
On the KLV-Airedale attempted to restart this sClockx and it now goes straight to Exit when checked on the command line
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
Burunduk wrote: Thu Jun 30, 2022 6:30 pmTried it on Fossapup. Occasionally it reacts on mouse but most often it doesn't. I don't know c and simply removed ret > 0 because it's almost always 0. It works now but maybe I messed up something else that way.
Code: Select all
if (XPending(disp)) { XNextEvent(disp, &ev); if (XFilterEvent(&ev, w)) continue; else { ... } }
Thank for the input. That's it, it changes to 1only after click.
Everything works for me here for all the versions.
Might as well call draw on click to change it instantly.
Code: Select all
...
else
date = "%r";
draw(g, date);
continue;
case Button3:
goto shutdown;
...
The full code. I hope it works for everyone.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
/* gcc sclockx.c -o sclockx $(pkg-config --cflags --libs cairo-xlib-xrender x11) */
void draw(cairo_t *g, char *date);
int main (int argc, char *argv[]) {
Display *disp = XOpenDisplay(NULL);
if(disp == NULL) {
printf("Display open failed.\n");
return 1;
}
cairo_t *g, *bg;
cairo_surface_t *ximg,*img;
int s;
img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,180,26);
bg = cairo_create(img);
XVisualInfo vinfo;
const char depths[] = { 32, 24, 8, 4, 2, 1, 0 };
for (int i = 0; depths[i]; i++) {
XMatchVisualInfo(disp, DefaultScreen(disp), 32, TrueColor, &vinfo);
if (vinfo.visual)
break;
}
XSetWindowAttributes attr;
attr.override_redirect = False;
attr.event_mask = ExposureMask | KeyPressMask |
VisibilityChangeMask | ButtonPressMask;
attr.colormap = XCreateColormap(disp, DefaultRootWindow(disp), vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
int w = XCreateWindow(disp, DefaultRootWindow(disp), 0, 0, 180, 26, 0,
vinfo.depth, InputOutput, vinfo.visual,
CWEventMask | CWColormap | CWBorderPixel | CWBackPixel , &attr);
XStoreName(disp, w, "sclockx");
XSelectInput(disp, w,
ExposureMask | KeyPressMask | ClientMessage |
ButtonPressMask | ButtonReleaseMask);
XSizeHints sh;
sh.width = sh.min_width = 150;
sh.height = sh.min_height = 24;
sh.max_width = 220;
sh.max_height = 40;
sh.win_gravity = 0;
sh.flags = PSize | PMinSize | PMaxSize | PWinGravity;
XSetWMNormalHints(disp, w, &sh);
Atom motif_hints;
long hints[5] = {2, 0, 0, 0, 0};
motif_hints = XInternAtom(disp, "_MOTIF_WM_HINTS", False);
XChangeProperty(disp, w, motif_hints, motif_hints, 32, PropModeReplace, (unsigned char *)&hints, 5);
Atom window_state = XInternAtom(disp, "_NET_WM_STATE", False);
long wmStateBelow = XInternAtom(disp, "_NET_WM_STATE_BELOW", False);
long wmStateSticky = XInternAtom(disp, "_NET_WM_STATE_STICKY", False);
long wmStateSkipTaskbar = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
long wmStateSkipPager = XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeReplace, (unsigned char *) &wmStateBelow, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSticky, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSkipTaskbar, 1);
XChangeProperty(disp, w, window_state, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmStateSkipPager, 1);
XFlush(disp);
XMapWindow(disp,w);
Atom wm_delete_window = XInternAtom(disp,"WM_DELETE_WINDOW",False);
XSetWMProtocols(disp,w,&wm_delete_window,1);
ximg = cairo_xlib_surface_create(disp,w,vinfo.visual,180,26);
cairo_xlib_surface_set_size(ximg,180,26);
g = cairo_create(ximg);
cairo_set_source_surface(g,img,0,0);
int x11_fd;
fd_set in_fds;
int nfds = x11_fd + 1;
struct timeval tv;
XEvent ev;
x11_fd = ConnectionNumber(disp);
static char *date = "%r";
for(;;) {
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);
// Set timer to one second
tv.tv_usec = 0;
tv.tv_sec = 1;
// Wait for X Event or a Timer
int ret;
if (!XPending(disp))
ret = select(nfds, &in_fds, NULL, NULL, &tv);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
goto shutdown;
if (ret == 0)
draw(g, date);
if (XPending(disp)) {
XNextEvent(disp, &ev);
if (XFilterEvent(&ev, w))
continue;
switch (ev.type) {
case ClientMessage:
if (ev.xclient.data.l[0] == wm_delete_window)
goto shutdown;
case ButtonPress:
switch(ev.xbutton.button){
case Button1:
if (date == "%r")
date = "%R:%S";
else if (date == "%R:%S")
date = "%a %d %b";
else if (date == "%a %d %b")
date = " %Y";
else
date = "%r";
draw(g, date);
continue;
case Button3:
goto shutdown;
default:
break;
}
}
}
if (ret > 1)
printf("An error occured!\n");
}
shutdown: printf("Exit\n");
cairo_destroy(g);
cairo_surface_destroy(ximg);
cairo_destroy(bg);
cairo_surface_destroy(img);
XDestroyWindow(disp,w);
XCloseDisplay(disp);
return 0;
}
void draw(cairo_t *g, char *date) {
char buffer[64];
time_t timer;
struct tm* tm_info;
time (&timer);
tm_info = localtime (&timer);
strftime (buffer, 64, date, tm_info);
cairo_save (g);
cairo_set_source_rgba (g,0,0,0,1);
cairo_set_operator (g, CAIRO_OPERATOR_CLEAR);
cairo_paint (g);
cairo_restore (g);
cairo_set_operator (g, CAIRO_OPERATOR_OVER);
cairo_save (g);
if (date == "%r")
cairo_set_source_rgb (g, 0.0, 1.0, 0.0);
else if (date == "%R:%S")
cairo_set_source_rgb (g, 1.0, 0.0, 0.0);
else if (date == "%a %d %b")
cairo_set_source_rgb (g, 1.0, 1.0, 1.0);
else
cairo_set_source_rgb (g, 0.9, 0.7, 0.0);
cairo_select_font_face(g,"Sans",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(g,24);
cairo_move_to (g, 0.0, 20.0);
cairo_show_text(g,buffer);
cairo_restore (g);
cairo_paint (g);
}
36°C today
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
Re: Simple Clock
The value was 0 even after click, this is why I removed the test. After this it reacted on clicks with a 1 sec delay. Your latest version reacts immediately. Thanks.
(Now I can see ret == 1 after click, don't know what makes the difference.)
To move the window to a certain position the wmctrl command can be used:
Code: Select all
# in this example x=250, y=150
wmctrl -r sclockx -e 0,250,150,-1,-1
(My conky shows 10°C higher CPU idle temp than it was in the spring.)
Update: The borders remain visible because picom draws shadows. Its config has this: dnd = { fade = false; shadow = false; } (same for dock but it's special for jwm) So tried to set it:
Code: Select all
Atom window_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False);
long wmWindowTypeDnD = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DND", False);
XChangeProperty(disp, w, window_type, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmWindowTypeDnD, 1);
Is there a better way to remove decorations of a specific window?
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
Burunduk wrote: Fri Jul 01, 2022 10:12 amThe value was 0 even after click, this is why I removed the test. After this it reacted on clicks with a 1 sec delay. Your latest version reacts immediately. Thanks.
(Now I can see ret == 1 after click, don't know what makes the difference.)To move the window to a certain position the wmctrl command can be used:
Code: Select all
# in this example x=250, y=150 wmctrl -r sclockx -e 0,250,150,-1,-1
(My conky shows 10°C higher CPU idle temp than it was in the spring.)
Update: The borders remain visible because picom draws shadows. Its config has this: dnd = { fade = false; shadow = false; } (same for dock but it's special for jwm) So tried to set it:
Code: Select all
Atom window_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False); long wmWindowTypeDnD = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DND", False); XChangeProperty(disp, w, window_type, XA_ATOM, 32, PropModeAppend, (unsigned char *) &wmWindowTypeDnD, 1);
Is there a better way to remove decorations of a specific window?
Not all window managers follow freedesktop.org specifications.
Some follow motif wm hints, but maybe SPLASH would do that. https://specifications.freedesktop.org/ ... 01s05.html
if I set _NET_WM_WINDOW_TYPE_SPLASH, Xfwm4 doesn't follow the gravity set in size hints to center.
It isn't placing it in center but to the top left.
I should implement that as an option along with the X and Y positions of the window.
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
- rockedge
- Site Admin
- Posts: 6561
- Joined: Mon Dec 02, 2019 1:38 am
- Location: Connecticut,U.S.A.
- Has thanked: 2770 times
- Been thanked: 2646 times
- Contact:
Re: Simple Clock
In KLV-Airedale (and Puppy Linux Bionic64) I am using a .desktop file for a menu start option.
Code: Select all
[Desktop Entry]
Encoding=UTF-8
Name=sClock
Icon=/usr/share/pixmaps/clock_digital.svg
Comment=Desktop Clock
Exec=sClock --color=orange --center --stick
Terminal=false
Type=Application
Categories=X-Desktop
GenericName=Desktop clock
Looks like this in KLV-Airedale-beta15 ->
at start up.....
moved to a better contrast region.....
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
rockedge wrote: Sat Jul 02, 2022 9:22 pmIn KLV-Airedale (and Puppy Linux Bionic64) I am using a .desktop file for a menu start option.
Code: Select all
[Desktop Entry] Encoding=UTF-8 Name=sClock Icon=/usr/share/pixmaps/clock_digital.svg Comment=Desktop Clock Exec=sClock --color=orange --center --stick Terminal=false Type=Application Categories=X-Desktop GenericName=Desktop clock
Looks like this in KLV-Airedale-beta15 ->
at start up.....
Screenshot_2022-07-02_17-21-53.jpg
moved to a better contrast region.....
Screenshot_2022-07-02_17-23-23.jpg
sclock (gtk3) fits good in there rockedge.
In the meantime, the new sclockx got some options.
Code: Select all
" -h, --help Show help message and quit\n"
" --above Keep clock above other windows, default is below\n"
" --color= Set text color, e.g. fcfcfc, this option can be set multiple times\n"
" --posx= Set X position\n"
" --posy= Set Y position\n"
" --splash Set window type to splash\n"
Now setting the color of all the clocks looks like:
Code: Select all
sclockx --color="ffffff" --color f6aa33 --color fcfccc --color ffccff --above
If not set it defaults to first set, and if first color is not set to green..
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <getopt.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
#include <sys/select.h>
/* gcc sclockx.c -o sclockx $(pkg-config --cflags --libs cairo-xlib-xrender x11) */
struct xwindow {
Display *disp;
Window w;
XVisualInfo vinfo;
cairo_t *cr;
cairo_t *bg;
cairo_surface_t *img;
cairo_surface_t *ximg;
};
struct options {
int pos_x;
int pos_y;
int above;
int splash;
int start;
};
struct colors {
int rgb[3];
int set[1];
};
static const char sclockx_usage[] =
"Usage: sclockx [options]\n\n"
" -h, --help Show help message and quit\n"
" --above Keep clock above other windows, default is below\n"
" --color= Set text color, e.g. fcfcfc, this option can be set multiple times\n"
" --posx= Set X position\n"
" --posy= Set Y position\n"
" --splash Set window type to splash\n"
"\n";
static void
draw (cairo_t *g, char *date,
struct colors *col);
static void
set_source_color (cairo_t *g,
struct colors *col,
int color_index);
static void
x11_create_window (struct xwindow *ctx);
static void
x11_move_window (struct xwindow *ctx,
struct options *opt);
static void
set_cairo (struct xwindow *ctx);
static void
main_loop (struct xwindow *ctx,
struct colors *col);
static void
set_hints (struct xwindow *ctx,
struct options *opt);
static char *
set_above (int above);
static void usage (void);
int main (int argc, char **argv)
{
struct colors col[4];
struct options opt = { 0 };
/* initial values */
opt.pos_x = -1;
opt.pos_y = -1;
opt.splash = 0;
opt.start = 1;
col[0].rgb[0] = 0;
col[0].rgb[1] = 255;
col[0].rgb[2] = 0;
int c;
int i, index = 0;
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"above", no_argument, 0, 2 },
{"color", required_argument, 0, 0 },
{"posx", required_argument, 0, 'x'},
{"posy", required_argument, 0, 'y'},
{"splash", no_argument, 0, 1 },
{"start", required_argument, 0, 's'},
{0, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "hx:y:0:12",
long_options, NULL)) != -1) {
switch (c) {
case 'x':
if (atoi(optarg) > -1)
opt.pos_x = atoi(optarg);
break;
case 'y':
if (atoi(optarg) > -1)
opt.pos_y = atoi(optarg);
break;
case 0:
sscanf(optarg, "%02x%02x%02x", &col[index].rgb[0], &col[index].rgb[1], &col[index].rgb[2]);
for (i = 0; i < 3; i++) {
if (col[index].rgb[i] > 255 || col[index].rgb[i] < -1) {
printf("Invalid color %s\n", optarg);
usage();
}
}
sscanf("1", "%d", &col[index].set[0]);
index++;
if (index > 4)
usage();
break;
case 1:
opt.splash = 1;
break;
case 2:
opt.above = 1;
break;
case 'h':
default:
usage();
}
}
if (optind < argc)
usage();
struct xwindow ctx = { 0 };
ctx.disp = XOpenDisplay(NULL);
if (!ctx.disp) {
printf("Display open failed.\n");
return 1;
}
x11_create_window (&ctx);
set_cairo (&ctx);
set_hints (&ctx, &opt);
XMapWindow(ctx.disp, ctx.w);
x11_move_window (&ctx, &opt);
XSync (ctx.disp, False);
main_loop (&ctx, col);
cairo_destroy (ctx.cr);
cairo_surface_destroy (ctx.ximg);
cairo_destroy (ctx.bg);
cairo_surface_destroy(ctx.img);
XDestroyWindow (ctx.disp, ctx.w);
XCloseDisplay (ctx.disp);
return 0;
}
static void
x11_create_window (struct xwindow *ctx)
{
const char depths[] = { 32, 24, 8, 4, 2, 1, 0 };
for (int i = 0; depths[i]; i++) {
XMatchVisualInfo (ctx->disp,
DefaultScreen (ctx->disp),
32, TrueColor, &ctx->vinfo);
if (ctx->vinfo.visual)
break;
}
XSetWindowAttributes attr;
attr.override_redirect = False;
attr.event_mask = KeyPressMask | ButtonPressMask;
attr.colormap = XCreateColormap(ctx->disp,
DefaultRootWindow (ctx->disp),
ctx->vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
ctx->w = XCreateWindow(ctx->disp, DefaultRootWindow (ctx->disp), 0, 0, 180, 26, 0,
ctx->vinfo.depth, InputOutput, ctx->vinfo.visual,
CWEventMask | CWColormap | CWBorderPixel | CWBackPixel , &attr);
XStoreName(ctx->disp, ctx->w, "sclockx");
XSelectInput(ctx->disp, ctx->w,
KeyPressMask | ClientMessage |
ButtonPressMask | ButtonReleaseMask);
}
static void
x11_move_window (struct xwindow *ctx,
struct options *opt)
{
if ((opt->pos_x > -1) && (opt->pos_y > -1))
XMoveWindow (ctx->disp, ctx->w, opt->pos_x, opt->pos_y);
if ((opt->pos_x > -1) && !(opt->pos_y > -1))
XMoveWindow (ctx->disp, ctx->w, opt->pos_x, 0);
if (!(opt->pos_x > -1) && (opt->pos_y > -1))
XMoveWindow (ctx->disp, ctx->w, 0, opt->pos_y);
}
static void
set_cairo (struct xwindow *ctx)
{
ctx->img = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 180, 26);
ctx->bg = cairo_create (ctx->img);
ctx->ximg = cairo_xlib_surface_create (ctx->disp, ctx->w,
ctx->vinfo.visual, 180, 26);
cairo_xlib_surface_set_size (ctx->ximg, 180, 26);
ctx->cr = cairo_create (ctx->ximg);
cairo_set_source_surface (ctx->cr, ctx->img, 0, 0);
}
static void
main_loop (struct xwindow *ctx,
struct colors *col)
{
int x11_fd;
fd_set in_fds;
int nfds = x11_fd + 4; //getopts opens something +1
struct timeval tv = { 0 };
XEvent ev;
x11_fd = ConnectionNumber (ctx->disp);
static char *date = "%r";
Atom wm_delete_window = XInternAtom (ctx->disp, "WM_DELETE_WINDOW", False);
XSetWMProtocols (ctx->disp, ctx->w, &wm_delete_window, 1);
for (;;) {
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);
// Set timer to one second
tv.tv_usec = 0;
tv.tv_sec = 1;
// Wait for X Event or a Timer
int ret;
if (!XPending(ctx->disp))
ret = select (nfds, &in_fds, NULL, NULL, &tv);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
goto shutdown;
if (ret == 0)
draw(ctx->cr, date, col);
if (XPending (ctx->disp)) {
XNextEvent (ctx->disp, &ev);
if (XFilterEvent (&ev, ctx->w))
continue;
switch (ev.type) {
case ClientMessage:
if (ev.xclient.data.l[0] == wm_delete_window)
goto shutdown;
case ButtonPress:
switch(ev.xbutton.button){
case Button1:
if (date == "%r")
date = "%R:%S";
else if (date == "%R:%S")
date = "%a %d %b";
else if (date == "%a %d %b")
date = " %Y";
else
date = "%r";
draw(ctx->cr, date, col);
continue;
case Button3:
goto shutdown;
default:
break;
}
}
}
if (ret > 1)
printf("An error occured!%d\n", ret);
}
shutdown: printf("Exit\n");
}
static void
draw (cairo_t *g, char *date,
struct colors *col)
{
char buffer[12];
time_t timer;
struct tm* tm_info;
time (&timer);
tm_info = localtime (&timer);
strftime (buffer, 64, date, tm_info);
cairo_save (g);
cairo_set_source_rgba (g,0,0,0,1);
cairo_set_operator (g, CAIRO_OPERATOR_CLEAR);
cairo_paint (g);
cairo_restore (g);
cairo_set_operator (g, CAIRO_OPERATOR_OVER);
cairo_save (g);
if (date == "%r")
set_source_color(g, col, 0);
else if (date == "%R:%S")
set_source_color(g, col, 1);
else if (date == "%a %d %b")
set_source_color(g, col, 2);
else
set_source_color(g, col, 3);
cairo_select_font_face(g,"Sans",CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(g,24);
cairo_move_to (g, 0.0, 20.0);
cairo_show_text(g,buffer);
cairo_restore (g);
cairo_paint (g);
}
static void
set_source_color (cairo_t *g, struct colors *col, int color_index)
{
if (col[color_index].set[0] != 1)
color_index = 0;
cairo_set_source_rgb (g, (float) col[color_index].rgb[0] / 255,
(float) col[color_index].rgb[1] / 255,
(float) col[color_index].rgb[2] / 255);
}
static void
set_hints (struct xwindow *ctx,
struct options *opt)
{
XSizeHints sh;
sh.width = sh.min_width = 150;
sh.height = sh.min_height = 24;
sh.max_width = 220;
sh.max_height = 40;
sh.win_gravity = 0;
sh.flags = PSize | PMinSize | PMaxSize | PWinGravity;
XSetWMNormalHints (ctx->disp, ctx->w, &sh);
Atom motif_hints;
long hints[5] = {2, 0, 0, 0, 0};
motif_hints = XInternAtom(ctx->disp, "_MOTIF_WM_HINTS", False);
XChangeProperty (ctx->disp, ctx->w, motif_hints, motif_hints, 32,
PropModeReplace, (unsigned char *)&hints, 5);
Atom window_state = XInternAtom (ctx->disp, "_NET_WM_STATE", False);
long wmStateBelow = XInternAtom (ctx->disp, set_above(opt->above), False);
long wmStateSticky = XInternAtom (ctx->disp, "_NET_WM_STATE_STICKY", False);
long wmStateSkipTaskbar = XInternAtom (ctx->disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
long wmStateSkipPager = XInternAtom (ctx->disp, "_NET_WM_STATE_SKIP_PAGER", False);
XChangeProperty (ctx->disp, ctx->w, window_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *) &wmStateBelow, 1);
XChangeProperty (ctx->disp, ctx->w, window_state, XA_ATOM, 32,
PropModeAppend, (unsigned char *) &wmStateSticky, 1);
XChangeProperty (ctx->disp, ctx->w, window_state, XA_ATOM, 32,
PropModeAppend, (unsigned char *) &wmStateSkipTaskbar, 1);
XChangeProperty (ctx->disp, ctx->w, window_state, XA_ATOM, 32,
PropModeAppend, (unsigned char *) &wmStateSkipPager, 1);
if (opt->splash) {
Atom window_type = XInternAtom (ctx->disp, "_NET_WM_WINDOW_TYPE", False);
long wmWindowTypeSplash = XInternAtom (ctx->disp, "_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty (ctx->disp, ctx->w, window_type, XA_ATOM, 32,
PropModeAppend, (unsigned char *) &wmWindowTypeSplash, 1);
}
}
static char *
set_above (int above)
{
static char *ret;
if (above)
ret = "_NET_WM_STATE_ABOVE";
else
ret = "_NET_WM_STATE_BELOW";
return ret;
}
static void
usage(void)
{
printf("%s", sclockx_usage);
exit(0);
}
What surprised me the most is that getopts opens some fd and leaves them open.
That interfered with the timeout and made the app extremely slow.
Had to change this:
Code: Select all
int nfds = x11_fd + 1;
Once I figured this, everything else was easy.
Code: Select all
int nfds = x11_fd + 4; //getopts opens something +1
Except half an hour power outage today, of course.
But I saved the code just before.
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
Re: Simple Clock
Wow! I'm glad that many of you got involved in writing some tools and scripts.
I found good examples long ago; the past 3-4 pages are well beyond but I was originally looking for, but as I say, if other participants want to embellish and enhance the scripts and write programs, this is precisely what "freedom" in software is all about. Congratulations to all of you; even the more "experienced" among us learned a few things along the way; I certainly learned what I was seeking, and now I have a small collection of scripts from a couple of lines to perhaps half a screen in size.
I also tried a few of the programs, though these are beyond the original scope of what I was looking for; nevertheless, this entire conversation was quite interesting and educational! Thank you all!
- rockedge
- Site Admin
- Posts: 6561
- Joined: Mon Dec 02, 2019 1:38 am
- Location: Connecticut,U.S.A.
- Has thanked: 2770 times
- Been thanked: 2646 times
- Contact:
Re: Simple Clock
compiled the latest version and a small problem showed up while left clicking->
Code: Select all
root# ./sclockx --color="ffffff" --color f6aa33 --color fcfccc --color ffccff --above
*** stack smashroot# ./sclockx --color="ffffff" --color f6aa33 --color fcfccc --color ffccff --above
*** stack smashing detected ***: terminated
Aborted
first left click changes clock format, second left click is causing stack smashing!
Very first time in all of these years I could generate stack smashing error! Didn't even know there was such a beast
Should be a name of a Punk Rock or Heavy metal band. "Stack Smash"
Re: Simple Clock
On my Fossapup, strftime() produces strings up to 14 bytes long (15 with \0). The buffer in draw() is too small. char buffer[64];
solves the problem.
Update:
misko_2083 wrote: Mon Jul 04, 2022 4:02 pmHad to change this:
Code: Select all
int nfds = x11_fd + 1;
The compiler warns that x11_fd is used uninitialized. Moved it, seems to work normally:
Code: Select all
x11_fd = ConnectionNumber (ctx->disp);
int nfds = x11_fd + 1;
Another warning was about "comparison with string literal results in unspecified behavior". While it works because the pointers are compared, it's probably simpler to use an integer here:
Code: Select all
static void
draw (cairo_t *g, int mode,
struct colors *col);
...
static int mode = 0;
...
if (ret == 0)
draw(ctx->cr, mode, col);
if (XPending (ctx->disp)) {
XNextEvent (ctx->disp, &ev);
if (XFilterEvent (&ev, ctx->w))
continue;
switch (ev.type) {
case ClientMessage:
if (ev.xclient.data.l[0] == wm_delete_window)
goto shutdown;
case ButtonPress:
switch(ev.xbutton.button){
case Button1:
mode = mode == 3 ? 0 : mode + 1;
draw(ctx->cr, mode, col);
continue;
...
static void
draw (cairo_t *g, int mode,
struct colors *col)
{
char buffer[64];
time_t timer;
const char *fmt[] = {"%r", "%R:%S", "%a %d %b", " %Y"};
struct tm* tm_info;
time (&timer);
tm_info = localtime (&timer);
strftime (buffer, 64, fmt[mode], tm_info);
...
cairo_set_operator (g, CAIRO_OPERATOR_OVER);
cairo_save (g);
set_source_color(g, col, mode);
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
rockedge wrote: Mon Jul 04, 2022 4:15 pmShould be a name of a Punk Rock or Heavy metal band. "Stack Smash"
rockedge wrote: Mon Jul 04, 2022 4:15 pmcompiled the latest version and a small problem showed up while left clicking->
Code: Select all
root# ./sclockx --color="ffffff" --color f6aa33 --color fcfccc --color ffccff --above *** stack smashroot# ./sclockx --color="ffffff" --color f6aa33 --color fcfccc --color ffccff --above *** stack smashing detected ***: terminated Aborted
first left click changes clock format, second left click is causing stack smashing!
Very first time in all of these years I could generate stack smashing error! Didn't even know there was such a beast
I've compiled with -fstack-protector-all
option and I can see that now.
Pushed the changes with a fix to github. https://github.com/Misko-2083/sclock
I can fix the smash but some smash protector makes select to return -1 which will exit on start very often.
Does it happens there?
masinick wrote: Mon Jul 04, 2022 4:13 pmWow! I'm glad that many of you got involved in writing some tools and scripts.
I found good examples long ago; the past 3-4 pages are well beyond but I was originally looking for, but as I say, if other participants want to embellish and enhance the scripts and write programs, this is precisely what "freedom" in software is all about. Congratulations to all of you; even the more "experienced" among us learned a few things along the way; I certainly learned what I was seeking, and now I have a small collection of scripts from a couple of lines to perhaps half a screen in size.
I also tried a few of the programs, though these are beyond the original scope of what I was looking for; nevertheless, this entire conversation was quite interesting and educational! Thank you all!
Well that's how it all starts not just software, from a simple solution to the over complicated one.
Burunduk wrote: Mon Jul 04, 2022 10:29 pmOn my Fossapup, strftime() produces strings up to 14 bytes long (15 with \0). The buffer in draw() is too small.
char buffer[64];
solves the problem.
Thanks.
I've pushed to github.
https://github.com/Misko-2083/sclock
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
- misko_2083
- Posts: 196
- Joined: Wed Dec 09, 2020 11:59 pm
- Has thanked: 10 times
- Been thanked: 20 times
Re: Simple Clock
Burunduk wrote: Mon Jul 04, 2022 10:29 pmThe compiler warns that x11_fd is used uninitialized. Moved it, seems to work normally:
Code: Select all
x11_fd = ConnectionNumber (ctx->disp); int nfds = x11_fd + 1;
Thanks.
Burunduk wrote: Mon Jul 04, 2022 10:29 pmAnother warning was about "comparison with string literal results in unspecified behavior". While it works because the pointers are compared, it's probably simpler to use an integer here:
Code: Select all
static void draw (cairo_t *g, int mode, struct colors *col); ... static int mode = 0; ... if (ret == 0) draw(ctx->cr, mode, col); if (XPending (ctx->disp)) { XNextEvent (ctx->disp, &ev); if (XFilterEvent (&ev, ctx->w)) continue; switch (ev.type) { case ClientMessage: if (ev.xclient.data.l[0] == wm_delete_window) goto shutdown; case ButtonPress: switch(ev.xbutton.button){ case Button1: mode = mode == 3 ? 0 : mode + 1; draw(ctx->cr, mode, col); continue; ... static void draw (cairo_t *g, int mode, struct colors *col) { char buffer[64]; time_t timer; const char *fmt[] = {"%r", "%R:%S", "%a %d %b", " %Y"}; struct tm* tm_info; time (&timer); tm_info = localtime (&timer); strftime (buffer, 64, fmt[mode], tm_info); ... cairo_set_operator (g, CAIRO_OPERATOR_OVER); cairo_save (g); set_source_color(g, col, mode);
Doesn't happen on Debian Bullseye.
Try compiling with -std=c11
or -std=c99
Sorry didn't look at the code. That's a very good idea.
Maybe there is a need for an option to select a starting time format.
Like an integer between 1 & 4 or more.
Or do you think it's better to add formats as the option?
--add 1 2 3 4 where 1 2 3 4 are predefined formats
or use (--add h m s) to create a custom format (hour minute second)?
Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c
Re: Simple Clock
misko_2083 wrote: Tue Jul 05, 2022 11:30 amDoesn't happen on Debian Bullseye.
Try compiling with-std=c11
or-std=c99
It's a warning I get with -Wall. The program compiles and runs. It works because no matter how many occurrences of the identical string literals are scattered over the code, only one is stored and &"string"
is always the same. This is probably not guaranteed hence the warning. Some explanations here
And in this case all those comparisons seem to be redundant, the code is shorter without.
Edit: found another link.
misko_2083 wrote:Or do you think it's better to add formats as the option?
The custom format is probably needed for non-English locales but maybe it's better to keep things simple.
The setting for the window type can be also removed for simplicity. I don't want to remove shadows from the splash windows so still use the dnd type and no one has complained of the shadows (not every puppy has picom).