mirror of
https://github.com/amiwm/amiwm.git
synced 2026-04-14 11:04:18 +00:00
Merge pull request #5 from erikarn/ahc_20220425_menu_widgets
This is the beginning of adding some battery display support into the menu and figuring out how to add arbitrary widgets into the menu bar. It's going to take a bunch more commits / time to clean this up to be more flexible, but at least now we have an MVP of adding a new "thing", buggy as it is.
This commit is contained in:
10
MODULES.md
10
MODULES.md
@@ -121,3 +121,13 @@ Module "Launcher" "(<label>) (<icon>) (<command and args>)"
|
|||||||
|
|
||||||
The icon is one of the .info icons in the amiwm IconDir.
|
The icon is one of the .info icons in the amiwm IconDir.
|
||||||
|
|
||||||
|
## Battery module
|
||||||
|
|
||||||
|
This is a simple battery state polling module that is being used
|
||||||
|
during battery monitoring / menu toolbar development.
|
||||||
|
|
||||||
|
It's currently FreeBSD specific and based on what xbatt does
|
||||||
|
to pull info from APM/ACPI. Adding Linux and other OS support
|
||||||
|
shouldn't be too difficult.
|
||||||
|
|
||||||
|
Module "Battery"
|
||||||
|
|||||||
@@ -171,6 +171,9 @@ Filesystem : filesystem.o $(LIBAMI)
|
|||||||
Keyboard : kbdmodule.o kbdlexer.o $(LIBAMI)
|
Keyboard : kbdmodule.o kbdlexer.o $(LIBAMI)
|
||||||
$(CC) -o Keyboard kbdmodule.o kbdlexer.o $(LIBS)
|
$(CC) -o Keyboard kbdmodule.o kbdlexer.o $(LIBS)
|
||||||
|
|
||||||
|
Battery : battery_module.o $(LIBAMI)
|
||||||
|
$(CC) -o Battery battery_module.o $(LIBS)
|
||||||
|
|
||||||
Launcher : launchermodule.o $(LIBAMI)
|
Launcher : launchermodule.o $(LIBAMI)
|
||||||
$(CC) -o Launcher launchermodule.o $(LIBS)
|
$(CC) -o Launcher launchermodule.o $(LIBS)
|
||||||
|
|
||||||
@@ -181,7 +184,7 @@ localetest : localetest.o $(LIBAMI)
|
|||||||
$(CC) -o localetest localetest.o $(LIBS)
|
$(CC) -o localetest localetest.o $(LIBS)
|
||||||
|
|
||||||
clean : lib_clean
|
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) lex.yy.c lex.c y.tab.c y.tab.h gram.h gram.c
|
||||||
$(RM) kbdlexer.c kbdmodule.h kbdmodule.c
|
$(RM) kbdlexer.c kbdmodule.h kbdmodule.c
|
||||||
$(RM) config.log
|
$(RM) config.log
|
||||||
|
|||||||
6
amiwm.1
6
amiwm.1
@@ -94,6 +94,12 @@ The time string is formatted with the standard strftime() parameters.
|
|||||||
The default is "%c". It has been found that "%a %b %e %Y %l:%M %p" works
|
The default is "%c". It has been found that "%a %b %e %Y %l:%M %p" works
|
||||||
well too. Number is the update interval in seconds.
|
well too. Number is the update interval in seconds.
|
||||||
|
|
||||||
|
.SH BatteryInfo {yes|no}
|
||||||
|
|
||||||
|
This lets you display battery information on the menu bar.
|
||||||
|
It reqiures a module (such as Battery) to gather current battery status
|
||||||
|
and push it into amiwm to display.
|
||||||
|
|
||||||
.SH ToolItem \f1\*(lq\f3name" \f1\*(lq\f3command" \f1\*(lq\f3hotkey"
|
.SH ToolItem \f1\*(lq\f3name" \f1\*(lq\f3command" \f1\*(lq\f3hotkey"
|
||||||
|
|
||||||
Adds an item in the Tools menu with the specified name, which executes
|
Adds an item in the Tools menu with the specified name, which executes
|
||||||
|
|||||||
84
battery_module.c
Normal file
84
battery_module.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <machine/apm_bios.h>
|
||||||
|
|
||||||
|
#define APM_DEV "/dev/apm"
|
||||||
|
|
||||||
|
#include "libami.h"
|
||||||
|
|
||||||
|
/* XXX should be an md method */
|
||||||
|
extern void (*md_periodic_func)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
periodic_func(void)
|
||||||
|
{
|
||||||
|
get_apm_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
arg = md_init(argc, argv);
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
progname=argv[0];
|
||||||
|
|
||||||
|
md_periodic_func = periodic_func;
|
||||||
|
|
||||||
|
apm_fd = open(APM_DEV, O_RDONLY);
|
||||||
|
if (apm_fd < 0) {
|
||||||
|
err(127, "open");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initial battery info */
|
||||||
|
get_apm_info();
|
||||||
|
|
||||||
|
/* Run main loop */
|
||||||
|
md_main_loop();
|
||||||
|
|
||||||
|
close(apm_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
2
gram.y
2
gram.y
@@ -66,6 +66,7 @@ static int ti_level=0;
|
|||||||
%token <num> INTERSCREENGAP AUTORAISE FOCUS FOLLOWMOUSE CLICKTOTYPE SLOPPY
|
%token <num> INTERSCREENGAP AUTORAISE FOCUS FOLLOWMOUSE CLICKTOTYPE SLOPPY
|
||||||
%token <num> CUSTOMICONSONLY
|
%token <num> CUSTOMICONSONLY
|
||||||
%token <num> TITLEBARCLOCK TITLECLOCKFORMAT
|
%token <num> TITLEBARCLOCK TITLECLOCKFORMAT
|
||||||
|
%token <num> BATTERYINFO
|
||||||
%token <num> OPAQUEMOVE OPAQUERESIZE SCREENMENU STYLE CLASS TITLE ICONTITLE ICON
|
%token <num> OPAQUEMOVE OPAQUERESIZE SCREENMENU STYLE CLASS TITLE ICONTITLE ICON
|
||||||
%token <num> SHORTLABELICONS
|
%token <num> SHORTLABELICONS
|
||||||
%token <ptr> STRING
|
%token <ptr> STRING
|
||||||
@@ -118,6 +119,7 @@ stmt : error
|
|||||||
prefs.titleclockinterval=$2;
|
prefs.titleclockinterval=$2;
|
||||||
prefs.titleclockformat=$3; }
|
prefs.titleclockformat=$3; }
|
||||||
| SCREENMENU truth { prefs.screenmenu=$2; }
|
| SCREENMENU truth { prefs.screenmenu=$2; }
|
||||||
|
| BATTERYINFO truth { prefs.battery_info = $2; }
|
||||||
| stylespec styleitems RIGHTBRACE
|
| stylespec styleitems RIGHTBRACE
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ LN_S = @LN_S@
|
|||||||
RM = -rm -f
|
RM = -rm -f
|
||||||
|
|
||||||
OBJS = drawinfo.o module.o broker.o eventdispatcher.o mdscreen.o \
|
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 \
|
lists.o readargs.o iconlib.o iconutil.o error.o strutil.o \
|
||||||
iffparse.o gadget_button.o gadget_textbox.o gadget_textinput.o
|
iffparse.o gadget_button.o gadget_textbox.o gadget_textinput.o
|
||||||
|
|
||||||
SRCS = drawinfo.c module.c broker.c eventdispatcher.c mdscreen.c \
|
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 \
|
lists.c readargs.c iconlib.c iconutil.c error.c strutil.c \
|
||||||
iffparse.c gadget_button.c gadget_textbox.c gadget_textinput.c
|
iffparse.c gadget_button.c gadget_textbox.c gadget_textinput.c
|
||||||
|
|
||||||
|
|||||||
@@ -389,6 +389,9 @@ extern Pixmap md_image_to_pixmap(Window, unsigned long, struct Image *,
|
|||||||
int, int, struct ColorStore *);
|
int, int, struct ColorStore *);
|
||||||
extern char *get_current_icondir(void);
|
extern char *get_current_icondir(void);
|
||||||
|
|
||||||
|
/* mdbattery.c */
|
||||||
|
extern void md_update_battery(int pct, int time, int ac);
|
||||||
|
|
||||||
/* mdwindow.c */
|
/* mdwindow.c */
|
||||||
extern int md_set_appwindow(Window);
|
extern int md_set_appwindow(Window);
|
||||||
|
|
||||||
|
|||||||
85
libami/mdbattery.c
Normal file
85
libami/mdbattery.c
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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<sizeof(w)) {
|
||||||
|
if(data) free(data);
|
||||||
|
#ifndef HAVE_ALLOCA
|
||||||
|
free(nai);
|
||||||
|
#endif
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
memcpy(&w, data, sizeof(w));
|
||||||
|
free(data);
|
||||||
|
#ifndef HAVE_ALLOCA
|
||||||
|
free(nai);
|
||||||
|
#endif
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pixmap md_image_to_pixmap(Window w, unsigned long bgcolor, struct Image *i,
|
||||||
|
int width, int height, struct ColorStore *cs)
|
||||||
|
{
|
||||||
|
Display *dpy = md_display();
|
||||||
|
static GC gc = None;
|
||||||
|
Pixmap pm;
|
||||||
|
static int iconcolormask;
|
||||||
|
static unsigned long *iconcolor = NULL;
|
||||||
|
if(gc == None && w != None)
|
||||||
|
gc = XCreateGC(dpy, w, 0, NULL);
|
||||||
|
if(iconcolor == NULL) {
|
||||||
|
char *p;
|
||||||
|
int res = md_command(w, MCMD_GETICONPALETTE, NULL, 0, &p);
|
||||||
|
if(res<0)
|
||||||
|
return None;
|
||||||
|
iconcolor = (unsigned long *)(void *)p;
|
||||||
|
iconcolormask = (res/sizeof(unsigned long))-1;
|
||||||
|
}
|
||||||
|
pm = image_to_pixmap(md_display(), w, gc, bgcolor, iconcolor, iconcolormask,
|
||||||
|
i, width, height, cs);
|
||||||
|
return pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_current_icondir()
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
if(md_command(None, MCMD_GETICONDIR, NULL, 0, &p)>=0 && p)
|
||||||
|
return p;
|
||||||
|
if(p) free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
241
libami/module.c
241
libami/module.c
@@ -8,6 +8,7 @@
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
#include "libami.h"
|
#include "libami.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
@@ -24,6 +25,7 @@ Window md_root = None;
|
|||||||
static int md_int_len=0;
|
static int md_int_len=0;
|
||||||
static char *md_int_buf=NULL;
|
static char *md_int_buf=NULL;
|
||||||
void (*md_broker_func)(XEvent *, unsigned long);
|
void (*md_broker_func)(XEvent *, unsigned long);
|
||||||
|
void (*md_periodic_func)(void);
|
||||||
|
|
||||||
void md_exit(int signal)
|
void md_exit(int signal)
|
||||||
{
|
{
|
||||||
@@ -54,30 +56,120 @@ static int md_write(void *ptr, int len)
|
|||||||
return tot;
|
return tot;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int md_read(void *ptr, int len)
|
/*
|
||||||
|
* 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, 0 on timeout, else -1 on error.
|
||||||
|
*/
|
||||||
|
static int md_read(void *ptr, int len, int block)
|
||||||
{
|
{
|
||||||
char *p=ptr;
|
char *p=ptr;
|
||||||
int r, tot=0;
|
int r, tot=0;
|
||||||
while(len>0) {
|
|
||||||
if((r=read(md_in_fd, p, len))<0) {
|
while (len > 0) {
|
||||||
if(errno==EINTR)
|
|
||||||
|
/* 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;
|
continue;
|
||||||
else
|
} else {
|
||||||
return r;
|
return (-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!r) {
|
|
||||||
if(tot)
|
/*
|
||||||
return tot;
|
* EOF and didn't read anything? md_exit() like
|
||||||
else
|
* the old code did.
|
||||||
md_exit(0);
|
*/
|
||||||
|
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;
|
tot+=r;
|
||||||
p+=r;
|
p+=r;
|
||||||
len-=r;
|
len-=r;
|
||||||
}
|
}
|
||||||
return tot;
|
|
||||||
|
return (tot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read in "len" bytes from the window manager command path
|
||||||
|
* into md_int_buf.
|
||||||
|
*/
|
||||||
static int md_int_load(int len)
|
static int md_int_load(int len)
|
||||||
{
|
{
|
||||||
if(len>=md_int_len) {
|
if(len>=md_int_len) {
|
||||||
@@ -88,7 +180,7 @@ static int md_int_load(int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
md_int_buf[len]='\0';
|
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 {
|
static struct md_queued_event {
|
||||||
@@ -96,6 +188,13 @@ static struct md_queued_event {
|
|||||||
struct mcmd_event e;
|
struct mcmd_event e;
|
||||||
} *event_head=NULL, *event_tail=NULL;
|
} *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()
|
void md_process_queued_events()
|
||||||
{
|
{
|
||||||
struct md_queued_event *e;
|
struct md_queued_event *e;
|
||||||
@@ -107,6 +206,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)
|
static void md_enqueue(struct mcmd_event *e)
|
||||||
{
|
{
|
||||||
struct md_queued_event *qe=malloc(sizeof(struct md_queued_event));
|
struct md_queued_event *qe=malloc(sizeof(struct md_queued_event));
|
||||||
@@ -122,6 +227,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)
|
static int md_get_async(int len)
|
||||||
{
|
{
|
||||||
if(md_int_load(len)!=len)
|
if(md_int_load(len)!=len)
|
||||||
@@ -131,18 +243,47 @@ static int md_get_async(int len)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int md_handle_input()
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Returns >1 if got input, 0 if timed out, < 0 if error.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if(md_read(&res, sizeof(res))!=sizeof(res))
|
|
||||||
return -1;
|
|
||||||
if(res>=0) {
|
if(res>=0) {
|
||||||
if(!res)
|
if(!res)
|
||||||
return 0;
|
return 0;
|
||||||
|
/* Read the command */
|
||||||
md_int_load(res);
|
md_int_load(res);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
/* Negative length; treat as an XEvent */
|
||||||
res=~res;
|
res=~res;
|
||||||
if(!res)
|
if(!res)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -150,6 +291,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 md_command(XID id, int cmd, void *data, int data_len, char **buffer)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@@ -161,21 +312,38 @@ int md_command(XID id, int cmd, void *data, int data_len, char **buffer)
|
|||||||
mcmd.cmd = cmd;
|
mcmd.cmd = cmd;
|
||||||
mcmd.len = data_len;
|
mcmd.len = data_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send header, read response code.
|
||||||
|
*/
|
||||||
if(md_write(&mcmd, sizeof(mcmd))!=sizeof(mcmd) ||
|
if(md_write(&mcmd, sizeof(mcmd))!=sizeof(mcmd) ||
|
||||||
md_write(data, data_len)!=data_len ||
|
md_write(data, data_len)!=data_len ||
|
||||||
md_read(&res, sizeof(res))!=sizeof(res))
|
md_read(&res, sizeof(res), 1)!=sizeof(res))
|
||||||
return -1;
|
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) {
|
while(res<-1) {
|
||||||
md_get_async(~res);
|
md_get_async(~res);
|
||||||
if(md_read(&res, sizeof(res))!=sizeof(res))
|
if(md_read(&res, sizeof(res), 1)!=sizeof(res))
|
||||||
return -1;
|
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) {
|
if(res>0) {
|
||||||
*buffer=malloc(res);
|
*buffer=malloc(res);
|
||||||
if(md_read(*buffer, res)!=res)
|
if(md_read(*buffer, res, 1)!=res)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the response size.
|
||||||
|
*/
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +374,23 @@ Display *md_display()
|
|||||||
return dpy;
|
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[])
|
char *md_init(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc>0)
|
if(argc>0)
|
||||||
@@ -227,12 +412,24 @@ char *md_init(int argc, char *argv[])
|
|||||||
if(md_command(None, MCMD_GET_VERSION, NULL, 0, &amiwm_version)<=0)
|
if(md_command(None, MCMD_GET_VERSION, NULL, 0, &amiwm_version)<=0)
|
||||||
md_fail();
|
md_fail();
|
||||||
|
|
||||||
|
md_fd_nonblocking(md_in_fd, 1);
|
||||||
|
|
||||||
return (argc>4? argv[4]:NULL);
|
return (argc>4? argv[4]:NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void md_main_loop()
|
void
|
||||||
|
md_main_loop()
|
||||||
{
|
{
|
||||||
do md_process_queued_events(); while(md_handle_input()>=0);
|
do {
|
||||||
|
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()
|
int md_connection_number()
|
||||||
|
|||||||
3
main.c
3
main.c
@@ -820,9 +820,12 @@ void internal_broker(XEvent *e)
|
|||||||
|
|
||||||
static void update_clock(void *dontcare)
|
static void update_clock(void *dontcare)
|
||||||
{
|
{
|
||||||
|
Scrn *scr;
|
||||||
|
|
||||||
if(server_grabs)
|
if(server_grabs)
|
||||||
return;
|
return;
|
||||||
call_out(prefs.titleclockinterval, 0, update_clock, dontcare);
|
call_out(prefs.titleclockinterval, 0, update_clock, dontcare);
|
||||||
|
|
||||||
scr = get_front_scr();
|
scr = get_front_scr();
|
||||||
do {
|
do {
|
||||||
redrawmenubar(scr->menubar);
|
redrawmenubar(scr->menubar);
|
||||||
|
|||||||
52
menu.c
52
menu.c
@@ -37,6 +37,8 @@ extern struct Library *XLibBase;
|
|||||||
#define CHECKED 2
|
#define CHECKED 2
|
||||||
#define DISABLED 4
|
#define DISABLED 4
|
||||||
|
|
||||||
|
char battery_status[128];
|
||||||
|
|
||||||
extern Display *dpy;
|
extern Display *dpy;
|
||||||
extern Cursor wm_curs;
|
extern Cursor wm_curs;
|
||||||
extern XContext screen_context, client_context;
|
extern XContext screen_context, client_context;
|
||||||
@@ -303,7 +305,7 @@ void redraw_item(struct Item *i, Window w)
|
|||||||
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
|
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
|
||||||
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
|
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
|
||||||
}
|
}
|
||||||
if(i->text)
|
if(i->text) {
|
||||||
#ifdef USE_FONTSETS
|
#ifdef USE_FONTSETS
|
||||||
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
|
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
|
||||||
scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
|
scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
|
||||||
@@ -312,8 +314,9 @@ void redraw_item(struct Item *i, Window w)
|
|||||||
XDrawImageString(dpy, w, scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
|
XDrawImageString(dpy, w, scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
|
||||||
scr->dri.dri_Ascent+1, i->text, i->textlen);
|
scr->dri.dri_Ascent+1, i->text, i->textlen);
|
||||||
#endif
|
#endif
|
||||||
else
|
} else {
|
||||||
XFillRectangle(dpy, w, scr->menubargc, 2, 2, m->width-10, 2);
|
XFillRectangle(dpy, w, scr->menubargc, 2, 2, m->width-10, 2);
|
||||||
|
}
|
||||||
if(i->sub) {
|
if(i->sub) {
|
||||||
int x=m->width-6-scr->hotkeyspace-1+8;
|
int x=m->width-6-scr->hotkeyspace-1+8;
|
||||||
#ifdef USE_FONTSETS
|
#ifdef USE_FONTSETS
|
||||||
@@ -485,9 +488,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)
|
void redrawmenubar(Window w)
|
||||||
{
|
{
|
||||||
static const char defaultTimeFormat[] = "%c";
|
static const char defaultTimeFormat[] = "%c";
|
||||||
|
int widget_rhs;
|
||||||
|
|
||||||
struct Menu *m;
|
struct Menu *m;
|
||||||
struct Item *item;
|
struct Item *item;
|
||||||
@@ -495,6 +505,7 @@ void redrawmenubar(Window w)
|
|||||||
if(!w)
|
if(!w)
|
||||||
return;
|
return;
|
||||||
if(w==scr->menubar) {
|
if(w==scr->menubar) {
|
||||||
|
/* Menubar itself */
|
||||||
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
|
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
|
||||||
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
|
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
|
||||||
#ifdef USE_FONTSETS
|
#ifdef USE_FONTSETS
|
||||||
@@ -507,6 +518,13 @@ void redrawmenubar(Window w)
|
|||||||
#endif
|
#endif
|
||||||
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARTRIMPEN]);
|
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARTRIMPEN]);
|
||||||
XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, scr->width-1, scr->bh-1);
|
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 )
|
if( prefs.titlebarclock )
|
||||||
{
|
{
|
||||||
char clockbuf[512];
|
char clockbuf[512];
|
||||||
@@ -519,15 +537,38 @@ void redrawmenubar(Window w)
|
|||||||
#ifdef USE_FONTSETS
|
#ifdef USE_FONTSETS
|
||||||
l = XmbTextEscapement(scr->dri.dri_FontSet, clockbuf, strlen(clockbuf));
|
l = XmbTextEscapement(scr->dri.dri_FontSet, clockbuf, strlen(clockbuf));
|
||||||
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet, scr->menubargc,
|
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));
|
clockbuf, strlen(clockbuf));
|
||||||
#else
|
#else
|
||||||
l = XTextWidth(scr->dri.dri_Font, clockbuf, strlen(clockbuf));
|
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));
|
1+scr->dri.dri_Ascent, clockbuf, strlen(clockbuf));
|
||||||
#endif
|
#endif
|
||||||
}
|
widget_rhs = widget_rhs - l - 8; // 8 = padding
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the battery indicator if it's enabled.
|
||||||
|
*/
|
||||||
|
if (prefs.battery_info) {
|
||||||
|
char battery_buf[512];
|
||||||
|
int l;
|
||||||
|
|
||||||
|
sprintf(battery_buf, "| %s |", battery_status);
|
||||||
|
#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) {
|
} else if(w==scr->menubardepth) {
|
||||||
|
/* Menubar depth widget */
|
||||||
if(!mbdclick) {
|
if(!mbdclick) {
|
||||||
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]);
|
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]);
|
||||||
XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2);
|
XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2);
|
||||||
@@ -545,6 +586,7 @@ void redrawmenubar(Window w)
|
|||||||
XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, 22, scr->bh-1);
|
XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, 22, scr->bh-1);
|
||||||
XDrawLine(dpy, w, scr->menubargc, 22, 0, 22, scr->bh-1);
|
XDrawLine(dpy, w, scr->menubargc, 22, 0, 22, scr->bh-1);
|
||||||
} else {
|
} else {
|
||||||
|
/* One of the menus is being displayed */
|
||||||
for(m=scr->firstmenu; m; m=m->next)
|
for(m=scr->firstmenu; m; m=m->next)
|
||||||
if(m->win==w)
|
if(m->win==w)
|
||||||
redraw_menu(m, w);
|
redraw_menu(m, w);
|
||||||
|
|||||||
36
module.c
36
module.c
@@ -490,6 +490,42 @@ static void handle_module_cmd(struct module *m, char *data, int data_len)
|
|||||||
} else
|
} else
|
||||||
reply_module(m, NULL, -1);
|
reply_module(m, NULL, -1);
|
||||||
break;
|
break;
|
||||||
|
case MCMD_UPDATE_BATTERY:
|
||||||
|
{
|
||||||
|
struct mcmd_update_battery *batt;
|
||||||
|
extern char battery_status[];
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
reply_module(m, NULL, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data_len != sizeof(struct mcmd_update_battery)) {
|
||||||
|
reply_module(m, NULL, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
batt = (void *) data;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
fprintf(stderr, "%s: called, BATTERY, pct=%d, time=%d, ac=%d\n",
|
||||||
|
__func__,
|
||||||
|
batt->battery_pct,
|
||||||
|
batt->battery_time,
|
||||||
|
batt->battery_ac);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX TODO: for now we're just populating a string here.
|
||||||
|
* Later on we should just store the current battery state
|
||||||
|
* somewhere (a key/value table would be nice!) and then
|
||||||
|
* the widget code can pull out its needed state to render.
|
||||||
|
*/
|
||||||
|
snprintf(battery_status, 128, "%d pct%s", batt->battery_pct,
|
||||||
|
batt->battery_ac == 1 ? " A" : " -");
|
||||||
|
|
||||||
|
reply_module(m, NULL, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
reply_module(m, NULL, -1);
|
reply_module(m, NULL, -1);
|
||||||
}
|
}
|
||||||
|
|||||||
9
module.h
9
module.h
@@ -16,6 +16,7 @@
|
|||||||
#define MCMD_MANAGEMENU 18
|
#define MCMD_MANAGEMENU 18
|
||||||
#define MCMD_ROTATE_WINDOW_RAISE 19
|
#define MCMD_ROTATE_WINDOW_RAISE 19
|
||||||
#define MCMD_ROTATE_WINDOW_LOWER 20
|
#define MCMD_ROTATE_WINDOW_LOWER 20
|
||||||
|
#define MCMD_UPDATE_BATTERY 21
|
||||||
|
|
||||||
struct mcmd_header {
|
struct mcmd_header {
|
||||||
XID id;
|
XID id;
|
||||||
@@ -42,6 +43,14 @@ struct NewAppIcon {
|
|||||||
char name[1];
|
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 {
|
extern struct module {
|
||||||
struct module *next;
|
struct module *next;
|
||||||
int in_fd, out_fd;
|
int in_fd, out_fd;
|
||||||
|
|||||||
1
prefs.h
1
prefs.h
@@ -17,6 +17,7 @@ extern struct prefs_struct {
|
|||||||
char *titleclockformat; /* format to use for the clock */
|
char *titleclockformat; /* format to use for the clock */
|
||||||
int titleclockinterval; /* how often do we update the clock?*/
|
int titleclockinterval; /* how often do we update the clock?*/
|
||||||
int icontray; // if true then icons will be shown in a tray on top of each screen (besides clock and screen name)
|
int icontray; // if true then icons will be shown in a tray on top of each screen (besides clock and screen name)
|
||||||
|
int battery_info; /* display battery info? */
|
||||||
struct _Style *firststyle, *laststyle;
|
struct _Style *firststyle, *laststyle;
|
||||||
} prefs;
|
} prefs;
|
||||||
|
|
||||||
|
|||||||
1
rc.c
1
rc.c
@@ -105,6 +105,7 @@ struct keyword { char *name; int token; } keywords[] = {
|
|||||||
{ "barblockpen", T_BARBLOCKPEN },
|
{ "barblockpen", T_BARBLOCKPEN },
|
||||||
{ "bardetailpen", T_BARDETAILPEN },
|
{ "bardetailpen", T_BARDETAILPEN },
|
||||||
{ "bartrimpen", T_BARTRIMPEN },
|
{ "bartrimpen", T_BARTRIMPEN },
|
||||||
|
{ "batteryinfo", BATTERYINFO },
|
||||||
{ "blockpen", T_BLOCKPEN },
|
{ "blockpen", T_BLOCKPEN },
|
||||||
{ "both", BOTH },
|
{ "both", BOTH },
|
||||||
{ "bottom", BOTTOM },
|
{ "bottom", BOTTOM },
|
||||||
|
|||||||
Reference in New Issue
Block a user