Page 7 of 9

Posted: Tue 16 Dec 2014, 00:22
by technosaurus
honestly, _I_ think 0644 is easier to read, since the octal numbers represent USER,GROUP,ALL and for each one, the binary bits represent READ, WRITE, EXEC permissions... so 0644 is user read/write and world read permission. Most Unix/Linux guys that write C would probably be the same.

Posted: Tue 16 Dec 2014, 03:20
by torios
Hi,
I was also looking through your code to try to get my mind around the genius of what you have done. There are a few things I don't fully understand based on the variable names. I'd like to ask you about them, but I feel like it would clutter the thread can I contact you outside of the forum to ask about this? If not I will continue through the code and ask here when I absolutely am stumped. Thanks for working with me on this, I really appreciate all your tireless efforts! I think your programs have incredible value and will bring some of the Puppy goodness I am so fond of to Ubuntu.

Part of the reason why I want to understand this is the move to
/sys/class/power_supply/BAT0
and the different files used. I want to be able to handle both (eventually).

Posted: Tue 16 Dec 2014, 04:57
by technosaurus
May as well ask it here. I know some other people wanted some C examples. Hopefully I can translate my naming system back to human. I've been meaning to learn doxygen style inline comments anyhow.

Posted: Tue 16 Dec 2014, 22:31
by torios
Well, I'll just paste the code here to show you what I did to make things easier for me to figure out things. I am still trying to figure it all out.
Basically I haven't figured out the ones that don't have long names...
there are a few things I didn't translate into a longer name yet that I already know... but certain things like:
bp
fd
i
chg (is this charged?)
d
p
s
ss
r
sz... I understand this is the size, but it is not immediately clear which size.

Just some minor things. I tried to name things here in the normal c naming convention...

Code: Select all

/*
 * proc2imgd.c
 *
 * Copyright 2014 Brad Conroy - released to public domain
 *
 */
#include <fcntl.h> //open
#include <unistd.h> //read,write
#include <string.h> //strstr, strlen
#include <stdlib.h> //getenv
#include <sys/stat.h> //mkdir
#include <sys/statfs.h> //for statfs
#include <stdint.h> //for *int*_t
#include <libgen.h> //basename

#define strcpyALL(buf, l, ...) do{ \
   char *bp=(char*)(buf); \
   const char *s, *a[] = { __VA_ARGS__,NULL}, **ss=a; \
   while((s=*ss++)) \
      while((*s)&&((--l) >0)) \
         *bp++=*s++; \
   *bp=0; \
}while(0)

static inline int ispad(int X){return (X)==' '||(unsigned)(X)-'\t'<5;}
#define isnum(X)   ((unsigned)(X)-'0' < 10)

int stod(const char *s){ //like atoi but no negatives and only for small numbers
   int r=0;
   while (ispad(*s))s++;
   while (isnum(*s)) r = 10*r + (*s++ - '0');
   return r;
}


static void dtos(int64_t d, char *buf){ //like itoa, but you pass the buffer
   int p=0;
   if (0>d) {
      buf[p++]='-';
      d=-d;
   }
   if (0==d){
      buf[p++]='0';
      buf[p]=0;
      return;
   }
   int64_t i=1000000000000000000;
   while (i > d) i/=10;
   while (0<i){
      buf[p++]=('0'+(d/i));
      if (i<=d) d=d%i;
      i/=10;
   }
   buf[p]=0;
   return;
}


//GLOBALs

static char //default colors TODO read from config file
   *line_color="#000", //lines, outlines, strokes, etc...
   *foreground_color="#AAA", //foreground items ... usually the actual image
   *background_color="#444", //background color ... todo match with theme
   *text_color="#FFF", //use a text color that will work with both the bg and fg
   *charge_color="#0F0", //usually green indicates a preferred status
   *discharge_color="#F00", //usually red denotes less preferred status
   *icon_width="22px", //set for standard tray size
   *icon_height="22px",
   buf[4096]={0},
   HOME[64];

static const char
   svg_header[]="<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" \tviewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" ",
   svg_footer[]="</svg>\n",
   svg_width[]=" width=\"",
   svg_height[]=" height=\"",
   svg_x[]=" x=\"",
   svg_y[]=" y=\"",
   svg_quote[]="\" ",
   svg_tag_end[]=">\n",
   svg_tag_close[]="/>\n",
   svg_rect[]="\t<rect ",
   svg_fill[]=" fill=\"",
   svg_text[]="\t<text ",
   center[]=" text-anchor=\"middle\"",
   rotate[]=" transform=\"rotate(90 50,50)\"",
   svg_font_size[]=" font-size=\"",
   svg_text_close[]="</text>\n";   

#if 0
static inline void do_wifi(const char *wlan){
const char upload[]="M71,29L99,2L99,27L92,18,75,34",
   download[] = "M98,0L70,27L70,5L77,12,90,0",
     updown[] = "<path d=\"%s\" fill=\"%s\" stroke=\"%s\"/>\n",
    sigqual[] = "<circle cx=\"0\" cy=\"100\" r=\"%d\" stroke=\"%s\" stroke-width=\"%d\" fill=\"%s\" fill-opacity=\"0.5\" />\n";

   static int lastrcv=0, lastxmt=0;
   int rcv,xmt,quality;

   FILE *wireless = fopen("/proc/net/wireless", "r");
   char dev[8], status[8], link[8], level[8], noise[8];
   fgets(dummy, 99, wireless);
   fgets(dummy, 99, wireless);
   while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
      if (!strcmp(argv[1],ip))
         printf("%s\n",dev);
   return 0;
   
}
#endif

static inline void do_fs(char *fname, int *lastsz){
   char extensions[]=" kMGTE", sz[8], *bp, outfile[64];
   size_t ext=0, len=sizeof(outfile);
   int fd;
   if (!fname) return;
   struct statfs st;
   if ((statfs(fname, &st))<0) return;
   uint64_t left = st.f_bfree * st.f_bsize;
   while(left>1024){
      left>>=10; //same as /=1024
      ++ext;
   }
   if ((int)left == *lastsz) return; //try not to trigger unnecessary redraw
   else *lastsz=left;
   dtos(left,sz);
   bp=sz+strlen(sz);
   if (ext) *bp++=extensions[ext];
   *bp++='b';*bp++='\n';*bp++=0;
   strcpyALL(outfile, len,HOME,(const char *)basename(fname),".svg");
   if (( fd = open(outfile,O_WRONLY|O_CREAT|O_TRUNC,0644 ))<0) return;
   len=sizeof(buf);

   strcpyALL(buf, len,
	svg_header,
	svg_width,
	icon_width,
	svg_quote, svg_height,icon_height, svg_quote, svg_tag_end,

	svg_rect, svg_width, "100%\"", svg_height, "100%\"",
	svg_fill, background_color, svg_quote,
	svg_tag_close,

	svg_text, svg_x, "50\"", svg_y, "50\"",
	svg_fill, text_color, svg_quote, svg_font_size, "30",
	svg_quote, center, svg_tag_end,   "\t\t",
	sz, "\n",
	svg_text_close,
	svg_footer
   );   
   write(fd,buf,strlen(buf));
   close(fd);
   return;
}


static inline void do_bat(char *batt, int *percent){
   const char BAT[]="/proc/acpi/battery/";
   char *bp=(char *)buf, fname[32], dy[24], ht[24];
   int i, fd, len=sizeof(buf), chg=0, full_capacity=-1, discharging_capacity=-1, remaining_capacity=-1;

/* We _could_ just do this block once, but last full capacity may change */
   i=sizeof(fname);
   strcpyALL(fname, i, BAT, batt, "/info");
   if (( fd = open(fname,O_RDONLY,0644 ))<0) return;
   len = read(fd,buf,len);
   close(fd);
   if (len < 0) return;
   buf[len]=0; //for strstr
   if (!(bp = strstr(buf,"design capacity:"))) return;
   else discharging_capacity = stod(&bp[25]);
   if ((bp = strstr(buf,"last ful"))) full_capacity = stod(&bp[25]);
   else full_capacity = discharging_capacity;

   i=sizeof(fname);
   strcpyALL(fname,i,BAT,batt,"/state");
   if (( fd = open(fname,O_RDONLY,0644 ))<0) return;
   i = read(fd,&(buf[len]),sizeof(buf)-len);
   close(fd);
   if (i < 0) return;
   else buf[(len+=i)]=0;

   if ((bp = strstr(buf,"remain")) && (i = stod(&bp[25])) == remaining_capacity) return;
   else remaining_capacity = i;
   if ((bp = strstr(buf,"charging st"))) chg=bp[25]-'c';
   i=sizeof(fname);
   i=(100*remaining_capacity)/((remaining_capacity>full_capacity)?discharging_capacity:full_capacity);
   if (*percent==((chg)?-i:i)) return; //try not to trigger unnecessary redraw
   else *percent = i;
   strcpyALL(fname,i,HOME, batt, ".tt");
   if (( fd = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644 ))<0) return;
   len=write(fd,buf,len);
   close(fd);
   i=sizeof(fname);
   strcpyALL(fname,i,HOME, batt, ".svg");
   if (( fd = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644))<0) return;
   dtos(100-*percent,dy);
   dtos(*percent,ht);
   if (chg) *percent=-*percent;
   len=sizeof(buf);

   strcpyALL(buf, len,
	svg_header, svg_width, icon_width, svg_quote,
	svg_height, icon_height, svg_quote, svg_tag_end,

	svg_rect, svg_x, "20%\"",
	svg_width, "60%\"",
	svg_height, "100%\"",
	svg_fill, background_color, svg_quote, svg_tag_close,

	svg_rect, svg_x, "20%\"",
	svg_width, "60%\"",
	svg_y, dy, svg_quote,
	svg_height, ht, svg_quote,
	svg_fill, (chg)?discharge_color:charge_color, svg_quote, svg_tag_close,

	svg_text, svg_x, "50\"",
	svg_y, "50\"",
	svg_fill, text_color, svg_quote,
	svg_font_size, "30", svg_quote,
	center, rotate, svg_tag_end,   "\t\t", batt, "\n",
	svg_text_close,
	svg_footer
   );
   write(fd,buf,sizeof(buf)-len);
}

int main(int argc, char **argv){
   int len=sizeof(HOME),
      state[argc/2];
   strcpyALL(HOME,len,getenv("HOME"),"/.sit/");
   mkdir(HOME,0422);
   do{
      do_fs("/mnt/save",&state[0]);
      do_bat("BAT0",&state[1]);
      //do_wifi("wlan0",&state[2]); //todo
   }while(!sleep(1));
   return 0;
} 

Posted: Wed 17 Dec 2014, 00:15
by technosaurus
torios wrote:

Code: Select all

bp ... things that end in p are typically pointers, in this case to buf
fd ... file descriptor (typically anything that ends with fd)
i ... just an integer for temporary use
chg (is this charged?) ... actually I should have renamed it dchg
      (it is a 1 when discharging or a 0 when charged or charging)
       I used the fact that their ascii values are sequential
d    I didn't want a full itoa function so used the printf format specifiers and called it dtos (int to string)
p    used inside [] for position (I wrote it before I really understood pointers)
s    string
ss   2d array of strings or pointer to array of strings
r     the return value
sz... follow the loop that fills it (it converts integer to string with b,K,M,G,...)

Posted: Wed 17 Dec 2014, 03:26
by torios
Thank you, that clear up so much for me!
I was not aware of some of those naming conventions, for example, I usually start my pointer variable names with p.
So, I would (generally speaking) name bp, something like pBuffer.
Though I have renamed it buffer_pointer in this code. I am very keen to learn more about how this works and understand the 'C' way of dong things... I do use some similar things, and and I definitely use some C libraries, but there is a lot that is very different in the overall way things are done. I may very well have more questions, but unravelling the mystery of the variable names (and knowing the general naming conventions you use) will definitely help me to expand this later. It is also a good lesson in learning how C is different and gives me a glimpse into the strengths of C.
Thank you so much!!

Posted: Wed 17 Dec 2014, 22:32
by torios
Well, I have successfully built this in a few situations and I have no errors!!
So, now for the basic question. How do I use this correctly with sdesk?
I have been looking at the code some and trying to figure out exactly what I need and where I need it... but I am a little stumped at how to include this with sdesk...

for my scripts that I have put in the panel I use the normal format of
sdesk -t /path/to/icon "tooltip" "exec" "" (unless I want a second action with the other click...)

as far as I know (from my blossoming understanding of C) your program dynamically generates the svg and tooltip files... however since I am using Ubuntu rather than Puppy there may be some things I need to modify (like the permission of the sit folder in HOME for example :)
Of course there is also no /mnt/save so I could do something else like /home
strcpyALL(fname,i,HOME, batt, ".tt");
So basically ~/.sit/BATT0.tt is this right?
and much the same for the svg.

Sorry if my questions sometimes seem elementary, I am still learning.
And again thank you for your efforts to help me!

Posted: Thu 18 Dec 2014, 15:26
by technosaurus
from the post with the latest tarball:
//http://murga-linux.com/puppy/viewtopi ... 677#714677
technosaurus wrote: -i <include files>
-b <background imagge>
-t <status icon> <tooltip> <left click action> <right click action>
the -t option can be used multiple times,
so the c program is running and spitting out .svg and .tt files

sdesk -t /path/to/BAT0.svg /path/to/BAT0.tt abiword geany [-t ...]

Posted: Wed 24 Dec 2014, 03:10
by torios
Hi,
thanks so much! in retrospect I feel that I was asking something rather silly :)
In my test of it, it seems to use about 4MB for proc2imgd and 3MB for sdesk. If I can get a full network monitor in there and not use much more RAM, this will be extremely useful for many reasons.

I really like the tooltip display, very handy! I would like to change the SVG though.

I am thinking it would be nice to have something of a configuration file for this battery program.... And if there is an icon theme in use use the network icons from that theme, or be able to specify a certain icon theme.
This way the program would be able to fit visually with a variety of colour schemes. If I have time to do anything with your program I will let you know... I have been very busy trying to finish up some things with my FLTK JWM settings program. It is starting to be very handy these days :)

Posted: Wed 24 Dec 2014, 19:21
by technosaurus
When I run my compile, it uses about 4kb not Mb, but I have my own c implementation that I use.

I may set something up to use a configure directory with 1 setting per file. That makes changing individual settings easier and allows us to use inotify to change things on the fly like SIT/Sdesk do with icons and tooltips. Most programs use a single flat or xml file and thus have to parse and do logic for everything and resave or rerender everything any time one thing is changed... If you want to do many changes, you have to do them in batches or it ends up looking like Christmas lights. As long as the content of individual configuration files is less than 60 bytes, it doesn't even allocate more than a symlink. I already have the code for it in my C macros thread.

Posted: Mon 29 Dec 2014, 22:18
by torios
This sounds good to me. I have been pretty busy checking some other things out... mainly networking.

I know there is some code in there for showing a network indicator.. is frisbee the main networking program for Puppy?

I downloaded a version of it to look through. (not trying to hijack this thread). If there is a different networking program used in Puppy could you point me to it? I'd ultimately like to use sdesk for everything, as I don't like NetworkManager in a lightweight system. Wicd is not being maintained anymore, and there are not too many other options (in the Ubuntu repositories).
If I can adapt the Puppy scripts for Ubuntu, then I could potentially combine this with sdesk.

I do think it is already a simpler battery indicator than using a power management system, and it can be extended with other 'on click' actions.

Posted: Thu 01 Jan 2015, 01:22
by NeroVance
This looks quite impressive, I'll need to look into this technosaurus.

Posted: Fri 02 Jan 2015, 13:28
by torios
It is really quite nice. It runs very light indeed!
I especially like that sdesk can handle running any script. This is one of the most amazing tray 'applets' on any desktop!
technosaurus has really done an amazing job here!

Posted: Sun 08 Feb 2015, 11:52
by Argolance
Bonjour,
Thank you for this very nice and useful 'applet'! :D

Question:
I was wondering why no action is assigned to the middle button of the mouse (If 'sit' could do more, it could do less as well)?
So, can 'sit' be modified to make the middle button available and how?

Cordialement.

Posted: Tue 10 Feb 2015, 07:21
by technosaurus
Argolance wrote:why no action is assigned to the middle button of the mouse?
Because the GTK devs felt it necessary to write 2 additional event handlers for the status icon (popup and activate) instead of just using button press events.
Could this be possible and how?
Only by completely rewriting an alternative statusicon widget.

FWIW GTK devs do this a lot (add extra code that reduces functionality)
... another example of such is GtkIconView. It could make a perfect desktop icon replacement in ~10 lines except that they added code to the widget itself that makes the background solid white... you can only change the color, not add a background image.

Posted: Tue 10 Feb 2015, 17:41
by musher0
technosaurus wrote:(...)
FWIW GTK devs do this a lot (add extra code that reduces functionality)
... another example of such is GtkIconView. It could make a perfect desktop icon replacement in ~10 lines except that they added code to the widget itself that makes the background solid white... you can only change the color, not add a background image.
A bureaucratic process has to be involved; otherwise the world be heading nowhere. :twisted: :wink:

Posted: Tue 10 Feb 2015, 18:22
by Argolance
Bonsoir,
Thanks.
technosaurus wrote:FWIW GTK devs do this a lot (add extra code that reduces functionality)
Why? Very strange indeed!: It is a pity...
Only by completely rewriting an alternative statusicon widget.
Perhaps 'yad' could be used to make such a 'simple icon tray' and should offer more capabilities?
musher0 wrote:A bureaucratic process has to be involved; otherwise the world be heading nowhere
?? :roll:
It is already the case and this is why the world is "heading nowhere"!
(I'm probably missing something, but I don't really see the connection with the subject of this thread). :oops:

Cordialement.

Posted: Wed 11 Feb 2015, 01:31
by torios
I like FLTK quite a bit, it keeps improving and making things easier, rather than removing functionality.
You can make very small programs easily with FLUID to design the UX.

Might be something for other posters here to consider.

Posted: Fri 13 Feb 2015, 07:43
by technosaurus
Argolance wrote:Perhaps 'yad' could be used to make such a 'simple icon tray' and should offer more capabilities?
Yad is also gtk based, so no.
torios wrote:I like FLTK quite a bit, it keeps improving and making things easier, rather than removing functionality.
You can make very small programs easily with FLUID to design the UX.

Might be something for other posters here to consider.
Fltk doesn't have a tray icon widget.

tcl/tk does
qt does

I did find an old X11 example here :

Code: Select all

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>

typedef enum systray_opcode_tag {
        SYSTEM_TRAY_REQUEST_DOCK   = 0,
        SYSTEM_TRAY_BEGIN_MESSAGE  = 1,
        SYSTEM_TRAY_CANCEL_MESSAGE = 2
} systray_opcode_t;

void send_message(
        Display *disp,
        Window dest,
        systray_opcode_t message,
        long data1,
        long data2,
        long data3)
{
        XEvent ev;

        memset( &ev, 0, sizeof(ev)) ;
        ev.xclient.type = ClientMessage ;
        ev.xclient.window = dest;
        ev.xclient.message_type = XInternAtom( disp, "_NET_SYSTEM_TRAY_OPCODE", False );
        ev.xclient.format = 32 ;
        ev.xclient.data.l[0] = CurrentTime ;
        ev.xclient.data.l[1] = message ;
        ev.xclient.data.l[2] = data1 ;
        ev.xclient.data.l[3] = data2 ;
        ev.xclient.data.l[4] = data3 ;
/* XXX handle error XXX */
        XSendEvent( disp, dest, False, NoEventMask, &ev) ;
        XSync( disp, False) ;
}


int main()
{
        Display  *disp ;
        Window  tray ;
        Window  icon ;
        Window  container = None ;
        GC  gc ;
        XEvent  ev ;
        int  icon_size = 22 ;

        disp = XOpenDisplay(NULL) ;

/* get system tray(as a embedder). */
/* XXX exec tray if it is nonexistent */
/* XXX assuming screen is 0 */
        tray = XGetSelectionOwner( disp,
                                  XInternAtom(disp, "_NET_SYSTEM_TRAY_S0", True) );
        printf("tray window = %p\n", tray) ;

/* create system tray icon window */
        icon = XCreateSimpleWindow( disp, DefaultRootWindow(disp),
                                    0,0, icon_size,icon_size, 0, 0xFF,0x0);
        printf("icon window = %p\n", icon) ;

/* select all of masks for debugging */
        XSelectInput( disp, icon, (OwnerGrabButtonMask << 1) -1 );

/* create GC */
        gc = XCreateGC( disp, icon, 0, NULL);
        XSetForeground( disp, gc, 0xFF) ;

/* set minimum size */
        {
                XSizeHints *hints;

                hints = XAllocSizeHints() ;
                hints->flags = PMinSize ;
                hints->min_width=icon_size;
                hints->min_height=icon_size;
                XSetWMNormalHints( disp, icon, hints);
                XFree( hints);
        }

/* set xembed infos */
        {
                Atom xa_xembed_info ;
                unsigned int buffer[2];

                xa_xembed_info = XInternAtom( disp, "_XEMBED_INFO", False) ;

                buffer[0]=0; /* ver 0 (0:0?) */
                buffer[1]=1; /* request mapping */
                XChangeProperty( disp, icon, xa_xembed_info,
                                 xa_xembed_info, 32, PropModeReplace,
                                 (unsigned char *)buffer, 2);
        }

/* request embedding */
        send_message( disp, tray, SYSTEM_TRAY_REQUEST_DOCK, icon,0,0);

        while(1){
                XNextEvent( disp, &ev);
                printf("type %d\n", ev.type);
                switch(ev.type)
                {
                case Expose:           /*12*/
                        XClearWindow( disp, icon);
                        XDrawLine( disp, icon, gc, 1,1, icon_size-1,icon_size-1) ;
                        printf("\texpose\n");
                        break;
                case VisibilityNotify: /*15*/
                        printf("\tvisible\n");
                        break;
                case MapNotify:        /*19*/
                        printf("\tmapped\n");
                        break;
                case ReparentNotify:    /*21*/
                        printf("\twindow %p\n", ev.xreparent.parent);
                        break;
                case ResizeRequest:    /*25*/
                        printf("\twidth %d\n", ev.xresizerequest.width);
                        printf("\theight %d\n", ev.xresizerequest.height);
                        if( ev.xresizerequest.width > ev.xresizerequest.height)
                                icon_size = ev.xresizerequest.height ;
                        else
                                icon_size = ev.xresizerequest.width ;
                        XResizeWindow( disp, icon, icon_size, icon_size);
                        if(container)
                                XResizeWindow( disp, container, icon_size, icon_size);
                        break;
                case PropertyNotify:    /*29*/
                        printf("\tatom %s\n", XGetAtomName( disp, ev.xproperty.atom));
                        break;
                case ClientMessage:    /*33*/
                        printf("\twindow %p\n", ev.xclient.window);
                        printf("\ttype %s\n", XGetAtomName( disp, ev.xclient.message_type));

                        printf("\ttime 0x%X\n", ev.xclient.data.l[0]);
                        printf("\tmajor 0x%X\n", ev.xclient.data.l[1]);
                        printf("\tdetail 0x%X\n", ev.xclient.data.l[2]);
                        printf("\tdata1 0x%X\n", ev.xclient.data.l[3]);
                        printf("\tdata2 0x%X\n", ev.xclient.data.l[4]);
/* container window could be got from ReparentNotify */
                        if( ev.xclient.data.l[1] == 0)
                                container = ev.xclient.data.l[3] ;
                        break;
                default:
                        ;
                };
        }
}
It would be a good exercise to adapt this to xcb or netsurf framebuffer and possibly use stb_image and libtinysvg for the images.

Posted: Fri 13 Feb 2015, 23:39
by torios
Hi,
I simply meant that FLTK is great for making simple programs to use with sdesk. It is very easy to mockup a design and keep all the code in FLUID. This makes it very simple for others to adapt the UX for their own purposes, or change it.
I have taken to causing my programs to read the .jwmrc file to set colors.

sdesk does all the work to set the tray icon, so FLTK does not need to :)

Plus FLTK is not as crazy as GTK. It seems like more and more things change and become more complex (for no reason?) with each release.