Retrieving active window from Mutter on Gnome/Wayland session - gnome

I'm trying to write an application that sends different dBus signals to different applications depending on what application is active. The idea is to pair it with Libinput-gestures, and allow per application gesture response. Problem is, it's impossible to tell which application is active on the client side.
I've been doing some research into detecting if an application has focus on any particular window manager under Wayland. Consensus is, Wayland doesn't know if an application has focus, and will not give that information. However the window manager itself does know.
So is there a way of creating an entirely server side routine for gnome, to send the title of the active window client side, to a select number of applications. In other words, we still have the "security" of not letting arbitrary applications know everything about the environment, but still allow some accessibility minded software retrieve that information and use it.

Almost 2 years old, but here it goes!! I don't know for sure if Mutter may have a way to do this as well, or if there is a better way to do the following. I suspect with better knowledge of gdbus and further research you can also convert this into some sort of official gdbus monitoring that can communicate with other apps so you do not have to ping for the status.
This is specific to Gnome and I suspect works on at least 3.15+. Tested on Ubuntu 19.10 Wayland. (Gnome 3.34.2)
# Single Command, runs 2 calls to gdbus to get the currently active Window from Gnome 3.x
# Escaped so you can copy and paste into terminal directly
gdbus call -e -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval global.get_window_actors\(\)[`gdbus call -e -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval global.get_window_actors\(\).findIndex\(a\=\>a.meta_window.has_focus\(\)===true\) | cut -d"'" -f 2`].get_meta_window\(\).get_wm_class\(\) | cut -d'"' -f 2
# Unescaped version, will not run
# Broken down into 2 commands.
# Call to Gnome to get the array location of the active Application
gdbus call -e -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval \
global.get_window_actors().findIndex(a=>a.meta_window.has_focus()===true) \
| cut -d"'" -f 2
# Replace the array number 2 with the one from the previous command and you will get the App Name of the actively focused Window
gdbus call -e -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval \
global.get_window_actors()[2].get_meta_window().get_wm_class() \
| cut -d'"' -f 2
And here is a gist I made as a note to myself, same as the code above. https://gist.github.com/rbreaves/257c3edfa301786e66e964d7ac036269
I also have a non-gdbus method on how to do something similar for KDE5 Plasma under Wayland up on my github for anyone interested. (added some code to an existing Plasmoid that was retrieving the class names already.)

The following works with Gnome 43:
Install https://extensions.gnome.org/extension/4974/window-calls-extended/
Run gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/WindowsExt --method org.gnome.Shell.Extensions.WindowsExt.FocusPID | sed -E "s/\\('(.*)',\\)/\\1/g" to get the PID of the focussed window or use a different method.

Related

send notification from virtual machine (docker container) to host machine

I m trying to make notify-send passing messages to host and create a notification on my desktop from my local-machine. But its not that simple :(.
My Operation system is Ubuntu and vm machine's Debian.
I know that containers communicating with "bridge" in docker or via "volume"
My approche was to install dbus-monitor,libnotify-bin on virtual machine
Write to file called notofications via demon who intercept notify-send messages.
Than have some sort of deamon on host machine which "watch" that file and everytime a new line of text is being added to that from virtual machine, deamon triggers launch a command notify-send "that line"
Usecase:
I work with docker container workspace.
I m developing websites and I found it pretty annoying that when I m "live building" script and it fails I dont get a notification.
So I wanted to get one with having same environment accross my teamates using ddev
Problem:
To intercept and write to file I tried to use dbus but:
my dbus-monitor script:
#!/bin/bash
file=notifications
dbus-monitor "interface='org.freedesktop.Notifications'" |\
grep --line-buffered "string" |\
grep --line-buffered -e method -e ":" -e '""' -e urgency -e notify -v |\
grep --line-buffered '.*(?=string)|(?<=string).*' -oPi |\
grep --line-buffered -v '^\s*$' |\
xargs -I '{}' echo {} >> $file
seemss not to work without display configuration. And I have no idea how to fix that.
Failed to open connection to session bus: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
In order to work I need to find solution to somehow "watch"
notify-send command and intercept the message. Please help :)

How to make a single window vnc session with x11vnc?

I want to create a VNC session to expose a single application that I start on a virtual display. And I want to do it with x11vnc because after that I can expose it through noVNC.
The problem is that x11vnc allows me to create a virtual display:
x11vnc -create
... or to expose a single window of an already launched application
x11vnc -id 0x200002
but I did not find any option to start a new application in a new virtual display (like xstartup for vncserver).
So far the only solution I found is to do all the procedure manually
# create a virtual display on the compute node
Xvnc :33 &
# launch the application on this virtual display
export DISPLAY=:33
glxgears &
# find out its window id
xwininfo -root -children
# -> xwininfo: Window id: 0xdc (the root window) (has no name)
#
# Root window id: 0xdc (the root window) (has no name)
# Parent window id: 0x0 (none)
# 1 child:
# 0x200002 "glxgears": () 300x300+0+0 +0+0
# start the vnc server with this specifix xid
x11vnc -id 0x200002 &
It works but it is a bit complex and I still have to write a small command to get the xid automatically.
I don't have enough "reputation" to write a comment, so I have to write my own answer despite this being just a modification to Michael's answer, which TBH I have yet to test. I came up with a quick hack to get the window ID since I won't be able to input it manually. Try this to find out the Window ID:
window_id=$(xwininfo -root -tree | grep glxgears | tail -n1 | sed "s/^[ \t]*//" | cut -d ' ' -f1)
So you're getting the tree, filtering for the program you're looking for, getting the last option, removing trailing whitespace, then getting only the first column, and saving it. Then you can run...
x11vnc -id $window_id &
...to the same effect as Michael's answer. Hopefully. Like I said, it's a hack.
Nice one for sharing windows at the office !
echo "Select Window...";x11vnc -id $(xwininfo|grep -oP '(?<=id: ).*(?= ")') -viewonly -forever
Or a shorter one:
x11vnc -id pick -viewonly -forever
x11vnc supports sharing a window based on it’s id. Here you can take simulator as window and share it.
Below is steps:
Run xwininfo from a terminal. Click on the window you want to
share. xwininfo will print out the window id.
Run `x11vnc -id win_id take win_id from above steps.
Example command:
x11vnc -id 0x2800005

Linux Show a message to the connected display without logging

Hello I am trying to secure a linux machine that I have built.
I want to prevent people from clonning the hard disk drive.
I have a script that runs with init on startup and every 1 hour.
Script is something like this. It has hard coded hard disk drive serial number, motherboard serial number and few other serials. Script checks the serial of number of the hard drive and mother against hard coded serial. If it does not match. It sends a halt message to the system and the system shuts down.
Now I want to display a message on the connected display / monitor before halting the system. Obviously user wont be logged on when this happens. So I am looking for a way to send the message to the screen without logging.
Here is the script snippet.
#!/bin/bash
$coded-hdserial="W4837486938473ASD534354"
$coded-mbserial="XFD6345-32423-IRJDFJDF-234823729"
$check-hdserial=`smartctl -i /dev/sda | grep "Serial Number" | awk -F ":" {'print $2'} | sed -e 's/^[ \t]*//'`
$check-mbserial=`lshw | grep -A 15 "*-core" | grep "serial:" | awk -F ":" {'print $2'} |sed -e 's/^[ \t]*//' | tr -d '.'`
if
$coded-hdserial == $check-hdserial
then
echo "OK" >/dev/null 2>&1
else
echo "This copy of the software cannot be validated, it may be is a counterfeit. Therefore you cannot continue to enjoy the privilege to use this software. Please contact the support for further information.
This system will now be shut down. Further attempts to make counterfeit or duplicate copies of this system will initiate the self destruction and you will loose all data."
halt in 1 minute
fi
if
$coded-mbserial == $check-mbserial
then
echo "OK" >/dev/null 2>&1
else
echo "This copy of the software cannot be validated, it may be is a counterfeit. Therefore you cannot continue to enjoy the privilege to use this software. Please contact the support for further information.
This system will now be shut down. Further attempts to make counterfeit or duplicate copies of this system will initiate the self destruction and you will loose all data."
halt in 1 minute
fi
My question how can I display a good nice looking warning message to connected monitor. Or probably a JPG image on the screen with warning.
Look at kernel support for frame buffer devices to which you might be able to dump raw pixel data like from a bitmap image file. This is how the GRand Unified Bootloader (GRUB) makes a graphical boot menu. No need for X, but you won't get actual dialog windows. If you want a lightweight ASCII art interactive menu system, look at a Curses implementations like ncurses.

DSH (dancer's shell) hangs when getting tail -f logs

I'm using dancer's shell dsh (http://www.netfort.gr.jp/~dancer/software/dsh.html.en) to send a tail -f command to 6 machines. I was hoping to use this to view a merged log from a service which resides in the same directory on each of these machines. The machines are all running RHEL 4. (Not my choice.)
What actually happens, is that I retrieve 4-20 lines from each log and then it just hangs.
Here are my options:
dsh -c -M -r ssh -g services -- /usr/bin/tail -f /var/myservice/my.log
"services" refers to a group of 6 servers.
I've tried several different ssh options in the dsh.conf file, including -n, -t, and -f, but it doesn't seem to make a difference. Also, screen is not installed on the target servers.
What's wrong with my command? How can I make it act like a proper tail -f?
It turns out chepner's comment is right. Those logs just don't create much output. I tried the identical command with a set of more active web applications and it works fine.
I know that command as "distributed shell", but no matter.
I'm suspicious the double-dash in the middle of your command string is asking for it to accept stdin input, which indeed would make it appear to hang. Try it without the "--"

Bash Script Block All Apple Devices

I am trying to create a shell script to block all apple devices on my network. I am using nmap for os detection. What I have so far is this:
while (true) do
nmap -O -T4 -p 22,80 -v 172.20.0.0/24 | grep -B9 'OS details: Apple' | \
grep 'Nmap scan report for' | cut -f4 -d'r' | cut -f2 -d' ' | \
iptables -i wlan0 -A INPUT -j DROP -s
sleep 10
done
Is there a way to simplify this at all so there is less grepping and cutting involved?
Also, this script will run into errors if there are more than one or zero apple devices found on the network. Is it possible to add logic for that?
Yes, of course it is possible. You can use perl/awk to simplify the script a lot.
Also, I'm not sure that your script is correct at the moment.
You have a pipe that write addresses to iptables, but iptables
doesn't work this way.
If you want to run iptables for each address that is produced by nmap,
you can read the addresses using read to some variable (in my example ADDR)
and then use the variable in iptables:
while (true) do
nmap -O -T4 -p 22,80 -v 172.20.0.0/24 | grep -B9 'OS details: Apple' | \
grep 'Nmap scan report for' | cut -f4 -d'r' | cut -f2 -d' ' | \
while read ADDR
do
iptables -i wlan0 -A INPUT -j DROP -s $ADDR
done
sleep 10
done
A few more remarks:
You do not need the parenthesis around true. This starts a new subshell, which is inefficient. In this case, you probably won't care, but it's good practice to avoid needless subshells.
the $ADDR in Igor Chubin's answer is dangerous. If $ADDR contains a whitespace character, it will be split up into separate parameters. Someone on the network may be able to affect the output of NMap, and modify the structure of the iptables command. Even if this is not the case here, it's good practice to put the argument in between double quotes whenever possible to prevent this: "$ADDR".
for similar reasons, you'll usually want to use read -r instead of just read. Without the -r parameter, backslash characters in the input will escape subsequent special characters (such as spaces).
NMap has its own Lua scripting support. This is another way to go at this problem, which may prevent you from having to parse any text at all.
If you are physically on the same network, you may be able to block Apple devices without any NMap at all, by blocking devices based on the MAC address of the device. The first three bytes identify the organisation which issued the MAC address. You can look them up here. They can be faked on a rooted device, but then again, so can the NMap fingerprinting (though that would likely be harder).
An important part of scripting is understanding the programs you are using and how to get the appropriate output from them. It looks like you have a decent understanding of Nmap, since you limit the number of ports scanned (-p 22,80) and request OS detection (-O), but you could avoid a lot of text processing if you used the appropriate output format.
Nmap's "grepable" format is deprecated, meaning that it can't be used to get a lot of more-recent features' output, but it works just fine for OS detection. You request it with -oG. Here's an example, borrowing some looping help from #IgorChubin's excellent answer:
while (true) do
nmap -O -T4 -p 22,80 -oG - 172.20.0.0/24 | awk '/OS: Apple/{print $2}' | \
while read ADDR
do
iptables -i wlan0 -A INPUT -j DROP -s $ADDR
done
sleep 10
done
Some other improvements include moving the sleep 10 into the while condition of the outermost loop, to allow killing it with Ctrl-C during one of the sleeps. Also, be aware that DHCP leases expire, and the IP you are blocking may be assigned to a different system in the future. In general, this approach does not seem like the best way to accomplish what you want.

Resources