Manipulating window look & behaviour with 'hey' | Haiku Project

I have an ActivityMonitor replicant showing network receive/send info on the Desktop. I’d also like to have something showing cpu usage. However, a combined cpu usage ActivityMonitor doesn’t show individual core usage, and having a graph of all cpus often isn’t that informative either, because the 8 doodling lines of my cores are easily confusing. ProcessController’s bars are too narrow. Here are both, showing their inadequacy:


This is a companion discussion topic for the original entry at https://www.haiku-os.org/blog/humdinger/2020-08-22_manipulating_windows_with_hey/
4 Likes

Thanks for the tutorial. On a similar note, I’ll need to implement audio recording functionality to my Video Editor (I’ve just ordered a cheap 3.5” jack microphone for testing today), and thought that interfacing with the built in app SoundRecorder using BMessages (instead of hey) might be a better and faster solution for me. The challenge then becomes redirecting Sound Recorder GUI button messages to my app. Just like with hey, I would interrogate button names and then modify the message targets. Should work in theory …

1 Like

those are like some of the features cmdow has

Thank you for sharing your experience.

I believe, hey scripting is the most underappreciated feature of Haiku. It really deserves more attention.

Look here too:

https://www.haiku-os.org/documents/dev/using_scripting_in_haiku/

I tried to use Hey as documented to do basic updates to the picture display utility. I was not able to reproduce many features in the documentation. I don’t know whether some features are not documented, or whether the hey command line usage is too complicated for my brain. Hopefully you have better luck.

Consider opening a new thread with the specific hey command that gives you trouble, and we’ll see if we can find out where’s the problem.

2 Likes

Having a library or a gallery showing a sample of some useful hey scripts would be cool.

4 Likes

These is a known way to get the current workspace bg color?

Workspaces applet is tainting each workspace with its background colour. You may try to get it from there.

Indeed! The DesktopColor() call in the BScreen class is probably what you’re looking for:

1 Like

not strictly related to hey but it’s involved, I’ve almost finished a bash script to manage windows using hey but with only one command line to do multiple things, but I’m stuck and I can’t go further

I dunno if there are some shell wizards out there but I’l try

I want to change the flags of the selected window, default flags=1572864 for quit on close and async controls, so I have to add the related value of flag to this value (not movable +1, not closable +32 etc), I pass the string to SumFlags functions that should do that, but when the while is done the value of flags is not changed, the variable is not declared locally and I can’t understand why it acts like that, any hint?

ChangeFlags()
{
flags=1572864
echo $1 | tr “,” “\n” | while read line; do #multiple values splitted by commas
SumFlags ${line}
done
hey -o “${app_name}” set Flags of Window “${win_ID}” to ${flags}
}

SumFlags()
{
case $1 in
nm|not-movable)
let flags+=1
;;
nr|not-resizable)
let flags+=2
;;
nh|not-h-resizable)
let flags+=4
;;
nv|not-v-resizable)
let flags+=8
;;
fs|accept-first-click)
let flags+=16
;;
nc|not-closable)
let flags+=32
;;
nz|not-zoomable)
let flags+=64
;;
af|avoid-front)
let flags+=128
;;
nw|no-workspace-activation)
let flags+=256
;;
as|avoid-focus)
let flags+=8192
;;
nb|not-minimizable)
let flags+=16384
;;
na|not_anchored)
let flags+=131072
;;
sp|same-position)
let flags+=2097152
;;
ce|close-on-escape)
let flags+=8388608
;;
*)
Usage
;;
esac
}

When you pipe data into a while loop, the “while” gets executed as a subshell with its own variables. You can use a “here string” in bash like …

while read line; do #multiple values splitted by commas
    SumFlags ${line}
done <<<  $(echo $1 | tr "," "\\n")

thanks, it worked perfectly, I didn’t know that “while” has that behavior but this explains a lot of weird things happened in other scripts.
If you want to try and fork, you are better than me at coding, this is my winpwnr gits

#! /bin/sh

Usage()
{
echo "usage: ${script_name} -option <value>
	-a	select the application by name
	
	-l	list windows for the selected application
	
	-s	select application's window by ID number or title
	
	-t	change the title of the selected window 
	
	-f	force full-screen for the selected window, no value is needed
	
	-w	show the selected window on {x} workspace(s),
			you can set multiple values separated by any character, like
			\"1,2,4,5\" or \"5.6.1\", use \"all\" to show it in every workspace
			
	-L	change the LOOK of the selected window:
			- b OR bordered
			- n OR no-border
			- t OR titled
			- d OR document
			- m OR modal
			- f OR floating
			
	-F	change the FEEL of the selected window:
			- n OR normal
			- ms OR modal-subset
			- mp OR modal-app
			- ml OR modal-all
			- fs OR floating-subset
			- fp OR floating-app
			- fl OR floating-all
			
	-G	change the FLAGS of the selected window, multiple values are accepted separated by commas
			- nm OR not-movable
			- nr OR not-resizable
			- nh OR not-h-resizable
			- nv OR not-v-resizable
			- fs OR accept-first-click
			- nc OR not-closable
			- nz OR not-zoomable
			- af OR avoid-front
			- nw OR no-workspace-activation
			- as OR avoid-focus
			- nb OR not-minimizable
			- na OR not_anchored
			- sp OR same-position
			- ce OR close-on-escape
			- r OR reset to cancel previous selection
			
	-M	minimize the selected window (1, t, true, on, y, yes / 0, f, false, off, n, no / toggle)
	
	-A	active the selected window (1, t, true, on, y, yes / 0, f, false, off, n, no / toggle)
	
	-m	move the selected window against the edges and corners of the screen:
		
		7	8	9		ul	u	ur		up-left		up		up-right
		
		4	5	6	OR	l	c	r	OR	left		center		right
		
		1	2	3		dl	d	dr		down-left	down		down-right
			
	-H	as the -m option but the selected window will be moved to the edges resized to half the screen size, a quarter of the screen size to the corners
	
	-r	resize the frame of the selected window to width,height, centered with respect to the original window and avoiding going out of bounds"
	>&2
exit
}

CheckArgs()
{
if [ $(echo -n "$1" | wc -c) -eq 2 ] && [ $(echo -n "$1" | awk '/-/{print}') ]
then
	OPTIND=`echo ${OPTIND}-1`
	return 1
fi	
}

SetWorkspace ()
{
[ "$1" != "all" ] && hey -o "${app_name}" set Workspaces of Window "${win_ID}" to `echo -n $1 | awk '{for(i=1;i<=NF;i++) print ($i-1)}' FS="[^0-9]" | sort -u | awk '{val+=2^($0)} END {print val}'` || hey -o "${app_name}" set Workspaces of Window "${win_ID}" to -1
}

EnlistWindows()
{
for (( i=0;i<=`echo $(hey "${app_name}" Count of Window | awk '/result/{print $4}') - 1 | bc`;i++ )); do echo -n "$i) ";hey "${app_name}" get Title of Window "$i" | awk '/result/{print $4}' FS="\""; done
}

ChangeTitle ()
{
hey -o "${app_name}" set Title of Window "${win_ID}" TO "$1"
}

ResizeFrame()
{
hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[\
$((echo -n "$1,"; hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}'; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{\
if ($1<$9) {x_pos=int($3+(($5-$3-$1)/2)); wx_pos=x_pos+$1; if (x_pos<0) {wx_pos-=x_pos;x_pos=0;};if (wx_pos>$9){delta=(wx_pos-$9);wx_pos-=delta;x_pos-=delta;}}\
else {x_pos=0;wx_pos=$9;};\
if ($2<$10) {y_pos=int($4+(($6-$4-$2)/2)); wy_pos=y_pos+$2; if (y_pos<0) {wy_pos-=y_pos;y_pos=0;};if (wy_pos>$10){delta=(wy_pos-$10);wy_pos-=delta;y_pos-=delta;}}\
else {y_pos=0;wy_pos=$10;};\
print x_pos,y_pos,wx_pos,wy_pos}' FS="," OFS=",")]
}
PlaceOnEdges()
{
case $1 in
	7|ul|up-left)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0,0,"($3-$1),($4-$2)}' FS="," OFS=",")]
		;;		
	8|u|up)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print int(($7-($3-$1))/2),"0",int(($7+($3-$1))/2),($4-$2)}' FS="," OFS=",")]
		;;		
	9|ur|up-right)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print ($7-($3-$1)),"0",$7,($4-$2)}' FS="," OFS=",")]
		;;		
	4|l|left)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print "0",int(($8-($4-$2))/2),($3-$1),int(($8+($4-$2))/2)}' FS="," OFS=",")]
		;;
	5|c|center)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print int(($7-($3-$1))/2),int(($8-($4-$2))/2),int(($7+($3-$1))/2),int(($8+($4-$2))/2)}' FS="," OFS=",")]
		;;		
	6|r|right)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print ($7-($3-$1)),int(($8-($4-$2))/2),$7,int(($8+($4-$2))/2)}' FS="," OFS=",")]
		;;	
	1|dl|down-left)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print "0",($8-($4-$2)),($3-$1),$8}' FS="," OFS=",")]
		;;
	2|d|down)
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print ($7-($3-$1))/2,($8-($4-$2)),int(($7+($3-$1))/2),$8}' FS="," OFS=",")]
		;;
	3|dr|down-right) # lower right corner. half screen size
		hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$((hey "${app_name}" get Frame of Window "${win_ID}" | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");printf "%s,",$0}' ; hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print $0}') | awk '{print ($7-($3-$1)),($8-($4-$2)),$7,$8}' FS="," OFS=",")]
		;;
	*)
		Usage
	;;
esac
}
SplitOnEdges()
{
case $1 in
	7|ul|up-left) # upper left corner, 1/4 screen size
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0","0",int($3/2),int($4/2)}' FS="," OFS=",")]
		;;		
	8|u|up) # upper half screen height
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0","0",$3,int($4/2)}' FS="," OFS=",")]
		;;		
	9|ur|up-right) # upper right corner, 1/4 screen size
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print int($3/2),"0",$3,int($4/2)}' FS="," OFS=",")]
		;;		
	4|l|left) # left half screen width
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0","0",int($3/2),$4}' FS="," OFS=",")]
		;;
	5|c|center) # middle screen, half screen size	
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print int($3/4),int($4/4),int($3*3/4),int($4*3/4)}' FS="," OFS=",")]
		;;		
	6|r|right) # right half screen width
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print int($3/2),"0",$3,$4}' FS="," OFS=",")]
		;;	
	1|dl|down-left) # lower left corner. half screen size
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0",int($4/2),int($3/2),$4}' FS="," OFS=",")]
		;;
	2|d|down) # lower half screen height
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print "0",int($4/2),$3,$4}' FS="," OFS=",")]
		;;
	3|dr|down-right) # lower right corner. half screen size
	hey -o "${app_name}" set Frame of Window "${win_ID}" TO BRect[$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");gsub(" ","");print int($3/2),int($4/2),$3,$4}' FS="," OFS=",")]
		;;
	*)
		Usage
	;;
esac
}
FullScreen()
{
hey -o "${app_name}" set Frame of Window "${win_ID}" to "BRect(\
$(hey Tracker get Frame of Window 0 | awk '/result/{sub(/^.*\(/,"");sub(/\)/,"");print}')"
}
ChangeLook()
{
case $1 in
	b|bordered)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 20
		;;
	n|no-border)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 19
		;;
	t|titled)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 1
		;;
	d|document)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 11
		;;
	m|modal)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 3
		;;
	f|floating)
		hey -o "${app_name}" set Look of Window "${win_ID}" to 7
		;;
	*)
		Usage
		;;
esac
}
ChangeFeel()
{
case $1 in
	n|normal)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 0
		;;
	ms|modal-subset)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 2
		;;
	mp|modal-app)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 1
		;;
	ml|modal-all)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 3
		;;
	fs|floating-subset)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 5
		;;
	fp|floating-app)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 4
		;;
	fl|floating-all)
		hey -o "${app_name}" set Feel of Window "${win_ID}" to 6
		;;
	*)
		Usage
		;;
esac
}
SumFlags()
{
case $1 in
	nm|not-movable)
		let flags+=1
		;;
	nr|not-resizable)
		let flags+=2
		;;
	nh|not-h-resizable)
		let flags+=4
		;;
	nv|not-v-resizable)
		let flags+=8
		;;
	fs|accept-first-click)
		let flags+=16
		;;
	nc|not-closable)
		let flags+=32
		;;
	nz|not-zoomable)
		let flags+=64
		;;
	af|avoid-front)
		let flags+=128
		;;
	nw|no-workspace-activation)
		let flags+=256
		;;
	as|avoid-focus)
		let flags+=8192
		;;
	nb|not-minimizable)
		let flags+=16384
		;;
	na|not_anchored)
		let flags+=131072
		;;
	sp|same-position)
		let flags+=2097152
		;;
	ce|close-on-escape)
		let flags+=8388608
		;;
	r|reset)
		return
		;;
	*)
		Usage
		;;
esac
}
ChangeFlags()
{
flags=1572864
while read line; do
SumFlags ${line}
done <<< $( echo $1 | tr "," "\\n" )
hey -o "${app_name}" set Flags of Window "${win_ID}" to ${flags} 
}
ToggleActive()
{
case $1 in
	1|t|true|on|y|yes)
		hey -o "${app_name}" set Active of Window "${win_ID}" to true
		;;
	0|f|false|off|n|no)
		hey -o "${app_name}" set Active of Window "${win_ID}" to false
		;;
	toggle)
		active=`hey -o "${app_name}" get Active of Window "${win_ID}"`
		[ "${active}" == "true" ] && ToggleActive 0 || ToggleActive 1
		;;
	*)
		Usage
		;;
esac
}
ToggleMinimize()
{
case $1 in
	1|t|true|on|y|yes)
		hey -o "${app_name}" set Minimize of Window "${win_ID}" to true
		;;
	0|f|false|off|n|no)
		hey -o "${app_name}" set Minimize of Window "${win_ID}" to false
		;;
	toggle)
		minimized=`hey -o "${app_name}" get Minimize of Window "${win_ID}"`
		[ "${minimized}" == "true" ] && ToggleMinimize 0 || ToggleMinimize 1
		;;
	*)
		Usage
		;;
esac
}
###############
# main script #
###############
script_name="$(basename ${0})"
if [ $# -ne 0 ]
then
	while getopts "a:hlfs:t:w:L:F:m:H:r:M:A:G:" script_opt
	do
		case ${script_opt} in
		a)
			app_name="$OPTARG"
			;;
		l)
			[ -n "${app_name}" ] && EnlistWindows
			exit
			;;
		s)
			[ -n "${app_name}" ] && win_ID="$OPTARG" || Usage
			;;
		m)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	PlaceOnEdges "$OPTARG"
			else
				Usage
			fi
			;;	
		H)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	SplitOnEdges "$OPTARG"
			else
				Usage
			fi
			;;
		f)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				FullScreen
			else
				Usage
			fi
			;;
		t)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ChangeTitle "$OPTARG"
			else
				Usage
			fi
			;;
		w)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	SetWorkspace "$OPTARG"
			else
				Usage
			fi
			;;
		r)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ResizeFrame "$OPTARG"
			else
				Usage
			fi
			;;
		L)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ChangeLook "$OPTARG"
			else
				Usage
			fi
			;;
		F)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ChangeFeel "$OPTARG"
			else
				Usage
			fi
			;;
		G)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ChangeFlags "$OPTARG"
			else
				Usage
			fi
			;;
		A)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ToggleActive "$OPTARG"
			else
				Usage
			fi
			;;
		M)
			if [ -n "${app_name}" ] && [ -n "${win_ID}" ]
			then
				CheckArgs "$OPTARG"
				[ $? -ne 1 ] &&	ToggleMinimize "$OPTARG"
			else
				Usage
			fi
			;;
		h|*)
			Usage
			;;
		esac
	done
else
	Usage
fi
exit

so basically if I want to have my Terminal with a size of 400x400 px, sitting at the upper left corner of the screen, visible in all workspaces, not closable not movable, with no borders the line is:

winpwnr.sh -a Terminal -s 0 -r 400,400 -w all -L no-border -m up-left -G not-closable,not-movable

3 Likes