Simple Clock

interpretive language scripts


Moderator: Forum moderators

masinick
Posts: 6
Joined: Mon Jun 13, 2022 6:37 pm
Has thanked: 1 time

Simple Clock

Post by masinick »

I have a short Bash script that produces a simple clock in the top left corner of a bash shell window.
I've copied the text of the script below.

I'd like to create a very simple Yad script that displays the date and time like this:
Jun 13, 2022 02:42:01 PM

in a small Yad clock. I've seen a Yad alarm clock called yalarm that was created a few years ago.
I have been able to modify the clock time in that script using the simple "%r" string instead of the "%H:%M:%S" string, but when I attempt to pull out the alarm clock function I have been unable to do that successfully and still display the time or the date and time.

Here is my bash script code:

Code: Select all

loop=1
while (( loop )); do
  clear
  date +"%b %d, %Y  %r"
  sleep 0.5s
done

Does anyone know what I can add to this simple script to display it in a small yad window instead of the terminal window?

Thanks for any guidance.

User avatar
fredx181
Posts: 3085
Joined: Tue Dec 03, 2019 1:49 pm
Location: holland
Has thanked: 376 times
Been thanked: 1315 times
Contact:

Re: Simple Clock

Post by fredx181 »

Hi masinick,
The following should do it basically, but tell me if you want the display similar as in yalarm with the colors and the special font and I'll look into that.

Code: Select all

while :
do
  date +"%b %d, %Y  %r"
  sleep 0.5
done 2>&1 | yad --title=clock --width=220 --form --cycle-read --field=": " --no-buttons --undecorated  &
2022-06-13_21-55-43.gif
2022-06-13_21-55-43.gif (20.61 KiB) Viewed 2509 times

EDIT: Could look like this with colors and special font (not transparent borders in this image but should be possible to make transparent by using "gtkdesklet"):

2022-06-13_22-43-06.gif
2022-06-13_22-43-06.gif (50.14 KiB) Viewed 2499 times
User avatar
mikewalsh
Moderator
Posts: 6163
Joined: Tue Dec 03, 2019 1:40 pm
Location: King's Lynn, UK
Has thanked: 795 times
Been thanked: 1983 times

Re: Simple Clock

Post by mikewalsh »

@fredx181 :-

"--cycle-read", huh? New one on me. Where d'ya find that one? I don't see any mention of this anywhere in the man pages...

Mike. ;)

User avatar
fredx181
Posts: 3085
Joined: Tue Dec 03, 2019 1:49 pm
Location: holland
Has thanked: 376 times
Been thanked: 1315 times
Contact:

Re: Simple Clock

Post by fredx181 »

mikewalsh wrote: Mon Jun 13, 2022 8:53 pm

@fredx181 :-

"--cycle-read", huh? New one on me. Where d'ya find that one? I don't see any mention of this anywhere in the man pages...

Mike. ;)

It's a real option (I didn't just dream it :) ) see here for example; https://www.mankier.com/1/yad

--cycle-read

Cycled reading of stdin data. Sending FormFeed character clears the form. This symbol may be sent as echo -e '\f'.

EDIT: Not sure btw from which yad version on this is supported, I use yad v0.40

masinick
Posts: 6
Joined: Mon Jun 13, 2022 6:37 pm
Has thanked: 1 time

Re: Simple Clock

Post by masinick »

Thanks!

I also added --posx and --posy coordinates to move the box close to the top; experimenting to see what values are best for my current setup.

I really appreciate your help!

User avatar
mikewalsh
Moderator
Posts: 6163
Joined: Tue Dec 03, 2019 1:40 pm
Location: King's Lynn, UK
Has thanked: 795 times
Been thanked: 1983 times

Re: Simple Clock

Post by mikewalsh »

Hmm... Interesting.

Can I pick your brains, Fred?

That wee script works a treat. I've modified it slightly, to go in a specific place on the desktop:-

Code: Select all

#!/bin/sh
#
# YAD clock... (cheers, Fred!)
#
while :
do
  date +"%a %d %b %H:%M %S"
  sleep 0.5
done 2>&1 | yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated  &

Now, of course, it's running with the preset global font & fontsize, yes? (I had to modify the window size a bit, anyway, 'cos I run with a slightly larger global font; the old peepers aren't as good as they once were!) Lifting this from Smokey's YAD guide, I'd like to change things a bit with

Code: Select all

--fontname="Exo 2 Bold Italic 24"

....but I can't for the life of me figure out where you insert this to change the font? I can see you perform your calculation first, then pipe the output into an undecorated YAD window. Fair enough, I understand that. The bit I haven't yet got my head round is that I've often found certain commands must go in very specific locations in the "chain".....and some of them don't even work unless others are present, yes?

I guess I just haven't used it enough, I suspect. (Things aren't yet "second nature", y'know? :roll:) And Grant's example doesn't make it that clear..... (*sigh*)

Mike. ;)

User avatar
fredx181
Posts: 3085
Joined: Tue Dec 03, 2019 1:49 pm
Location: holland
Has thanked: 376 times
Been thanked: 1315 times
Contact:

Re: Simple Clock

Post by fredx181 »

mikewalsh wrote:

Can I pick your brains, Fred?

That wee script works a treat. I've modified it slightly, to go in a specific place on the desktop:-
....

Hey Mike, I'll come back to that later, don't know atm, bit late already here, not sure if --fontname works with the --form option of yad, my guess is not.

@masinick You're welcome and.. :welcome: to the forum !

User avatar
mikewalsh
Moderator
Posts: 6163
Joined: Tue Dec 03, 2019 1:40 pm
Location: King's Lynn, UK
Has thanked: 795 times
Been thanked: 1983 times

Re: Simple Clock

Post by mikewalsh »

fredx181 wrote: Mon Jun 13, 2022 9:43 pm
mikewalsh wrote:

Can I pick your brains, Fred?

That wee script works a treat. I've modified it slightly, to go in a specific place on the desktop:-
....

Hey Mike, I'll come back to that later, don't know atm, bit late already here, not sure if --fontname works with the --form option of yad, my guess is not.

No worries, mate. As & when, as & when.....more curiosity than anything else at present. In your own time....

Mike. ;)

williams2
Posts: 1062
Joined: Sat Jul 25, 2020 5:45 pm
Been thanked: 305 times

Re: Simple Clock

Post by williams2 »

I use this in my Firefox start script.

Code: Select all

yaf-splash -close never -fontsize 26 -bg cyan4 -text 'Firefox starting ...' -timeout 5 &>/dev/null & disown
User avatar
fredx181
Posts: 3085
Joined: Tue Dec 03, 2019 1:49 pm
Location: holland
Has thanked: 376 times
Been thanked: 1315 times
Contact:

Re: Simple Clock

Post by fredx181 »

Hey Mike, I'll come back to that later, don't know atm, bit late already here, not sure if --fontname works with the --form option of yad, my guess is not.

Seems that --fontname doesn't combine with --form --field, only way to set font and colors in this case AFAIK is with a gtkrc config file (only for gtk2, so won't work with yad compiled with gtk3)

Code: Select all

# Set font and colors, comment, uncomment or modify as preferred
FONTNAME="Ticking Timebomb BB 30"
#FONTNAME="Exo 2 Bold Italic 24"
#FONTNAME="Sans Bold 20"
FCOL=yellow
BCOL=grey30
#FCOL=blue
#BCOL=yellow

# create gtkrc
echo "style \"y_clock\" { font_name=\"$FONTNAME\"
base[NORMAL]=\"$BCOL\" 
text[NORMAL]=\"$FCOL\" }
widget \"*\" style \"y_clock\"
" > /tmp/gtkrc_yclock

while :
do
  date +"%a %d %b %H:%M %S"
  sleep 0.5
done 2>&1 | GTK2_RC_FILES=/tmp/gtkrc_yclock yad --title=clock --geometry=330x0+420+16 --form --cycle-read --field=": " --no-buttons --undecorated --gtk-module=gtk2desklet &
2022-06-14_11-09-14.gif
2022-06-14_11-09-14.gif (63.27 KiB) Viewed 2409 times

If gtk2desklet is installed, the borders will become transparent, remove --gtk-module=gtk2desklet from the code if not desired.
Here's the Ticking Timebomb font attached (remove fake .gz and place in ~/.local/share/fonts (if not exist, create it) or in /usr/share/fonts .

TickingTimebombBB.ttf.gz
Remove fake .gz
(30.51 KiB) Downloaded 55 times
User avatar
mikewalsh
Moderator
Posts: 6163
Joined: Tue Dec 03, 2019 1:40 pm
Location: King's Lynn, UK
Has thanked: 795 times
Been thanked: 1983 times

Re: Simple Clock

Post by mikewalsh »

@fredx181 :-

Yah, that works nicely. Now; here's a poser....

How do you kill the process manually? I've saved all the above as a script named "time.sh", OK? Trying all the usual suspects - killall, kill, pkill, xkill, etc - on the script, nothing works.

Under the 'Processes' tab of Mate-System-Monitor - this is what I normally use to kill reluctant processes - it simply shows up as a running YAD process. Highlighting the process, then clicking the 'End Process' button, it quits beautifully. BUT; the actual process doesn't appear to show up anywhere..?

I know it probably wouldn't bother most folks, who would want it showing all the time.....but when it comes to desktop widgets, although I'm happy for them to auto-start and run till shutdown, I still like to have a manual 'override'. This is what I've done with all the wee GIFs I have running on the desktop - 3, at present - and 'killall' works nicely to shut these down. But the same process doesn't work with this......and I can't actually find the running process anywhere in the file-system. Not even in /tmp.

Any suggestions? Ideas?

(EDIT:- I thought the following might work, but.....no dice...

Code: Select all

killall 'yad --title=clock --geometry=330x0+420+16 --form --cycle-read --field=": "  --no-buttons --undecorated --gtk-module=gtk2desklet &'

What d'you reckon? I'm probably approaching this from the wrong angle...)

Mike. :?

User avatar
stemsee
Posts: 779
Joined: Sun Jul 26, 2020 8:11 am
Location: lattitude 8
Has thanked: 185 times
Been thanked: 131 times

Re: Simple Clock

Post by stemsee »

clock.png
clock.png (14.17 KiB) Viewed 2089 times

Here's an idea which will let you add background colours and fonts and text colours, still using yad. yad --text-info lets you specify font size and color and background colour too.

UPDATED to use yad --text-info with pango markup available.

Code: Select all

#!/bin/sh

#!/bin/sh

mkfifo /tmp/clock
exec 8<> /tmp/clock
yad --text-info --fontname="Sans Bold Italic 20" --no-buttons --back=black --fore=red --skip-tray --width=200 --height=72 --undecorated --no-headers --listen <& 8 &
while sleep 1
do
TIME="$(date +%X)"

echo -e '\f' >/tmp/clock
printf "%s\n" "$TIME" >/tmp/clock
done
Last edited by stemsee on Tue Jun 14, 2022 1:41 pm, edited 5 times in total.
User avatar
fredx181
Posts: 3085
Joined: Tue Dec 03, 2019 1:49 pm
Location: holland
Has thanked: 376 times
Been thanked: 1315 times
Contact:

Re: Simple Clock

Post by fredx181 »

@mikewalsh
Yeah Mike, you are right, difficult to kill, I'm not sure, but I think that the time.sh process is already gone after running it and the while loop process stays .
I found that this should work to kill the yad process, but perhaps there's a better solution.
pidyclock="$(pgrep -lf "yad --title=clock" | awk '{ print $1 }')"; kill $pidyclock
EDIT: Or simply: kill $(pgrep -lf "yad --title=clock" | awk '{ print $1 }')

User avatar
wiak
Posts: 4082
Joined: Tue Dec 03, 2019 6:10 am
Location: Packing - big job
Has thanked: 65 times
Been thanked: 1208 times
Contact:

Re: Simple Clock

Post by wiak »

I think you could also run your clock script in a backgrounded shell job kind of construct like this:

Code: Select all

{ ./yourclock; } &

and probably:

Code: Select all

kill %1

kills the whole job off?

or you can pick up the pid after running it (using $!); no that doesn't work - you can kill the job off though

https://www.tinylinux.info/
DOWNLOAD wd_multi for hundreds of 'distros' at your fingertips: viewtopic.php?p=99154#p99154
Αξίζει να μεταφραστεί;

User avatar
mikewalsh
Moderator
Posts: 6163
Joined: Tue Dec 03, 2019 1:40 pm
Location: King's Lynn, UK
Has thanked: 795 times
Been thanked: 1983 times

Re: Simple Clock

Post by mikewalsh »

fredx181 wrote: Tue Jun 14, 2022 12:56 pm

@mikewalsh
Yeah Mike, you are right, difficult to kill, I'm not sure, but I think that the time.sh process is already gone after running it and the while loop process stays .
I found that this should work to kill the yad process, but perhaps there's a better solution.
pidyclock="$(pgrep -lf "yad --title=clock" | awk '{ print $1 }')"; kill $pidyclock
EDIT: Or simply: kill $(pgrep -lf "yad --title=clock" | awk '{ print $1 }')

Well, either works for me, Fred. So that gives me time.sh to start it.......and time-stop.sh to make it quit.

That'll do! :thumbup:

I have "hidden" manual controls for all my desktop GIFS/widgets...

[Click to enlarge:-]

Image

Mike. :D

User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

fredx181 wrote: Tue Jun 14, 2022 12:56 pm

difficult to kill

You guys... :lol:

Just made this:

Code: Select all

#include <stdio.h>
#include <time.h>
#include <gtk/gtk.h>

static gboolean
on_timeout (gpointer user_data)
{
  GtkLabel *label = GTK_LABEL (user_data);
  time_t timer;
  char buff[28];
  struct tm* tm_info;

  time (&timer);
  tm_info = localtime(&timer);

  strftime(buff, 28, "%a %b %d/%m/%Y %H:%M:%S", tm_info);

  gchar *markup = g_strdup_printf ("<b><span font='Sans Bold 20' foreground='red'>%s</span></b>", buff); 
  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);

  return G_SOURCE_CONTINUE;
}

void destroy_handler (GtkApplication* app, gpointer data)
{
    g_application_quit(G_APPLICATION (data));
}

static gboolean
key_handler (GtkWidget *w, GdkEventKey *ev, gpointer data)
{
  GtkApplication *app = GTK_APPLICATION (data);
  switch (ev->keyval)
    {
    case GDK_KEY_Escape:
        destroy_handler(NULL, app);
        return TRUE;
    }
  return FALSE;
}

static gboolean
button_handler (GtkWidget *w, GdkEventButton *ev, gpointer data)
{
  if (ev->button == 1)
    {
      gtk_window_begin_move_drag(GTK_WINDOW(w),
          ev->button,
          ev->x_root,
          ev->y_root,
          ev->time);
      return TRUE;
    }
  if (ev->button == 3)
    {
      GtkApplication *app = GTK_APPLICATION (data);
      GtkWidget *item, *popup_menu;

      popup_menu = gtk_menu_new ();
      gtk_menu_set_reserve_toggle_size (GTK_MENU (popup_menu), FALSE);
      item = gtk_menu_item_new_with_label ("Exit");
      gtk_widget_show (item);
      gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (destroy_handler), app);
      gtk_menu_popup_at_pointer (GTK_MENU (popup_menu), NULL);
      return TRUE;
    }
  return FALSE;
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget           *window;
  GtkWidget           *grid;
  GtkWidget           *label;
  GtkStyleProvider    *style_provider;
  char                *css_text;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Simple Clock");
  gtk_window_set_default_size (GTK_WINDOW (window), 400, 60);
  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);

  grid = gtk_grid_new ();
  gtk_grid_set_column_homogeneous (GTK_GRID (grid),
                                TRUE);
  gtk_grid_set_row_homogeneous (GTK_GRID (grid),
                                FALSE);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 10);

  label = gtk_label_new(NULL);
  g_timeout_add (1000, on_timeout, label);

  gtk_widget_set_halign (label, GTK_ALIGN_CENTER);

  gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);

  gtk_container_add (GTK_CONTAINER (window), grid);
  gtk_container_set_border_width (GTK_CONTAINER(window),10);

  style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
  gtk_style_context_add_provider (gtk_widget_get_style_context (window),
                                  style_provider,
                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

  css_text = g_strdup_printf ("window,\n"
                              "window\n"
                              "{\n"
                              "  background: black;\n"
                              "}\n");

  gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (style_provider),
                                   css_text, -1, NULL);
  g_free (css_text);

  g_signal_connect (G_OBJECT(window), "destroy",
                    G_CALLBACK (destroy_handler), app);
  g_signal_connect (G_OBJECT (window), "key-press-event",
                    G_CALLBACK (key_handler), app);
  g_signal_connect (G_OBJECT (window), "button-press-event",
                    G_CALLBACK (button_handler), app);
  gtk_widget_show_all (window);
}

int
main (int argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.simple_time",
                             G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

Save as sclock.c
Fred you install libgtk-3-dev since you run debian.
Compile with:

Code: Select all

gcc sclock.c -o sclock $(pkg-config --cflags --libs gtk+-3.0)

run

Code: Select all

./sclock

I made it look the same as yad above red/black.
Plus left click can drag a window, right click opens a menu to exit.
Also Escape key when the window is in focus is used to exit app.

@mikewalsh Almost forgot, I set the skip_pager_hint so it doesn't show in a window list on alt+tab.

P.S. Used an app named peek to record this animated gif
Image

Oh I just noticed I used this date format dd/mm/YYYY.
I don't know about you guys, it comes naturally for me to read day first, then month.

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

User avatar
MochiMoppel
Posts: 1240
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 21 times
Been thanked: 440 times

Re: Simple Clock

Post by MochiMoppel »

masinick wrote: Mon Jun 13, 2022 6:48 pm

I have a short Bash script that produces a simple clock in the top left corner of a bash shell window.

I changed the script to prettify the display and bring it closer to the following yad adaptations. Important is to get rid of the clear command because it creates flicker.

Code: Select all

#!/bin/sh
urxvt -title ConsoleClock -font 9x15B +scrollBar -bg yellow -underlineColor yellow -geometry 25x1 -e bash -c '
while : ; do
  echo -en $(date +"%b %d, %Y  %r")" \r"
  sleep 1
done'
consoleclock.png
consoleclock.png (1.67 KiB) Viewed 1950 times

However if I understand your post correctly, a simple clock is not your objective. This is what you already have and can produce with your modification of yalarm. What you really want is to use/fix/change the alarm function of that script, right? If so it would be nice if you could post the yalarm script and clarify what functionality the "simple clock" eventually should have.

mikewalsh wrote: Tue Jun 14, 2022 11:51 am

How do you kill the process manually? I've saved all the above as a script named "time.sh", OK? Trying all the usual suspects - killall, kill, pkill, xkill, etc - on the script, nothing works.

Click on the window and then press Esc key or Alt+F4
or close the "clock" tab in the tray.

But that solves only part of the problem.

fredx181 wrote: Tue Jun 14, 2022 12:56 pm

I found that this should work to kill the yad process, but perhaps there's a better solution.
pidyclock="$(pgrep -lf "yad --title=clock" | awk '{ print $1 }')"; kill $pidyclock
EDIT: Or simply: kill $(pgrep -lf "yad --title=clock" | awk '{ print $1 }')

Or simpler (they all do the same thing):
kill $(pgrep -f "yad --title=clock")
pkill -f "yad --title=clock"
pkill -f title=clock <= not exactly the same but should be sufficient

Now here is the problem: This kills yad and its window, but it doesn't kill time.sh
After three times of starting time.sh and killing yad, 6 processes of the script are still running:

Code: Select all

# pgrep -f time.sh    
17639
17640
17752
17753
17893
17894

Killing all processes when closing the window (via Alt+F4 or tray) is tricky. The most convenient way I can think of is using the trap command (I took the liberty to remove the counterproductive 2>&1 redirection and changed sleep to 1 sec)

Code: Select all

#!/bin/sh
while :
do
  date +"%a %d %b %H:%M %S"
  sleep 1
done  | { trap "pkill -f $0" EXIT ; yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated  ;}

[EDIT]: No, doesn't need trap, can be done after yad closed or killed:

Code: Select all

done  | { yad --title="clock" --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated ; pkill -f "$0"  ;}
Last edited by MochiMoppel on Sat Jun 18, 2022 1:29 am, edited 1 time in total.
User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

On the other hand there is no need for background. The window is now transparent.
Added some options to set the color of the text, date format, font.

Code: Select all

Usage:
  sclock [OPTION?]

Help Options:
  -h, --help        Show help options

Application Options:
  --color=COLOR     Specify color to use
  --date=STRING     Specify display time, not 'now
  --font=FONT       Specify font to use

Also set GdkWindowHints to prevent resizing.
It resized and maximized window if dragged to the screen edge on Xfwm4, probably with other window managers too.
If wrong options are set it defaults to

Code: Select all

    color = "red";
    date = "%a %b %d/%m/%Y %H:%M:%S";
    font = "Sans Bold 20";

Compiles with the same command:

Code: Select all

gcc sclock.c -o sclock $(pkg-config --cflags --libs gtk+-3.0)

sclock.c

Code: Select all

#include <stdio.h>
#include <time.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <pango/pango.h>

static gchar *date = NULL;
static gchar *font = NULL;
static gchar *color = NULL;

static gboolean
on_timeout (gpointer user_data)
{
  GtkLabel *label = GTK_LABEL (user_data);
  GError *error = NULL;
  char *out = NULL;

  time_t timer;
  char buff[28];
  struct tm* tm_info;

  time (&timer);
  tm_info = localtime(&timer);
  strftime(buff, 28, date, tm_info);

  gchar *markup = g_strdup_printf ("<b><span font='%s' foreground='%s'>%s</span></b>",
                                   font, color, buff);

  if (pango_parse_markup (markup,
                         -1,
                          0,
                          NULL,
                          &out,
                          NULL,
                          &error) == FALSE)
  {
    fprintf (stderr, "%s\n", error->message);
    color = "red";
    date = "%a %b %d/%m/%Y %H:%M:%S";
    font = "Sans Bold 20";

    gchar *markup = g_strdup_printf ("<b><span font='%s' foreground='%s'>%s</span></b>",
                                     font, color, buff);

    if (out)
       free (out);
    g_error_free (error);
  }
  
  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);

  return G_SOURCE_CONTINUE;
}

void destroy_handler (GtkApplication* app, gpointer data)
{
    g_application_quit(G_APPLICATION (data));
}

static gboolean
key_handler (GtkWidget *w, GdkEventKey *ev, gpointer data)
{
  GtkApplication *app = GTK_APPLICATION (data);
  switch (ev->keyval)
    {
    case GDK_KEY_Escape:
        destroy_handler(NULL, app);
        return TRUE;
    }
  return FALSE;
}

static gboolean
button_handler (GtkWidget *w, GdkEventButton *ev, gpointer data)
{
  if (ev->button == 1)
    {
      gtk_window_begin_move_drag(GTK_WINDOW(w),
          ev->button,
          ev->x_root,
          ev->y_root,
          ev->time);
      return TRUE;
    }
  if (ev->button == 3)
    {
      GtkApplication *app = GTK_APPLICATION (data);
      GtkWidget *item, *popup_menu;

      popup_menu = gtk_menu_new ();
      gtk_menu_set_reserve_toggle_size (GTK_MENU (popup_menu), FALSE);
      item = gtk_menu_item_new_with_label ("Exit");
      gtk_widget_show (item);
      gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (destroy_handler), app);
      gtk_menu_popup_at_pointer (GTK_MENU (popup_menu), NULL);
      return TRUE;
    }
  return FALSE;
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget           *window;
  GtkWidget           *grid;
  GtkWidget           *label;
  GdkScreen           *screen;
  GdkVisual           *visual;
  GdkGeometry         hints;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Simple Clock");
  gtk_window_set_default_size (GTK_WINDOW (window), 10, 10);
  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);

  gtk_widget_set_app_paintable (window, TRUE);
  screen = gdk_screen_get_default();
  visual = gdk_screen_get_rgba_visual(screen);

  if (visual != NULL && gdk_screen_is_composited(screen)) {
    gtk_widget_set_visual(window, visual);
  }

  grid = gtk_grid_new ();
  gtk_grid_set_column_homogeneous (GTK_GRID (grid),
                                TRUE);
  gtk_grid_set_row_homogeneous (GTK_GRID (grid),
                                FALSE);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 10);

  label = gtk_label_new(NULL);
  g_timeout_add (1000, on_timeout, label);

  gtk_widget_set_halign (label, GTK_ALIGN_CENTER);

  gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);

  gtk_container_add (GTK_CONTAINER (window), grid);
  gtk_container_set_border_width (GTK_CONTAINER(window), 10);

  g_signal_connect (G_OBJECT(window), "destroy",
                    G_CALLBACK (destroy_handler), app);
  g_signal_connect (G_OBJECT (window), "key-press-event",
                    G_CALLBACK (key_handler), app);
  g_signal_connect (G_OBJECT (window), "button-press-event",
                    G_CALLBACK (button_handler), app);
  gtk_widget_show_all (window);

  hints.min_width = 0;
  hints.max_width = gtk_widget_get_allocated_width (window);
  hints.min_height = 0;
  hints.max_height = gtk_widget_get_allocated_height (window);

  gtk_window_set_geometry_hints(
        GTK_WINDOW(window),
        window,
        &hints,
        (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
}

static int
get_options (int argc,
             char *argv[])
{
  static
    GOptionEntry option_entries[] = {
    { "color",        0, 0, G_OPTION_ARG_STRING,   &color,
       "Specify color to use", "COLOR" },
    { "date",        0, 0, G_OPTION_ARG_STRING,   &date,
       "Specify display time, not 'now", "STRING" },
    { "font",        0, 0, G_OPTION_ARG_STRING,   &font,
       "Specify font to use", "FONT" },
    { NULL }
  };
              
  GOptionContext *option_context;

  GError *error = NULL;

#if (!GLIB_CHECK_VERSION (2, 36, 0))
  g_type_init ();
#endif

  option_context = g_option_context_new (NULL);
  g_option_context_add_main_entries (option_context,
                                     option_entries,
                                     NULL);
  if (g_option_context_parse (option_context,
                              &argc,
                              &argv,
                              &error) == FALSE) {
    fprintf (stderr, "%s\n", error->message);
    return 1;
  }

  if (color == NULL)
      color = "red";
  if (date == NULL)
      date = "%a %b %d/%m/%Y %H:%M:%S";
  if (font == NULL)
      font = "Sans Bold 20";

  g_option_context_free (option_context);

  return 0;
}

int
main (int argc,
      char **argv)
{
  int status;
  GtkApplication *app;
  gboolean opts;

  opts = get_options (argc, argv);
  if (opts == 1)
     return 1;

  app = gtk_application_new ("org.gtk.simple_clock",
                             G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

Animated gif made with peek app:
Image
Options used for the gif: --color="#fcfcfc" --font="Noto Sans 30" --date="Year %Y: %H:%M:%S"

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

MochiMoppel wrote: Wed Jun 15, 2022 3:25 am

Killing all processes when closing the window (via Alt+F4 or tray) is tricky. The most convenient way I can think of is using the trap command (I took the liberty to remove the counterproductive 2>&1 redirection and changed sleep to 1 sec)

Code: Select all

#!/bin/sh
while :
do
  date +"%a %d %b %H:%M %S"
  sleep 1
done  | { trap "pkill -f $0" EXIT ; yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated  ;}

[EDIT]: No, doesn't need trap, can be done after yad closed or killed:

Code: Select all

done  | { yad --title="clock" --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated ; pkill -f "$0"  ;}

Not sure but I think that was an old bug in yad version 0.40.1.
But Gustavo hasn't packaged any new versions for Debian since then. https://bugs.debian.org/cgi-bin/bugrepo ... bug=919785
And everyone is stuck with that. I know @step prefers Gtk2.
Yad was ported long ago to Gtk3 and right now at version 12.

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

williams2
Posts: 1062
Joined: Sat Jul 25, 2020 5:45 pm
Been thanked: 305 times

Re: Simple Clock

Post by williams2 »

i sometimes use xclock

xclock.png
xclock.png (13.26 KiB) Viewed 1890 times
User avatar
MochiMoppel
Posts: 1240
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 21 times
Been thanked: 440 times

Re: Simple Clock

Post by MochiMoppel »

misko_2083 wrote: Wed Jun 15, 2022 6:07 pm

Not sure but I think that was an old bug in yad version 0.40.1.

I'm using version 0.36.2 and I wasn't sure if it's a bug at all or a general problem when using such pipe constructs (see here), but then I built a similar construct with Xdialog. Unlike yad this would not leave any processes hanging around when the clock window is closed. So yes, may be a yad bug (and no, using the yad option --kill-parent SIGTERM would not solve the problem. Would terminate the parent but would not stop the while..done subprocess)

Code: Select all

#!/bin/sh
while : ; do 
	echo  XXX 
	date +"%a %d %b %H:%M %S" 
	echo XXX 
	sleep 1 
done | Xdialog --no-buttons -infobox "" 250x30 0
User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

MochiMoppel wrote: Thu Jun 16, 2022 1:38 am
misko_2083 wrote: Wed Jun 15, 2022 6:07 pm

Not sure but I think that was an old bug in yad version 0.40.1.

I'm using version 0.36.2 and I wasn't sure if it's a bug at all or a general problem when using such pipe constructs (see here), but then I built a similar construct with Xdialog. Unlike yad this would not leave any processes hanging around when the clock window is closed. So yes, may be a yad bug (and no, using the yad option --kill-parent SIGTERM would not solve the problem. Would terminate the parent but would not stop the while..done subprocess)

Date is the problem.
This works.

Code: Select all

    while : ; do
        date="$(date +"%a %d %b %H:%M %S")"
        echo "$date"
        sleep 1
    done | yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

User avatar
MochiMoppel
Posts: 1240
Joined: Mon Jun 15, 2020 6:25 am
Location: Japan
Has thanked: 21 times
Been thanked: 440 times

Re: Simple Clock

Post by MochiMoppel »

misko_2083 wrote: Thu Jun 16, 2022 9:17 am

Date is the problem.

Because date is an external command. All external commands piping to yad will cause this problem while Bash builtin commands like echo or printf are OK. Therefore this would also work (in bash 4.2 or newer) and would be more efficient:

Code: Select all

#!/bin/sh
while : ; do
	printf '%(%a %d %b %H:%M %S)T\n'
	sleep 1
done | yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated &
User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

MochiMoppel wrote: Fri Jun 17, 2022 2:08 am
misko_2083 wrote: Thu Jun 16, 2022 9:17 am

Date is the problem.

Because date is an external command

Interesting, I'll have a look at the source code later.

MochiMoppel wrote: Fri Jun 17, 2022 2:08 am

would be more efficient:

Code: Select all

#!/bin/sh
while : ; do
	printf '%(%a %d %b %H:%M %S)T\n'
	sleep 1
done | yad --title=clock --geometry=230x50+420+16 --form --cycle-read --field=": " --no-buttons --undecorated &

Indeed.

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

masinick
Posts: 6
Joined: Mon Jun 13, 2022 6:37 pm
Has thanked: 1 time

Re: Simple Clock

Post by masinick »

I love all of these suggestions.
I found a solution and I have also been experimenting with simple clocks in several scripting languages and tools, including Bash, yad, TCL/Tk, pythons and Conky.

At this point I have several solutions and the comments are correct; there are many clocks available; this is for retirement coding practice so all comments are appreciated; thank you all!

masinick
Posts: 6
Joined: Mon Jun 13, 2022 6:37 pm
Has thanked: 1 time

Re: Simple Clock

Post by masinick »

I hacked the C code, citing our talented coder misco_2083, and I offer back my modified hacks here for anyone interested:

Code: Select all

/* sclock.c */
/* Provided on https://forum.puppylinux.com/viewtopic.php?p=59787#p59787 */
/* by misco_2083 */
/* requires libgtk-3-dev on Debian, pulls in a lot of extra packages */
/* if you use it on antiX */
/* commented and adapted by Brian Masinick */

#include <stdio.h>
#include <time.h>
#include <gtk/gtk.h>

static gboolean
on_timeout (gpointer user_data)
{
  GtkLabel *label = GTK_LABEL (user_data);
  time_t timer;
  char buff[12];
  struct tm* tm_info;

  time (&timer);
  tm_info = localtime(&timer);

  strftime(buff, 12, "%r", tm_info);

  gchar *markup = g_strdup_printf ("<b><span font='Sans Bold 16' foreground='green'>%s</span></b>", buff); 
  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);

  return G_SOURCE_CONTINUE;
}

void destroy_handler (GtkApplication* app, gpointer data)
{
    g_application_quit(G_APPLICATION (data));
}

static gboolean
key_handler (GtkWidget *w, GdkEventKey *ev, gpointer data)
{
  GtkApplication *app = GTK_APPLICATION (data);
  switch (ev->keyval)
    {
    case GDK_KEY_Escape:
        destroy_handler(NULL, app);
        return TRUE;
    }
  return FALSE;
}

static gboolean
button_handler (GtkWidget *w, GdkEventButton *ev, gpointer data)
{
  if (ev->button == 1)
    {
      gtk_window_begin_move_drag(GTK_WINDOW(w),
          ev->button,
          ev->x_root,
          ev->y_root,
          ev->time);
      return TRUE;
    }
  if (ev->button == 3)
    {
      GtkApplication *app = GTK_APPLICATION (data);
      GtkWidget *item, *popup_menu;

      popup_menu = gtk_menu_new ();
      gtk_menu_set_reserve_toggle_size (GTK_MENU (popup_menu), FALSE);
      item = gtk_menu_item_new_with_label ("Exit");
      gtk_widget_show (item);
      gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (destroy_handler), app);
      gtk_menu_popup_at_pointer (GTK_MENU (popup_menu), NULL);
      return TRUE;
    }
  return FALSE;
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget           *window;
  GtkWidget           *grid;
  GtkWidget           *label;
  GtkStyleProvider    *style_provider;
  char                *css_text;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Digital Clock");
  gtk_window_set_default_size (GTK_WINDOW (window), 220, 20);
  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);

  grid = gtk_grid_new ();
  gtk_grid_set_column_homogeneous (GTK_GRID (grid),
                                TRUE);
  gtk_grid_set_row_homogeneous (GTK_GRID (grid),
                                FALSE);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 10);

  label = gtk_label_new(NULL);
  g_timeout_add (1000, on_timeout, label);

  gtk_widget_set_halign (label, GTK_ALIGN_CENTER);

  gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);

  gtk_container_add (GTK_CONTAINER (window), grid);
  gtk_container_set_border_width (GTK_CONTAINER(window),5);

  style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
  gtk_style_context_add_provider (gtk_widget_get_style_context (window),
                                  style_provider,
                                  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

  css_text = g_strdup_printf ("window,\n"
                              "window\n"
                              "{\n"
                              "  background: black;\n"
                              "}\n");

  gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (style_provider),
                                   css_text, -1, NULL);
  g_free (css_text);

  g_signal_connect (G_OBJECT(window), "destroy",
                    G_CALLBACK (destroy_handler), app);
  g_signal_connect (G_OBJECT (window), "key-press-event",
                    G_CALLBACK (key_handler), app);
  g_signal_connect (G_OBJECT (window), "button-press-event",
                    G_CALLBACK (button_handler), app);
  gtk_widget_show_all (window);
}

int
main (int argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.simple_time",
                             G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

 
User avatar
rockedge
Site Admin
Posts: 6553
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 2757 times
Been thanked: 2629 times
Contact:

Re: Simple Clock

Post by rockedge »

@masinick Wow! That works great and really fits the look of this desktop

Screenshot(15).jpg
Screenshot(15).jpg (41.45 KiB) Viewed 2104 times
masinick
Posts: 6
Joined: Mon Jun 13, 2022 6:37 pm
Has thanked: 1 time

Re: Simple Clock

Post by masinick »

Glad you like it! Without the coding expertise and helpful notes from misco_2083 that never would have happened.

We have several other really nice, simple examples too. Thanks to everyone who responded. This has been an educational and fun exercise!

User avatar
misko_2083
Posts: 196
Joined: Wed Dec 09, 2020 11:59 pm
Has thanked: 10 times
Been thanked: 20 times

Re: Simple Clock

Post by misko_2083 »

masinick wrote: Tue Jun 21, 2022 9:22 pm

misco_2083

That guy has a similar username. :D

I've added a some options.
Bacground and border is drawn with cairo. see in help ($ ./sclock --help)
Colors can be in various formats x11 like, black, white, lime, then rgb(r,g,b), rgba(r,g,b,a), #FFFFFF .
--opacity between 0 and 100
--lock prevents moving on left click drag.
Although it's still possible to use Alt_L+L_click drag.
There is a right click menu item to lock/unlock.
--posx --posy and --center to set the initial position
--keep-above to place it on top of window stack, default is to place it bellow all the windows now.
Keep above t may be useful for displaying the clock with timeout.

Code: Select all

timeout 5 ./sclock --keep-above

Code: Select all

#include <time.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>
#include <pango/pango.h>
#include <cairo/cairo.h>

GdkRGBA color_bg;
GdkRGBA color_border;
static gchar *bgcolor = NULL;
static gchar *border_color = NULL;
static gchar *color = NULL;
static gchar *date = NULL;
static gchar *font = NULL;
static gboolean above = FALSE;
static gint border;
static gboolean center = FALSE;
static gboolean lock = FALSE;
static gint opacity;
static gint  posx = 0;
static gint  posy = 0;

static gboolean
on_timeout (gpointer user_data)
{
  GtkLabel *label = GTK_LABEL (user_data);
  GError *error = NULL;
  char *out = NULL;

  time_t timer;
  char buff[64];
  struct tm* tm_info;

  time (&timer);
  tm_info = localtime (&timer);
  strftime (buff, 64, date, tm_info);

  gchar *markup = g_strdup_printf ("<b><span font='%s' foreground='%s'>%s</span></b>",
                                   font, color, buff);
  if (pango_parse_markup (markup,
                         -1,
                          0,
                          NULL,
                          &out,
                          NULL,
                          &error) == FALSE)
  {
    g_printerr ("%s\nSwitching to default values\n", error->message);
    color = "red";
    date = "%r";
    font = "Sans Bold 20";

    gchar *markup = g_strdup_printf ("<span font='%s' foreground='%s'>%s</span>",
                                     font, color, buff);

    if (out)
       free (out);
    g_error_free (error);
  }
  
  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);

  return G_SOURCE_CONTINUE;
}

void destroy_handler (GtkApplication* app, gpointer data)
{
  g_application_quit(G_APPLICATION (data));
}

static void
toggle_lock_position (GtkWidget *menu_item, gpointer user_data)
{
  if (lock == TRUE)
      lock = FALSE;
  else
      lock = TRUE;
}

static gboolean
key_handler (GtkWidget *w, GdkEventKey *ev, gpointer data)
{
  GtkApplication *app = GTK_APPLICATION (data);
  switch (ev->keyval)
    {
    case GDK_KEY_Escape:
        destroy_handler(NULL, app);
        return TRUE;
    }
  return FALSE;
}

static gboolean
button_handler (GtkWidget *window, GdkEventButton *ev, gpointer data)
{
  if ((ev->button == 1) && (lock == FALSE))
    {
      gtk_window_begin_move_drag (GTK_WINDOW(window),
          ev->button,
          ev->x_root,
          ev->y_root,
          ev->time);
      return TRUE;
    }
  if (ev->button == 3)
    {
      GtkApplication *app = GTK_APPLICATION (data);
      GtkWidget *toggle_lock, *exit, *popup_menu;

      popup_menu = gtk_menu_new ();
      gtk_menu_set_reserve_toggle_size (GTK_MENU (popup_menu), FALSE);
      if (lock == TRUE)
          toggle_lock = gtk_menu_item_new_with_label ("Unlock");
      else
          toggle_lock = gtk_menu_item_new_with_label ("Lock");
      gtk_widget_show (toggle_lock);
      exit = gtk_menu_item_new_with_label ("Exit");
      gtk_widget_show (exit);
      gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), toggle_lock);
      gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), exit);
      g_signal_connect (G_OBJECT (toggle_lock), "activate", G_CALLBACK (toggle_lock_position), NULL);
      g_signal_connect (G_OBJECT (exit), "activate", G_CALLBACK (destroy_handler), app);
      gtk_menu_popup_at_pointer (GTK_MENU (popup_menu), NULL);
      return TRUE;
    }
  return FALSE;
}

static void
geometry_hints (GtkWidget *widget,
                    gpointer data)
{
  GdkGeometry         hints;

  hints.min_width = 0;
  hints.max_width = gtk_widget_get_allocated_width (widget);
  hints.min_height = 0;
  hints.max_height = gtk_widget_get_allocated_height (widget);

  gtk_window_set_geometry_hints(
        GTK_WINDOW (widget),
        widget,
        &hints,
        (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
}

static void
draw_handler (GtkWidget *widget,
              cairo_t *cr,
              gpointer user_data)
{
  float alpha;
  float alpha_border;
  if (opacity) {
      alpha = alpha_border = (float) opacity / 100;
  }
  else {
      alpha = color_bg.alpha;
      alpha_border = color_border.alpha;
  }
  
  cairo_set_source_rgba (cr, color_bg.red, color_bg.green, color_bg.blue,  alpha);
  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); 
  cairo_paint(cr);

  if (border) {
     if (border_color == NULL) {
         cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.7);
     }
     else {
         cairo_set_source_rgba (cr, color_border.red, color_border.green, color_border.blue,  alpha_border);
      }
      cairo_rectangle(cr, border / 2, border / 2, gtk_widget_get_allocated_width (widget) - border,
                                                gtk_widget_get_allocated_height (widget) - border);
      cairo_set_line_width(cr, border);
      cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); 
      cairo_stroke(cr); 
  }
}

static void
composited_changed (
  GtkWidget *widget,
  gpointer user_data)
{
  GdkScreen           *screen;
  GdkVisual           *visual;

  screen = gdk_screen_get_default();
  visual = gdk_screen_get_rgba_visual(screen);
  if (visual != NULL && gdk_screen_is_composited(screen))
      gtk_widget_set_visual(widget, visual);
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget           *window;
  GtkWidget           *grid;
  GtkWidget           *label;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Simple Clock");
  gtk_window_set_default_size (GTK_WINDOW (window), 10, 10);
  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
  gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
  gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
  gtk_widget_set_app_paintable (window, TRUE);
  composited_changed (window, NULL);
  if (center == TRUE)
      gtk_window_set_position(GTK_WINDOW(window),
                              GTK_WIN_POS_CENTER_ALWAYS);
  if (above == TRUE) {
      gtk_window_set_keep_above (GTK_WINDOW(window), TRUE);
  }
  else {
      gtk_window_set_keep_below (GTK_WINDOW(window), TRUE);
  }

  grid = gtk_grid_new ();
  gtk_grid_set_column_homogeneous (GTK_GRID (grid),
                                TRUE);
  gtk_grid_set_row_homogeneous (GTK_GRID (grid),
                                FALSE);
  gtk_grid_set_row_spacing (GTK_GRID (grid), 10);

  label = gtk_label_new (NULL);
  g_timeout_add (1000, on_timeout, label);
  gtk_widget_set_halign (label, GTK_ALIGN_CENTER);

  gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
  gtk_container_add (GTK_CONTAINER (window), grid);
  gtk_container_set_border_width (GTK_CONTAINER (window), 8);

  g_signal_connect (G_OBJECT(window), "destroy",
                    G_CALLBACK (destroy_handler), app);
  g_signal_connect (G_OBJECT (window), "key-press-event",
                    G_CALLBACK (key_handler), app);
  g_signal_connect (G_OBJECT (window), "button-press-event",
                    G_CALLBACK (button_handler), app);
  g_signal_connect (G_OBJECT (window), "size-allocate",
                    G_CALLBACK (geometry_hints), NULL);
  g_signal_connect (G_OBJECT (window), "draw",
                    G_CALLBACK (draw_handler), NULL);
  g_signal_connect (G_OBJECT (window), "draw",
                    G_CALLBACK (draw_handler), NULL);
  g_signal_connect (G_OBJECT (window), "composited-changed",
                    G_CALLBACK (composited_changed), NULL);
  gtk_widget_show_all (window);

  if ((posx != 0) || (posy != 0))
     gtk_window_move (GTK_WINDOW (window), posx, posy);
}

static int
get_options (int argc,
             char *argv[])
{
  static
    GOptionEntry option_entries[] = {
    { "bgcolor",       0, 0, G_OPTION_ARG_STRING,  &bgcolor,
       "Specify window background color, black, #000, rgb(r,g,b), rgba(r,g,b,a)", "COLOR" },
    { "border",  0, 0, G_OPTION_ARG_INT,   &border,
       "Draw window border, same as bgcolor", "COLOR" },
    { "border-color",  0, 0, G_OPTION_ARG_STRING,   &border_color,
       "Set border color", "COLOR" },
    { "center",  0, 0, G_OPTION_ARG_NONE,   &center,
       "Place window at the center of the screen", NULL },
    { "color",       0, 0, G_OPTION_ARG_STRING,  &color,
       "Specify color of the label, white, #FFFFFF", "COLOR" },
    { "date",        0, 0, G_OPTION_ARG_STRING,  &date,
       "Specify display time, e.g. %a %b %d/%m/%Y %H:%M:%S but not 'now", "STRING" },
    { "font",        0, 0, G_OPTION_ARG_STRING,  &font,
       "Specify font to use", "FONT" },
    { "keep-above",  0, 0, G_OPTION_ARG_NONE,   &above,
       "Keep window above, default is to keep window below", NULL },
    { "lock",  0, 0, G_OPTION_ARG_NONE,   &lock,
       "Lock position", NULL },
    { "opacity",  0, 0, G_OPTION_ARG_INT,   &opacity,
       "Set window opacity, compositing must be enabled first", NULL },
    { "posx",        0, 0, G_OPTION_ARG_INT,    &posx,
       "Specify X position to use", "INT" },
    { "posy",        0, 0, G_OPTION_ARG_INT,   &posy,
       "Specify Y position to use", "INT" },
    { NULL }
  };
              
  GOptionContext *option_context;
  GError *error = NULL;

#if (!GLIB_CHECK_VERSION (2, 36, 0))
  g_type_init ();
#endif

  option_context = g_option_context_new (NULL);
  g_option_context_add_main_entries (option_context,
                                     option_entries,
                                     NULL);
  if (g_option_context_parse (option_context,
                              &argc,
                              &argv,
                              &error) == FALSE) {
    g_printerr ("%s\n", error->message);
    g_error_free (error);
    return 1;
  }
  if (bgcolor != NULL) {
     if (gdk_rgba_parse (&color_bg, bgcolor) == FALSE) {
         g_printerr ("Unknown color: %s\n", bgcolor);
         return 1;
     }
  }
  if (border_color != NULL) {
      if (gdk_rgba_parse (&color_border, border_color) == FALSE) {
          g_printerr ("Unknown color: %s\n", border_color);
          return 1;
      }
  }
  if (opacity < 0 || opacity > 100) {
      g_printerr ("Opacity must be between 0 and 100: %d\n", opacity);
      return 1;
  }
  if (color == NULL)
      color = "red";
  if (date == NULL)
      date = "%r";
  if (font == NULL)
      font = "Sans Bold 20";
  g_option_context_free (option_context);

  return 0;
}

int
main (int argc,
      char **argv)
{
  int status;
  GtkApplication *app;
  gboolean opts;

  opts = get_options (argc, argv);

  if (opts == 1)
     return 1;

  app = gtk_application_new ("org.gtk.simple_clock",
                             G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

If we resize the buffer it would be possible to use several colors and font sizes with pango markup.

Code: Select all

# in terminal
_date="%a, %b %d, %Y
<span color='#cfcfcf'>%r</span>"
./sclock--keep-above --date="${_date}" --border=2 --border-color=blue --bgcolor=grey

Which currently gives

sclock.png
sclock.png (6.01 KiB) Viewed 2086 times

EDIT:
Just had an idea to place it next to the xfce4-panel.
xdotool helps to find the position (Y and Y).

Do you want to exit the Circus? The Harsh Truth
https://www.youtube.com/watch?v=ZJwQicZHp_c

User avatar
rockedge
Site Admin
Posts: 6553
Joined: Mon Dec 02, 2019 1:38 am
Location: Connecticut,U.S.A.
Has thanked: 2757 times
Been thanked: 2629 times
Contact:

Re: Simple Clock

Post by rockedge »

can I include sclock in KLV's? Include it as feature.

Compiled in KLV-Airedale (install gtk+-devel)
Started with : sclock --color=orange in a .desktop file
Could use a shell script to set options and start or modify the .desktop file itself.
Should probably just make a sclock-config GUI for fun

Screenshot_2022-06-23_15-13-37.jpg
Screenshot_2022-06-23_15-13-37.jpg (56.95 KiB) Viewed 2023 times
Screenshot_2022-06-23_15-29-42.jpg
Screenshot_2022-06-23_15-29-42.jpg (64.33 KiB) Viewed 2022 times
Post Reply

Return to “Scripts”