Start and check name of window on virtual X display - python

I'm writing a test on Ubuntu 18.04. I want to create a virtual display, start a window on it, and check the window name. In three separate shells I'm running:
Xvfb :4 -screen 0 1920x1080x24+32 -fbdir /var/tmp
then
DISPLAY=:4 xterm
then
DISPLAY=:4 xdotool getwindowfocus getwindowname
That last command returns
XGetInputFocus returned the focused window of 1. This is likely a bug in the X server.
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 20 (X_GetProperty)
Resource id in failed request: 0x1
Serial number of failed request: 20
Current serial number in output stream: 20
That error seems to come from xdotool:
int xdo_get_focused_window(const xdo_t *xdo, Window *window_ret) {
int ret = 0;
int unused_revert_ret;
ret = XGetInputFocus(xdo->xdpy, window_ret, &unused_revert_ret);
/* Xvfb with no window manager and given otherwise no input, with
* a single client, will return the current focused window as '1'
* I think this is a bug, so let's alert the user. */
if (*window_ret == 1) {
fprintf(stderr,
"XGetInputFocus returned the focused window of %ld. "
"This is likely a bug in the X server.\n", *window_ret);
}
return _is_success("XGetInputFocus", ret == 0, xdo);
}
I just want to do the minimal thing to get a virtual display, start a window on it, and check the window name.
What should I do?

Related

Killing a Python process from Node doesn't kill Python's child process (child process being ffmpeg.exe)

I am developing an Electron application. In this application, I am spawning a Python process with a file's path as an argument, and the file itself is then passed to ffmpeg (through the ffmpeg-python module) and then goes through some Tensorflow functions.
I am trying to handle the case in which the user closes the Electron app while the whole background process is going. From my tests though, it seems like ffmpeg's process stays up no matter what. I'm on Windows and I'm looking at the task manager and I'm not sure what's going on: when closing the Electron app's window, sometimes ffmpeg.exe will be a single process, some other times it will stay in an Electron processes group.
I have noticed that if I kill Electron's process through closing the window, the python process will also close once ffmpeg has done its work, so I guess this is half-working. The problem is, ffmpeg is doing intensive stuff and if the user needs to close the window, then the ffmpeg process also NEEDS to be killed. But I can't achieve that in any way.
I have tried a couple things, so I'll paste some code:
main.js
// retrieve video data
ipcMain.handle('get-games', async (event, arg) => {
const spawn = require('child_process').spawn;
const pythonProcess = spawn('python', ["./backend/predict_games.py", arg]);
// sets pythonProcess as a global variable to be accessed when quitting the app
global.childProcess = pythonProcess;
return new Promise((resolve, reject) => {
let result = "";
pythonProcess.stdout.on('data', async (data) => {
data = String(data);
if (data.startsWith("{"))
result = JSON.parse(data);
});
pythonProcess.on('close', () => {
resolve(result);
})
pythonProcess.on('error', (err) => {
reject(err);
});
})
});
app.on('before-quit', function () {
global.childProcess.kill('SIGINT');
});
predict_games.py (the ffmpeg part)
def convert_video_to_frames(fps, input_file):
# a few useful directories
local_dir = os.path.dirname(os.path.abspath(__file__))
snapshots_dir = fr"{local_dir}/snapshots/{input_file.stem}"
# creates snapshots folder if it doesn't exist
Path(snapshots_dir).mkdir(parents=True, exist_ok=True)
print(f"Processing: {Path(fr'{input_file}')}")
try:
(
ffmpeg.input(Path(input_file))
.filter("fps", fps=fps)
.output(f"{snapshots_dir}/%d.jpg", s="426x240", start_number=0)
.run(capture_stdout=True, capture_stderr=True)
)
except ffmpeg.Error as e:
print("stdout:", e.stdout.decode("utf8"))
print("stderr:", e.stderr.decode("utf8"))
Does anyone have any clue?
Alright, I was finally able to fix this! Since ffmpeg-python is just a collection of bindings for good old ffmpeg, the executable itself is still at the core of the module. This also means that when ffmpeg is running, a screen similar to this:
...
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
Stream mapping:
Stream #0:0 (h264) -> fps:default
fps:default -> Stream #0:0 (mjpeg)
...
Press [q] to stop, [?] for help
is what's going on behind the scenes. Once I realized this, all I had to do was find a way to send a 'q' to ffmpeg's stdin. And I did it by adding this snippet on the window-all-closed event:
app.on('window-all-closed', () => {
// writes a 'q' in ffmpeg's terminal to quit ffmpeg's process
// reminder: python gets closed when the Electron app is closed
global.childProcess.stdin.write("q\n");
if (process.platform !== 'darwin') app.quit()
})
The Python script itself is untouched compared to the snippet in the question, and this is the only thing I ended up modifying. Now everytime I quit my Electron app, ffmpeg gets sent a 'q'. The Python process doesn't need to be manually killed because Electron already does that for you.
So problem solved. :)

How to take screenshot of Chromebook in Linux command-line?

In Linux on my Chromebook, I am trying to take a screenshot using the command line, but nothing seems to be working. I have tried ImageMagick...
sudo apt-get install imagemagick
import -window root filename.png
# "unable to read X window image 'root'"
import filename.png
# "unable to grab mouse '': No such file or directory"
And I have also tried scrot...
sudo apt-get install scrot
scrot -u filename.png
#"BadDrawable (invalid Pixmap or Window parameter)"
I tried several python methods, but the only one that I could successfully install and get to run without errors was pyscreeze (which uses scrot), and it produced nothing but a blank, black image, which is useless to me.
In terms of other python methods, I tried pyautogui which failed to install, telling me "Failed building wheel for Pillow." I tried pyscreenshot, which installed and ran but told me "All backends failed." I also tried ImageGrab, which told me "ImageGrab is MacOS and Windows only."
Does anyone know of a way to make this work?
Thanks in advance!
Javascript solution
Here is a way to take a screenshot of any part of the chromebook's screen, a chrome window, or a chrome tab.
Paste this into your browser console to take a screenshot.
async function takeScreenshot(format = "image/png") {
const stream = await navigator.mediaDevices.getDisplayMedia({video:true});
const video = document.createElement("video");
video.srcObject = stream;
video.muted = true;
await video.play();
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext("2d");
context.drawImage(video, 0, 0);
const blob = await new Promise(resolve => canvas.toBlob(resolve, format));
stream.getTracks().forEach(track => track.stop());
return blob;
}
function download(blob, name = "Untitled") {
const elt = document.createElement("a");
elt.download = name;
elt.href = URL.createObjectURL(blob);
elt.click();
URL.revokeObjectURL(elt.href);
}
takeScreenshot("image/png").then(blob => download(blob, "Screenshot.png"));
I don't have a solution but an idea how to do this
You need chromebook in developer mode to have access to the actual Linux console, not the virtual machine linux that you install via "settings" app
As chromebook is on Wayland, you need to use something like grim which works on Wayland and not scrot which is for X Windows
You could use native wayland-enabled Linux chroot like https://github.com/nmilosev/crouton-fedora-wayland to install grim and other wayland native tools

Segmentation fault occurs when a C++ program is reading a file while a separate python GUI script is writing to the same file

I am currently running this on Raspbian OS - Debian.
I have two separate programs running in unison. I have a c++ 'engine' and a python 'gui' interface. I know there is probably a much better practice, but at the moment they are communicating via flat files. Essentially the python GUI writes to a file, cmd.sf, with specific text and the engine then decodes that exact same file and executes whatever it needs to do.
The setup is quite simple:
C++ Engine:
The C++ program is constantly reading the cmd.sf file and stays in an infinite loop within the engine if the context of the file is -1. The moment the file changes the engine should parse what the Python GUI essentially wrote and upon successful execution of whatever the contents told the engine to do, it writes back to the file -1
Python GUI
On the GUI end, it's the same concept except it is reversed. GUI also constantly reads from the cmd.sf file and doesn't proceed with writing the same or different instruction until it knows the C++ engine is done with its previous instruction. So it essentially checks the file to make sure it is anything BUT -1
The problem lies where if I initially set cmd.sf to -1, the C++ engine does what it needs to do successfully, by constantly reading and checking the contents of the file. However, the moment I instruct the GUI to change the file's contents, the C++ engine hangs, spits out a seg fault, and aborts.
However, I have found something that does work and I can not for the life of me figure out why. If I was to open cmd.sf in a text-editor such as geany (I am Raspbian) and change the contents via the editor and save it, it does not cause a segfault error. In fact the C++ engine notices the change of the file contents, executes the instruction appropriately and write -1 back to the file. It seems to not like it when I programatically change the contents of the file.
Here is a snippet of my python code that changes the contents of the file, this is nested in a loop:
scan_cmd = AllCommands.start_scan
# generate the key cmd packet for engine to start listening to incoming switches
#
# with open("../data/switches_debug.sf") as sw_file:
# switch_ids = [i.split(",")[0] for i in sw_file.readlines()]
# #print(switch_ids)
packet = CommandPacket(0xFFFFFF, scan_cmd)
content = ""
can_edit_file = False
while not can_edit_file:
with open("../data/cmd.sf", "r") as cmd_file:
try:
content = int(cmd_file.readlines()[0])
except ValueError:
# means gui has already written to file and is in the form of x,x,x,...,x
# 12345,67,8
# The beginning of this function should just check to see if
# file content IS NOT -1 in order to prevent engine and gui
# writing to the file at the same time
#
# So if GUI has written to file and in the
# form of csv, it is obviously not -1
#
# assign content a value that is not -1
content = 0
if content == -1:
can_edit_file = True
msg = "Begin Listening... [%s]" % packet.hex()
print(msg)
content = ','.join(str(x) for x in packet.plist)
# open as 'w' to overrite content of file
with open("../data/cmd.sf", "w") as cmd_file:
cmd_file.write(content)
print("Wrote [%s] to ../data/cmd.sf" % packet.hex())
Similarly, this is the C++ code that reads and checks if the file has changed:
Scribe Cher("../data/cmd.sf");
for (;;) {
std::cout << std::flush;
// cpu_timer tmr;
// loop forever and read from cmd.sf for instructions
// if file contents is != -1 instruction from GUI is set; read and execute
// upon successful instruction execution write '-1' to file
// read contents of cmd.sf file
bool file_is_ready = false;
int u = 0;
do{
Cher.ReadFile(); // custome object that actually does the reading
cmd_file = std::stoi(Cher.FileContents); // Cher.FileContents is std::string
//debugging section
if(u % 10000 == 0){
std::cout << std::flush;
fmt::printf("File Contents: {%s}\n", Cher.FileContents);
}
if(cmd_file != -1){
file_is_ready = true;
}
u++;
}while(!file_is_ready);
}
The Cher instance is of object Scribe with is a helper class that controls reading/writing to files. Upon initialization, it sets one important member within the class and that is the path to file.. each "Scribe" is assigned to one file.
void Scribe::ReadFile(){
std::string file_contents;
std::vector<std::string> vstring;
this->File.close(); //in case the file is opened
if(!this->File.open(std::ios::in)){
throw std::ios::failure("Unable to open file.");
//std::cout << "Unable to Open" << std::endl;
}
this->File.clear();
this->File.seekg(0, std::ios_base::beg);
while(this->File >> file_contents){
std::cout << "infinite loop" << std::endl;
vstring.push_back(file_contents);
}
//for(auto &i: vstring){
// std::cout << i << std::endl;
//
this->FileContents = vstring[0];
this->File.close();
}
Here is an example stdout output from the terminal when I run this by initially setting the cmd.sf to -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
Segmentation Fault //this is when I use the python gui to change file contents

Sending Multiple Serial Bytes from Arduino to Python to Display Images

Essentially, I've been trying to write a program that when you push a specific button, a specific image appears. For example, if I push Button1, Image1 will be displayed. Next, if I push Button2, Image1 will disappear and Image2 will displayed. The problem I ran into is regarding button2. Eventually, I would like it so that many image files can be opened. Right now, I have serial data being sent from the arduino to a raspberry pi with python. The python program recognizes button1 being pressed and displays the image. However, when I press button2 (before or after pressing button1), the program stops and an error message appears.
Any help to resolve this issue would be great!
I have tried altering the bytes sent from the Arduino but it was to no avail. I am new to serial data processing so there could be something I have missed.
Arduino Code
int First=2;
int buttonState=0;
int Second=3;
int buttonState2=0;
void setup()
{
Serial.begin(9600);
pinMode(First, INPUT);
pinMode(Second, INPUT);
}
void loop()
{
int buttonState=digitalRead(First);
int buttonState2=digitalRead(Second);
if(buttonState==HIGH)
{
Serial.print(0x0);
delay(100);
}
if (buttonState==LOW)
{
//do nothing
}
//BUTTON STATE SECOND
if(buttonState2==HIGH)
{
Serial.print(0x1);
delay(100);
}
if (buttonState2==LOW)
{
//do nothing
}
}
Python Code(The formatting for two lines is off due to how the question is posted):
import numpy
import cv2, glob
import sys
import os
import serial
from subprocess import Popen
ser=serial.Serial('/dev/ttyUSB0',9600)
Title = cv2.imread('/home/pi/Desktop/Avengers/Title.jpg')
Zero = cv2.imread('/home/pi/Desktop/Avengers/000.jpg')
while True:
command = ser.read()
if command:
#flush serial for unprocessed data
ser.flushInput()
print("new command:", command)
if (int(command) == 0):
cv2.namedWindow("Title", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Title",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.imshow('Title', Title)
cv2.waitKey(0)
cv2.destroyAllWindows()
if (int(command) == 1):
cv2.namedWindow("Zero", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Zero",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.imshow('Zero', Zero)
cv2.waitKey(0)
cv2.destroyAllWindows()
I expect one image to displayed when I push a button, and another image to be displayed when I push the other button. The results of the code allow one button to display an image. However, when the other button is pushed, no image is displayed. In short, one button works and the other doesn't. An error message reads:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 490, in read
'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/pi/OpenJPG.py", line 14, in <module>
command = ser.read()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 497, in read
raise SerialException('read failed: {}'.format(e))
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

Communication with the USB device in Python

I want to communicate with and send data to a USB device. I am able to find the device but while attaching the device with the kernel driver it is giving USB Error: Resource Busy. The following is my code:
import usb
dev = usb.core.find(idVendor=0x0403, idProduct=0x6001)
dev.set_configuration()
cfg = dev.get_active_configuration()
dev.attach_kernel_driver(interface)
interface_number = cfg[(0, 0)].bInterfaceNumber
alternate_settting = usb.control.get_interface(interface_number)
intf = usb.util.find_descriptor(
cfg, bInterfaceNumber=interface_number,
bAlternateSetting=alternate_setting)
ep = usb.util.find_descriptor(
intf, custom_match=lambda e:
usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
dev.detach_kernel_driver(interface)
ep.write("\r" + linea1[:19] + "\n\r" + " " * (20 - len(linea2)) + linea2)
Assuming your using Linux and libusb-1.0 as a PyUSB's backend library.
According to the libusb documentation:
// Detach a kernel driver from an interface.
// If successful, you will then be able to claim the interface and perform I/O.
int libusb_detach_kernel_driver (libusb_device_handle *dev,
int interface_number)
// Re-attach an interface's kernel driver, which was previously
// detached using libusb_detach_kernel_driver().
int libusb_attach_kernel_driver(libusb_device_handle *dev,
int interface_number)
So basically, you need to call detach_kernel_driver first to detach already attached kernel driver (if any) from the device's interface, so you can communicate with it in your code (it's either your code or some kernel driver talking to the device's interface). When you're done, you may want to call attach_kernel_driver to re-attach the kernel driver again.
I believe there's no need to call any of those C functions/Python methods if you can ensure that no kernel driver is loaded for a given device (or manually unload it before running your code).
Edit:
I just got this piece of code (based on your sample) working. Note: for simplicity I've hardcoded 0 as interface number for detach_kernel_driver and attach_kernel_driver - you should make it smarter, I suppose.
import usb
dev = usb.core.find(idVendor=0x0403, idProduct=0x6001)
reattach = False
if dev.is_kernel_driver_active(0):
reattach = True
dev.detach_kernel_driver(0)
dev.set_configuration()
cfg = dev.get_active_configuration()
interface_number = cfg[(0,0)].bInterfaceNumber
alternate_settting = usb.control.get_interface(dev, interface_number)
intf = usb.util.find_descriptor(cfg, bInterfaceNumber = interface_number,
bAlternateSetting = alternate_settting)
ep = usb.util.find_descriptor(intf,custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
ep.write("test\n\r")
# This is needed to release interface, otherwise attach_kernel_driver fails
# due to "Resource busy"
usb.util.dispose_resources(dev)
# It may raise USBError if there's e.g. no kernel driver loaded at all
if reattach:
dev.attach_kernel_driver(0)

Categories