From e42512c034fd17a4a0b33595b2de65d979878f5a Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Mon, 25 Apr 2022 19:03:50 -0700 Subject: [PATCH 1/8] [amiwm] Don't use global scr for this iteration The global scr is a bit of an overused thing. It's definitely not needed here. Don't use it here. --- main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main.c b/main.c index 6c8f90f..a6f43d1 100644 --- a/main.c +++ b/main.c @@ -820,9 +820,12 @@ void internal_broker(XEvent *e) static void update_clock(void *dontcare) { + Scrn *scr; + if(server_grabs) return; call_out(prefs.titleclockinterval, 0, update_clock, dontcare); + scr = get_front_scr(); do { redrawmenubar(scr->menubar); From 18e858ae8069ed2e0db4bf1cac2a312ade457ebf Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Mon, 25 Apr 2022 21:28:49 -0700 Subject: [PATCH 2/8] [amiwm] MVP for initial battery stuff Totally not ready for prod, but at least I'm making progress figuring out how to add extra bits to this thing. * add a second widget to the menu bar, next to the title bar * add a new module command to update the battery information * add a freebsd specific Battery module, not linked into the build right now. * amiwm will print out whenever we get battery information from the module. Right now I'm trying to figure out how to get some kind of periodic background event into the module main loop. Launcher does it using cx_broker(), but I dunno if I can adapt that pattern here. --- Makefile.in | 5 ++- battery_module.c | 69 +++++++++++++++++++++++++++++++++++++ libami/Makefile.in | 4 +-- libami/libami.h | 3 ++ libami/mdbattery.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ menu.c | 45 ++++++++++++++++++++++-- module.c | 21 ++++++++++++ module.h | 9 +++++ 8 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 battery_module.c create mode 100644 libami/mdbattery.c diff --git a/Makefile.in b/Makefile.in index 3751322..5e323c6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -171,6 +171,9 @@ Filesystem : filesystem.o $(LIBAMI) Keyboard : kbdmodule.o kbdlexer.o $(LIBAMI) $(CC) -o Keyboard kbdmodule.o kbdlexer.o $(LIBS) +Battery : battery_module.o $(LIBAMI) + $(CC) -o Battery battery_module.o $(LIBS) + Launcher : launchermodule.o $(LIBAMI) $(CC) -o Launcher launchermodule.o $(LIBS) @@ -181,7 +184,7 @@ localetest : localetest.o $(LIBAMI) $(CC) -o localetest localetest.o $(LIBS) clean : lib_clean - $(RM) core $(PROGS) $(LIBAMI) Keyboard Launcher *.o + $(RM) core $(PROGS) $(LIBAMI) Keyboard Battery Launcher *.o $(RM) lex.yy.c lex.c y.tab.c y.tab.h gram.h gram.c $(RM) kbdlexer.c kbdmodule.h kbdmodule.c $(RM) config.log diff --git a/battery_module.c b/battery_module.c new file mode 100644 index 0000000..272b4a6 --- /dev/null +++ b/battery_module.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +#include + +#define APM_DEV "/dev/apm" + +#include "libami.h" + +/* + * Test battery module for FreeBSD, using APM. + */ + +void docmd(XEvent *e, void *callback) +{ + ((void (*)(Window))callback)(e->xany.window); +} + +static char *progname; +static int apm_fd = -1; + +static bool +get_apm_info(void) +{ + int ret; + struct apm_info info; + + ret = ioctl(apm_fd, APMIO_GETINFO, &info); + if (ret < 0) { + warn("ioctl (APMIO_GETINFO)"); + return false; + } + + printf("Battery life: %d\n", info.ai_batt_life); + printf("Battery time: %d\n", info.ai_batt_time); + printf("Battery AC: %d\n", info.ai_acline); + + md_update_battery(info.ai_batt_life, info.ai_batt_time, + info.ai_acline); + + return true; +} + +int main(int argc, char *argv[]) +{ + char *arg=md_init(argc, argv); + + progname=argv[0]; + + apm_fd = open(APM_DEV, O_RDONLY); + if (apm_fd < 0) { + err(127, "open"); + } + + /* + * XXX TODO: how do I actually get this to run once + * a second in the main loop? + */ + get_apm_info(); + + md_main_loop(); + + close(apm_fd); + return 0; +} diff --git a/libami/Makefile.in b/libami/Makefile.in index c53816f..dc27c58 100644 --- a/libami/Makefile.in +++ b/libami/Makefile.in @@ -19,12 +19,12 @@ LN_S = @LN_S@ RM = -rm -f OBJS = drawinfo.o module.o broker.o eventdispatcher.o mdscreen.o \ - mdicon.o mdwindow.o kbdsupport.o hotkey.o \ + mdicon.o mdwindow.o kbdsupport.o hotkey.o mdbattery.o \ lists.o readargs.o iconlib.o iconutil.o error.o strutil.o \ iffparse.o gadget_button.o gadget_textbox.o gadget_textinput.o SRCS = drawinfo.c module.c broker.c eventdispatcher.c mdscreen.c \ - mdicon.c mdwindow.c kbdsupport.c hotkey.c \ + mdicon.c mdwindow.c kbdsupport.c hotkey.c mdbattery.c \ lists.c readargs.c iconlib.c iconutil.c error.c strutil.c \ iffparse.c gadget_button.c gadget_textbox.c gadget_textinput.c diff --git a/libami/libami.h b/libami/libami.h index 160dbea..5e9e662 100644 --- a/libami/libami.h +++ b/libami/libami.h @@ -389,6 +389,9 @@ extern Pixmap md_image_to_pixmap(Window, unsigned long, struct Image *, int, int, struct ColorStore *); extern char *get_current_icondir(void); +/* mdbattery.c */ +extern void md_update_battery(int pct, int time, int ac); + /* mdwindow.c */ extern int md_set_appwindow(Window); diff --git a/libami/mdbattery.c b/libami/mdbattery.c new file mode 100644 index 0000000..24bab6a --- /dev/null +++ b/libami/mdbattery.c @@ -0,0 +1,85 @@ +#include +#include + +#include "libami.h" +#include "module.h" +#include "alloc.h" + +void +md_update_battery(int pct, int time, int ac) +{ + struct mcmd_update_battery batt = { 0 }; + int res; + + batt.battery_time = time; + batt.battery_pct = pct; + batt.battery_ac = ac; + + res = md_command0(None, MCMD_UPDATE_BATTERY, &batt, sizeof(batt)); + (void) res; +} + +Window md_create_appicon(Window p, int x, int y, char *name, + Pixmap pm1, Pixmap pm2, Pixmap pmm) +{ + char *data; + Window w; + int res, l=strlen(name); +#ifdef HAVE_ALLOCA + struct NewAppIcon *nai=alloca(sizeof(struct NewAppIcon)+l); +#else + struct NewAppIcon *nai=malloc(sizeof(struct NewAppIcon)+l); + if(nai==NULL) return None; +#endif + nai->x=x; nai->y=y; + nai->pm1=pm1; nai->pm2=pm2; nai->pmm=pmm; + strcpy(nai->name, name); + res=md_command(p, MCMD_CREATEAPPICON, nai, sizeof(struct NewAppIcon)+l, + &data); + if(res=0 && p) + return p; + if(p) free(p); + return NULL; +} + diff --git a/menu.c b/menu.c index eba1e1f..0ec80de 100644 --- a/menu.c +++ b/menu.c @@ -485,9 +485,16 @@ void createmenubar() } } +/* + * Redraw the menu bar and its components. + * + * This takes in the target window, which may be the basic menubar, + * a clicked-on menu, or the depth widget. + */ void redrawmenubar(Window w) { static const char defaultTimeFormat[] = "%c"; + int widget_rhs; struct Menu *m; struct Item *item; @@ -495,6 +502,7 @@ void redrawmenubar(Window w) if(!w) return; if(w==scr->menubar) { + /* Menubar itself */ XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]); XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]); #ifdef USE_FONTSETS @@ -507,6 +515,13 @@ void redrawmenubar(Window w) #endif XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARTRIMPEN]); XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, scr->width-1, scr->bh-1); + + /* Widgets start here and move to the left */ + widget_rhs = (scr->width - 30); + /* + * Update the title bar clock if it's enabled. + */ + if( prefs.titlebarclock ) { char clockbuf[512]; @@ -519,15 +534,38 @@ void redrawmenubar(Window w) #ifdef USE_FONTSETS l = XmbTextEscapement(scr->dri.dri_FontSet, clockbuf, strlen(clockbuf)); XmbDrawImageString(dpy, w, scr->dri.dri_FontSet, scr->menubargc, - (scr->width-30-l), 1+scr->dri.dri_Ascent, + widget_rhs - l, 1+scr->dri.dri_Ascent, clockbuf, strlen(clockbuf)); #else l = XTextWidth(scr->dri.dri_Font, clockbuf, strlen(clockbuf)); - XDrawImageString( dpy, w, scr->menubargc,(scr->width-30-l), + XDrawImageString( dpy, w, scr->menubargc, widget_rhs - l, 1+scr->dri.dri_Ascent, clockbuf, strlen(clockbuf)); #endif - } + widget_rhs = widget_rhs - l - 8; // 8 = padding + } + + /* + * Update the battery indicator if it's enabled. + */ + if (1) { + char battery_buf[512]; + int l; + + sprintf(battery_buf, "| Battery |"); +#ifdef USE_FONTSETS + l = XmbTextEscapement(scr->dri.dri_FontSet, battery_buf, strlen(battery_buf)); + XmbDrawImageString(dpy, w, scr->dri.dri_FontSet, scr->menubargc, + widget_rhs - l, 1+scr->dri.dri_Ascent, + battery_buf, strlen(battery_buf)); +#else + l = XTextWidth(scr->dri.dri_Font, battery_buf, strlen(battery_buf)); + XDrawImageString( dpy, w, scr->menubargc, widget_rhs - l, + 1+scr->dri.dri_Ascent, battery_buf, strlen(battery_buf)); +#endif + widget_rhs = widget_rhs - l - 8; // 8 = padding + } } else if(w==scr->menubardepth) { + /* Menubar depth widget */ if(!mbdclick) { XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]); XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2); @@ -545,6 +583,7 @@ void redrawmenubar(Window w) XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, 22, scr->bh-1); XDrawLine(dpy, w, scr->menubargc, 22, 0, 22, scr->bh-1); } else { + /* One of the menus is being displayed */ for(m=scr->firstmenu; m; m=m->next) if(m->win==w) redraw_menu(m, w); diff --git a/module.c b/module.c index 3b1bb7b..955e2f6 100644 --- a/module.c +++ b/module.c @@ -490,6 +490,27 @@ static void handle_module_cmd(struct module *m, char *data, int data_len) } else reply_module(m, NULL, -1); break; + case MCMD_UPDATE_BATTERY: + { + struct mcmd_update_battery *batt; + if (data_len != sizeof(struct mcmd_update_battery)) { + reply_module(m, NULL, -1); + break; + } + batt = (void *) data; + + fprintf(stderr, "%s: called, BATTERY, pct=%d, time=%d, ac=%d\n", + __func__, + batt->battery_pct, + batt->battery_time, + batt->battery_ac); + + /* XXX TODO: update the battery menu thingy here */ + + reply_module(m, NULL, 0); + break; + } + break; default: reply_module(m, NULL, -1); } diff --git a/module.h b/module.h index 9c891f1..4d227dd 100644 --- a/module.h +++ b/module.h @@ -16,6 +16,7 @@ #define MCMD_MANAGEMENU 18 #define MCMD_ROTATE_WINDOW_RAISE 19 #define MCMD_ROTATE_WINDOW_LOWER 20 +#define MCMD_UPDATE_BATTERY 21 struct mcmd_header { XID id; @@ -42,6 +43,14 @@ struct NewAppIcon { char name[1]; }; +struct mcmd_update_battery { + int battery_time; + int battery_pct; + int battery_cap; + int battery_ac; + int battery_charging; +}; + extern struct module { struct module *next; int in_fd, out_fd; From 54adc01be4d544131fab917ddd835fdd1e8a40fd Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 8 May 2022 14:04:21 -0700 Subject: [PATCH 3/8] [libami] document how the module loop works; start thinking about how to make it async * Yeah it'd be nice to just use libevent here, alas * Figure out how all the reading/writing works and comment it * Add a periodic function that'll be called every trip through the main loop; will turn it into something more formally periodic later. There's still lots to do here before I can actually schedule periodic events and the read()s are non-blocking. Give it time! --- libami/module.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/libami/module.c b/libami/module.c index 3579380..259e01b 100644 --- a/libami/module.c +++ b/libami/module.c @@ -8,6 +8,7 @@ #ifdef HAVE_UNISTD_H #include #endif +#include #include "libami.h" #include "module.h" @@ -24,6 +25,7 @@ Window md_root = None; static int md_int_len=0; static char *md_int_buf=NULL; void (*md_broker_func)(XEvent *, unsigned long); +void (*md_periodic_func)(void); void md_exit(int signal) { @@ -54,6 +56,12 @@ static int md_write(void *ptr, int len) return tot; } +/* + * Read from the input file descriptor until len; ,populate + * our buffer. + * + * Return total read, else -1 on error. + */ static int md_read(void *ptr, int len) { char *p=ptr; @@ -78,6 +86,10 @@ static int md_read(void *ptr, int len) return tot; } +/* + * Read in "len" bytes from the window manager command path + * into md_int_buf. + */ static int md_int_load(int len) { if(len>=md_int_len) { @@ -96,6 +108,13 @@ static struct md_queued_event { struct mcmd_event e; } *event_head=NULL, *event_tail=NULL; +/* + * Process queued XEvents from the window manager. + * + * The window manager pushes subscribed XEvents down to + * modules and this pulls them out of the queue and + * calls md_broker_func() on each of them. + */ void md_process_queued_events() { struct md_queued_event *e; @@ -107,6 +126,12 @@ void md_process_queued_events() } } +/* + * Enqueue an mcmd event into the event queue. + * + * This is called when there's an XEvent being queued + * from the window manager to the module. + */ static void md_enqueue(struct mcmd_event *e) { struct md_queued_event *qe=malloc(sizeof(struct md_queued_event)); @@ -122,6 +147,13 @@ static void md_enqueue(struct mcmd_event *e) } } +/* + * Read an async XEvent from the window manager. + * + * This is called by md_handle_input() to read an XEvent. + * The "I'm an Xevent" marker is ~len, so it's de-inverted + * and then a subsequent len field match must match it. + */ static int md_get_async(int len) { if(md_int_load(len)!=len) @@ -131,18 +163,30 @@ static int md_get_async(int len) return 1; } +/* + * Read input from the window manager. + * + * This reads two chunks - the size of the request, + * and then the request itself. + * + * Negative request lengths are treated special - they're + * treated as XEvents thrown into the input stream. + */ int md_handle_input() { int res; + /* Read the length of the request */ if(md_read(&res, sizeof(res))!=sizeof(res)) return -1; if(res>=0) { if(!res) return 0; + /* Read the command */ md_int_load(res); return 0; } else { + /* Negative length; treat as an XEvent */ res=~res; if(!res) return 0; @@ -150,6 +194,16 @@ int md_handle_input() } } +/* + * Send a command from the module back to the window manager. + * + * This sends a request up to the window manager and then reads the + * response to return. If asynchronous XEvents occur in the reply + * stream then those are enqueued via md_get_async(). + * + * If there is a response, buffer is set to a memory buffer containing it. + * It is thus up to the caller to free it. + */ int md_command(XID id, int cmd, void *data, int data_len, char **buffer) { int res; @@ -161,21 +215,38 @@ int md_command(XID id, int cmd, void *data, int data_len, char **buffer) mcmd.cmd = cmd; mcmd.len = data_len; + /* + * Send header, read response code. + */ if(md_write(&mcmd, sizeof(mcmd))!=sizeof(mcmd) || md_write(data, data_len)!=data_len || md_read(&res, sizeof(res))!=sizeof(res)) return -1; + /* + * If the response code is negative (well, less than -1) + * then its treated as an async XEvent. So, queue that + * and keep reading for the response code. + */ while(res<-1) { md_get_async(~res); if(md_read(&res, sizeof(res))!=sizeof(res)) return -1; } + + /* + * If the response code is >0, then allocate a buffer + * of a suitable size and read the response into the buffer. + */ if(res>0) { *buffer=malloc(res); if(md_read(*buffer, res)!=res) return -1; } + + /* + * Return the response size. + */ return res; } @@ -230,9 +301,43 @@ char *md_init(int argc, char *argv[]) return (argc>4? argv[4]:NULL); } -void md_main_loop() +void +md_main_loop() { - do md_process_queued_events(); while(md_handle_input()>=0); + fd_set readfds; + struct timeval tv; + int ret; + + /* + * For now I'm going to use select() for up to + * one second on the input FD, even though the + * FD is blocking. + * + * That way in the main loop we at least will + * get the chance to run the periodic function. + * + * A module can then for now set its own timer + * signal to run, which should interrupt this + * select. + */ + do { + FD_ZERO(&readfds); + FD_SET(md_in_fd, &readfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + + ret = select(md_in_fd + 1, &readfds, NULL, NULL, &tv); + (void) ret; + + if (md_periodic_func != NULL) { + md_periodic_func(); + } + + /* Process async XEvent events that have been read */ + md_process_queued_events(); + + /* Loop over, reading input events */ + } while(md_handle_input()>=0); } int md_connection_number() From 4bd5a665db278e4b51bcbf251682b67c759919ad Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 14 May 2022 22:07:36 -0700 Subject: [PATCH 4/8] [libami] Add a 5 second read timeout so the periodic routine can be called * add a basic select() loop for the read FD to see if it's ready * optionally block in md_read() even if we timeout - this is used for the md_command() side of things * md_handle_input() however doesn't block and will happily timeout so the loop can run and the periodic function can run. This indeed seems to work. It's a bit dirty, but it at least stops the main loop from being fully blocking and that's super useful for modules that wish to schedule background work. --- libami/module.c | 184 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 138 insertions(+), 46 deletions(-) diff --git a/libami/module.c b/libami/module.c index 259e01b..ff1bdaa 100644 --- a/libami/module.c +++ b/libami/module.c @@ -56,34 +56,114 @@ static int md_write(void *ptr, int len) return tot; } +/* + * Wait until the read FD is ready, or timeout (5 seconds.) + * + * Returns: + * + 1 if OK + * + 0 if timeout + * < 0 if error + */ +static int +md_wait_read_fd(void) +{ + fd_set readfds; + struct timeval tv; + int ret; + + FD_ZERO(&readfds); + FD_SET(md_in_fd, &readfds); + tv.tv_sec = 5; + tv.tv_usec = 0; + + ret = select(md_in_fd + 1, &readfds, NULL, NULL, &tv); + if (ret == 0) { + return (0); + } + if (ret < 0) { + return (-1); + } + if (FD_ISSET(md_in_fd, &readfds)) { + return (1); + } + + /* FD wasn't set; just return 0 */ + return (0); +} + /* * Read from the input file descriptor until len; ,populate * our buffer. * - * Return total read, else -1 on error. + * Return total read, 0 on timeout, else -1 on error. */ -static int md_read(void *ptr, int len) +static int md_read(void *ptr, int len, int block) { char *p=ptr; int r, tot=0; - while(len>0) { - if((r=read(md_in_fd, p, len))<0) { - if(errno==EINTR) + + while (len > 0) { + + /* Wait until the socket is ready, or timeout */ + r = md_wait_read_fd(); + if (r < 0) { + return (-1); + } + + /* + * Note: If we've read /anything/, then we just keep + * going until we're done. Otherwise we'll exit + * out here with a partial read and things will + * go sideways. + * + * If we're not blocking and select timed out, + * return timeout. + */ + if ((tot == 0) && (block == 0) && (r == 0)) { + return (0); + } + + /* + * Try to read some data. Go back around again + * if we hit EINTR/EWOULDBLOCK. + * + * If we hit EOF then that's an error. + */ + r = read(md_in_fd, p, len); + + /* Error */ + if (r < 0) { + if ((errno == EINTR) || (errno == EWOULDBLOCK)) { continue; - else - return r; + } else { + return (-1); + } } - if(!r) { - if(tot) - return tot; - else - md_exit(0); + + /* + * EOF and didn't read anything? md_exit() like + * the old code did. + */ + if ((r == 0) && (tot == 0)) { + md_exit(0); } + + /* + * EOF, but we read data, so at least return what + * we did read. + */ + if (r == 0) { + return (tot); + } + + /* r > 0 here */ + tot+=r; p+=r; len-=r; } - return tot; + + return (tot); } /* @@ -100,7 +180,7 @@ static int md_int_load(int len) } md_int_buf[len]='\0'; - return md_read(md_int_buf, len); + return md_read(md_int_buf, len, 1); } static struct md_queued_event { @@ -171,14 +251,31 @@ static int md_get_async(int len) * * Negative request lengths are treated special - they're * treated as XEvents thrown into the input stream. + * + * Returns >1 if got input, 0 if timed out, < 0 if error. */ -int md_handle_input() +int md_handle_input(void) { - int res; + int res, ret; + + /* Read the length of the request, don't block. */ + ret = md_read(&res, sizeof(res), 0); + + /* Timeout? */ + if (ret == 0) { + return (0); + } + + /* Error? */ + if (ret < 0) { + return (-1); + } + + /* Read size doesn't match request size? */ + if (ret != sizeof(res)) { + return (-1); + } - /* Read the length of the request */ - if(md_read(&res, sizeof(res))!=sizeof(res)) - return -1; if(res>=0) { if(!res) return 0; @@ -220,7 +317,7 @@ int md_command(XID id, int cmd, void *data, int data_len, char **buffer) */ if(md_write(&mcmd, sizeof(mcmd))!=sizeof(mcmd) || md_write(data, data_len)!=data_len || - md_read(&res, sizeof(res))!=sizeof(res)) + md_read(&res, sizeof(res), 1)!=sizeof(res)) return -1; /* @@ -230,7 +327,7 @@ int md_command(XID id, int cmd, void *data, int data_len, char **buffer) */ while(res<-1) { md_get_async(~res); - if(md_read(&res, sizeof(res))!=sizeof(res)) + if(md_read(&res, sizeof(res), 1)!=sizeof(res)) return -1; } @@ -240,7 +337,7 @@ int md_command(XID id, int cmd, void *data, int data_len, char **buffer) */ if(res>0) { *buffer=malloc(res); - if(md_read(*buffer, res)!=res) + if(md_read(*buffer, res, 1)!=res) return -1; } @@ -277,6 +374,23 @@ Display *md_display() return dpy; } +/* + * make the fd blocking or non-blocking. + */ +static int +md_fd_nonblocking(int fd, int nb) +{ + int ret, val; + + val = fcntl(fd, F_GETFD); + if (nb) { + ret = fcntl(fd, F_SETFD, val | O_NONBLOCK); + } else { + ret = fcntl(fd, F_SETFD, val & ~O_NONBLOCK); + } + return (ret == 0); +} + char *md_init(int argc, char *argv[]) { if(argc>0) @@ -298,37 +412,15 @@ char *md_init(int argc, char *argv[]) if(md_command(None, MCMD_GET_VERSION, NULL, 0, &amiwm_version)<=0) md_fail(); + md_fd_nonblocking(md_in_fd, 1); + return (argc>4? argv[4]:NULL); } void md_main_loop() { - fd_set readfds; - struct timeval tv; - int ret; - - /* - * For now I'm going to use select() for up to - * one second on the input FD, even though the - * FD is blocking. - * - * That way in the main loop we at least will - * get the chance to run the periodic function. - * - * A module can then for now set its own timer - * signal to run, which should interrupt this - * select. - */ do { - FD_ZERO(&readfds); - FD_SET(md_in_fd, &readfds); - tv.tv_sec = 1; - tv.tv_usec = 0; - - ret = select(md_in_fd + 1, &readfds, NULL, NULL, &tv); - (void) ret; - if (md_periodic_func != NULL) { md_periodic_func(); } From 030f55fa2e77436afdb7daf675b7695f3bccda4e Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 14 May 2022 22:08:55 -0700 Subject: [PATCH 5/8] [battery] Tie into the periodic function to update APM info Tie into the periodic function so we can get the APM info. For now it's not checking that some time has elapsed, the hope is that it'll just be driven by md_main_loop() / 5 second select timeout. --- battery_module.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/battery_module.c b/battery_module.c index 272b4a6..1b4959e 100644 --- a/battery_module.c +++ b/battery_module.c @@ -11,6 +11,9 @@ #include "libami.h" +/* XXX should be an md method */ +extern void (*md_periodic_func)(void); + /* * Test battery module for FreeBSD, using APM. */ @@ -45,21 +48,29 @@ get_apm_info(void) return true; } +static void +periodic_func(void) +{ + fprintf(stderr, "Ha!\n"); + get_apm_info(); +} + int main(int argc, char *argv[]) { - char *arg=md_init(argc, argv); + char *arg; + + arg = md_init(argc, argv); progname=argv[0]; + md_periodic_func = periodic_func; + apm_fd = open(APM_DEV, O_RDONLY); if (apm_fd < 0) { err(127, "open"); } - /* - * XXX TODO: how do I actually get this to run once - * a second in the main loop? - */ + /* initial battery info */ get_apm_info(); md_main_loop(); From 915b84e403ac6606050b94c9c03f27666881502e Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 15 May 2022 10:49:17 -0700 Subject: [PATCH 6/8] [battery] Update to not spit out debugging Now that this actually seems to work, let's not spit out so much debugging info. It's not needed! Whilst here quieten a debugging output. --- battery_module.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/battery_module.c b/battery_module.c index 1b4959e..b7271d9 100644 --- a/battery_module.c +++ b/battery_module.c @@ -38,9 +38,11 @@ get_apm_info(void) return false; } +#if 0 printf("Battery life: %d\n", info.ai_batt_life); printf("Battery time: %d\n", info.ai_batt_time); printf("Battery AC: %d\n", info.ai_acline); +#endif md_update_battery(info.ai_batt_life, info.ai_batt_time, info.ai_acline); @@ -51,15 +53,16 @@ get_apm_info(void) static void periodic_func(void) { - fprintf(stderr, "Ha!\n"); get_apm_info(); } -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { char *arg; arg = md_init(argc, argv); + (void) arg; progname=argv[0]; @@ -73,6 +76,7 @@ int main(int argc, char *argv[]) /* initial battery info */ get_apm_info(); + /* Run main loop */ md_main_loop(); close(apm_fd); From fc23b3e054eb2d257ae8eb7e1ff0d7935d7428e5 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 15 May 2022 10:50:55 -0700 Subject: [PATCH 7/8] [battery] Add help on how the battery module works. --- MODULES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MODULES.md b/MODULES.md index be5227f..4c6889b 100644 --- a/MODULES.md +++ b/MODULES.md @@ -121,3 +121,13 @@ Module "Launcher" "(