Question
I'm trying to find NET_WM_NAME property for each of the window/client that X11 reports. Problem is that there's nothing returned - number of items is 0 and returned data results in empty string. I've looked at multiple code examples through out github and examples written in C and C++ , specifically Why is XGetWindowProperty returning null? as well as Xlib XGetWindowProperty Zero items returned , however I cannot find where is the problem with my code. Seemingly everything is fine, order of parameters passed to XGetWindowProperty function is in accordance with documentation, and the function returns success status, but results are empty. Where is the problem with my code ?
Code
Below is the code I am working with. The issue is xgetwindowproperty function. The other parts below it work fine, and are provided only for completeness.
#! /usr/bin/env python3
import sys
from ctypes import *
def xgetwindowproperty(display,w):
actual_type_return = c_ulong()
actual_format_return = c_int()
nitems_return = c_ulong()
bytes_after_return = c_ulong()
prop_return = POINTER(c_ubyte)()
wm_name = Xlib.XInternAtom(display,'_NET_WM_NAME',False)
utf8atom = Xlib.XInternAtom(display,'UTF8_STRING',False)
print('_NET_WM_NAME',wm_name, 'UTF8_STRING',utf8atom)
# AnyPropertyType = c_long(0)
status = Xlib.XGetWindowProperty(
display,
w,
wm_name,
0,
65536,
False,
utf8atom,
byref(actual_type_return),
byref(actual_format_return),
byref(nitems_return),
byref(bytes_after_return),
byref(prop_return)
)
print(nitems_return.value) # returns 0
# empty string as result
print( 'Prop', ''.join([ chr(c) for c in prop_return[:bytes_after_return.value] ]) )
Xlib.XFree(prop_return)
print('#'*10)
# -------
Xlib = CDLL("libX11.so.6")
display = Xlib.XOpenDisplay(None)
if display == 0:
sys.exit(2)
w = Xlib.XRootWindow(display, c_int(0))
root = c_ulong()
children = POINTER(c_ulong)()
parent = c_ulong()
nchildren = c_uint()
Xlib.XQueryTree(display, w, byref(root), byref(parent), byref(children), byref(nchildren))
for i in range(nchildren.value):
print("Child:",children[i])
xgetwindowproperty(display,children[i])
Related
hie,
I'm writing my first big python program (3.8) and I try to use a function for several uses (same work but with different targets from existing attributes)
I hope it's clear enough.
here the wanted Job :
it's inside a QT5 GUI (QApplication)
class GuiSuperQuizz(QWidget, QApplication):
...
...
def ajout_pts_blindtest(self, nbr):
x = nbr
x = str(x)
eval("team" + x).ajou_pts(int(self.point_blindtest))
eval("self.score_equip_" + x).setText(str(eval("team" + x).point)) # bug is here
eval("self.gest_score_equip_" + x).setText(str(eval("team" + x).point))
print(eval("team" + x).point)
self.continu[0] = False
self.en_pause[0] = False
self.records_scores()
The interpreter do not recognize the attribute "score_equip_1" and give me an error
AttributeError: 'GuiSuperQuizz' object has no attribute 'score_equip_1'
Yet, I know that attribute works well with this other function that work fine
def ajout_pts_rap_team1(self):
team1.ajou_pts(int(self.point_rap))
self.score_equip_1.setText(str(team1.point))
self.gest_score_equip_1.setText(str(team1.point))
print(team1.point)
self.continu[0] = False
self.en_pause[0] = False
self.aff_ligne4()
self.records_scores()
For not writing 4 functions to target 4 variables that are just incremented (it's a Quizz game with 4 players) I try try to concatenate in 1 function that arrange targets.
if I test the same logic on a very simple lines that works:
test1 = 456
def test(nbr):
x = nbr
x=str(x)
print(eval("test"+x))
test(1)
456
If anyone got some explanations ....
I can't seem to get EnumThreadWindows to work. It keeps failing with error 87. Code:
error = ctypes.WinDLL('Kernel32').GetLastError
enum_func = ctypes.WINFUNCTYPE(wintypes.BOOL,
wintypes.HWND,
wintypes.LPARAM)
def callback(hwnd, lParam):
length = ctypes.WinDLL('User32').GetWindowTextLengthW(hwnd) + 1
buf = ctypes.create_unicode_buffer(length)
ctypes.WinDLL('User32').GetWindowTextW(hwnd, buf, length)
print(buf.value)
worker = enum_func(callback)
test = ctypes.WinDLL('User32').EnumThreadWindows(6000, worker, None)
print(error(test))
I've tried pid = wintypes.DWORD(6000), test = ctypes.WinDLL('User32').EnumThreadWindows(pid.value, worker, None) to no avail.
What am I doing wrong?
Here's working code. Make sure to pass a valid thread ID.
You might be interested in the fact that an LPARAM can be anything, including a python object, so if you pass a Python object it can be manipulated in the callback:
import ctypes
from ctypes import wintypes
from collections import namedtuple
Window = namedtuple('Window','hwnd title')
WNDENUMPROC = ctypes.WINFUNCTYPE(wintypes.BOOL,
wintypes.HWND,
ctypes.py_object) # to allow any Python object.
u32 = ctypes.WinDLL('user32',use_last_error=True) # to ensure GetLastError was captured
# Declaring arguments and return type helps catch errors and support 64-bit.
# HWND is 64-bit on 64-bit Python, and could get truncated if left to ctypes default
# of c_int (32-bit). This code works on Python 2.7 and 3.9.
u32.GetWindowTextLengthW.argtypes = wintypes.HWND,
u32.GetWindowTextLengthW.restype = ctypes.c_int
u32.GetWindowTextW.argtypes = wintypes.HWND,wintypes.LPWSTR,ctypes.c_int
u32.GetWindowTextW.restype = ctypes.c_int
u32.EnumThreadWindows.argtypes = wintypes.DWORD,WNDENUMPROC,ctypes.py_object # to pass Python object
u32.EnumThreadWindows.restype = wintypes.BOOL
#WNDENUMPROC # decorator makes this a ctypes-compatible function
def callback(hwnd, lParam):
length = u32.GetWindowTextLengthW(hwnd) + 1
buf = ctypes.create_unicode_buffer(length)
u32.GetWindowTextW(hwnd, buf, length)
lParam.append(Window(hwnd,buf.value)) # append data to the callback parameter
return True # return True to continue enumeration
result = [] # A python object
if u32.EnumThreadWindows(6332, callback, result): # 6332 was a thread in my explore.exe
for wnd in result: # list results when enumeration complete
print(wnd)
else:
print('error:',ctypes.get_last_error()) # print error of EnumThreadWindows.
# Python could use a Win32 function that fails in
# between the ctypes call and calling GetLastError
# directly.
Output:
Window(hwnd=65832, title='')
Window(hwnd=65838, title='')
Window(hwnd=131174, title='')
Window(hwnd=65682, title='')
Window(hwnd=65678, title='')
Window(hwnd=65826, title='Program Manager')
Window(hwnd=196928, title='MSCTFIME UI')
Window(hwnd=65680, title='Default IME')
I'm not sure if the title accurately describes what I'm trying to do. I have a Python3.x script that I wrote that will issue flood warning to my facebook page when the river near my home has reached it's lowest flood stage. Right now the script works, however it only reports data from one measuring station. I would like to be able to process the data from all of the stations in my county (total of 5), so I was thinking that maybe a class method may do the trick but I'm not sure how to implement it. I've been teaching myself Python since January and feel pretty comfortable with the language for the most part, and while I have a good idea of how to build a class object I'm not sure how my flow chart should look. Here is the code now:
#!/usr/bin/env python3
'''
Facebook Flood Warning Alert System - this script will post a notification to
to Facebook whenever the Sabine River # Hawkins reaches flood stage (22.3')
'''
import requests
import facebook
from lxml import html
graph = facebook.GraphAPI(access_token='My_Access_Token')
river_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=obs'
ref_url = 'http://water.weather.gov/ahps2/river.php?wfo=SHV&wfoid=18715&riverid=203413&pt%5B%5D=147710&allpoints=143204%2C147710%2C141425%2C144668%2C141750%2C141658%2C141942%2C143491%2C144810%2C143165%2C145368&data%5B%5D=all'
def checkflood():
r = requests.get(river_url)
tree = html.fromstring(r.content)
stage = ''.join(tree.xpath('//div[#class="stage_stage_flow"]//text()'))
warn = ''.join(tree.xpath('//div[#class="current_warns_statmnts_ads"]/text()'))
stage_l = stage.split()
level = float(stage_l[2])
#check if we're at flood level
if level < 22.5:
pass
elif level == 37:
major_diff = level - 23.0
major_r = ('The Sabine River near Hawkins, Tx has reached [Major Flood Stage]: #', stage_l[2], 'Ft. ', str(round(major_diff, 2)), ' Ft. \n Please click the link for more information.\n\n Current Warnings and Alerts:\n ', warn)
major_p = ''.join(major_r)
graph.put_object(parent_object='me', connection_name='feed', message = major_p, link = ref_url)
<--snip-->
checkflood()
Each station has different 5 different catagories for flood stage: Action, Flood, Moderate, Major, each different depths per station. So for Sabine river in Hawkins it will be Action - 22', Flood - 24', Moderate - 28', Major - 32'. For the other statinos those depths are different. So I know that I'll have to start out with something like:
class River:
def __init__(self, id, stage):
self.id = id #station ID
self.stage = stage #river level'
#staticmethod
def check_flood(stage):
if stage < 22.5:
pass
elif stage.....
but from there I'm not sure what to do. Where should it be added in(to?) the code, should I write a class to handle the Facebook postings as well, is this even something that needs a class method to handle, is there any way to clean this up for efficiency? I'm not looking for anyone to write this up for me, but some tips and pointers would sure be helpful. Thanks everyone!
EDIT Here is what I figured out and is working:
class River:
name = ""
stage = ""
action = ""
flood = ""
mod = ""
major = ""
warn = ""
def checkflood(self):
if float(self.stage) < float(self.action):
pass
elif float(self.stage) >= float(self.major):
<--snip-->
mineola = River()
mineola.name = stations[0]
mineola.stage = stages[0]
mineola.action = "13.5"
mineola.flood = "14.0"
mineola.mod = "18.0"
mineola.major = "21.0"
mineola.alert = warn[0]
hawkins = River()
hawkins.name = stations[1]
hawkins.stage = stages[1]
hawkins.action = "22.5"
hawkins.flood = "23.0"
hawkins.mod = "32.0"
hawkins.major = "37.0"
hawkins.alert = warn[1]
<--snip-->
So from here I'm tring to stick all the individual river blocks into one block. What I have tried so far is this:
class River:
... name = ""
... stage = ""
... def testcheck(self):
... return self.name, self.stage
...
>>> for n in range(num_river):
... stations[n] = River()
... stations[n].name = stations[n]
... stations[n].stage = stages[n]
...
>>> for n in range(num_river):
... stations[n].testcheck()
...
<__main__.River object at 0x7fbea469bc50> 4.13
<__main__.River object at 0x7fbea46b4748> 20.76
<__main__.River object at 0x7fbea46b4320> 22.13
<__main__.River object at 0x7fbea46b4898> 16.08
So this doesn't give me the printed results that I was expecting. How can I return the string instead of the object? Will I be able to define the Class variables in this manner or will I have to list them out individually? Thanks again!
After reading many, many, many articles and tutorials on class objects I was able to come up with a solution for creating the objects using list elements.
class River():
def __init__(self, river, stage, flood, action):
self.river = river
self.stage = stage
self.action = action
self.flood = flood
self.action = action
def alerts(self):
if float(self.stage < self.flood):
#alert = "The %s is below Flood Stage (%sFt) # %s Ft. \n" % (self.river, self.flood, self.stage)
pass
elif float(self.stage > self.flood):
alert = "The %s has reached Flood Stage(%sFt) # %sFt. Warnings: %s \n" % (self.river, self.flood, self.stage, self.action)
return alert
'''this is the function that I was trying to create
to build the class objects automagically'''
def riverlist():
river_list = []
for n in range(len(rivers)):
station = River(river[n], stages[n], floods[n], warns[n])
river_list.append(station)
return river_list
if __name__ == '__main__':
for x in riverlist():
print(x.alerts())
"Update"
*Finally resolved the issue, changed the try except to include TypeError and also use pass instead of continue in the except.
"End of update"
I wrote code to search for distance between two locations using Google Distance Matrix API. The origin location are fixed, however for the destination, I get it from an xlsx file. I was expecting to get Dictionary with Destination as the Key and the distance as value. When I run the code below, after certain loop I'm stumbled with this error code:
TypeError: Expected a lat/lng dict or tuple, but got NoneType
Can you help me understand the cause of the error? Here is the code (pygmap.py):
import googlemaps
import openpyxl
#get origin and destination locations
def cleanWB(file_path):
destination = list()
wb = openpyxl.load_workbook(filename=file_path)
ws = wb.get_sheet_by_name('Sheet1')
for i in range(ws.max_row):
cellValueLocation = ws.cell(row=i+2,column=1).value
destination.append(cellValueLocation)
#remove duplicates from destination list
unique_location = list(set(destination))
return unique_location
def getDistance(origin, destination):
#Google distance matrix API key
gmaps = googlemaps.Client(key = 'INSERT API KEY')
distance = gmaps.distance_matrix(origin, destination)
distance_status = distance['rows'][0]['elements'][0]['status']
if distance_status != 'ZERO_RESULTS':
jDistance = distance['rows'][0]['elements'][0]
distance_location = jDistance['distance']['value']
else:
distance_location = 0
return distance_location
And I run it using this code:
import pygmap
unique_location = pygmap.cleanWB('C:/Users/an_id/Documents/location.xlsx')
origin = 'alam sutera'
result = {}
for i in range(len(unique_location)):
try:
result[unique_location[i]] = pygmap.getDistance(origin, unique_location[i])
except (KeyError, TypeError):
pass
If I print results it will show that I have successfully get 46 results
result
{'Pondok Pinang': 25905, 'Jatinegara Kaum': 40453, 'Serdang': 1623167, 'Jatiasih
': 44737, 'Tanah Sereal': 77874, 'Jatikarya': 48399, 'Duri Kepa': 20716, 'Mampan
g Prapatan': 31880, 'Pondok Pucung': 12592, 'Johar Baru': 46791, 'Karet': 26889,
'Bukit Duri': 34039, 'Sukamaju': 55333, 'Pasir Gunung Selatan': 42140, 'Pinangs
ia': 30471, 'Pinang Ranti': 38099, 'Bantar Gebang': 50778, 'Sukabumi Utara': 204
41, 'Kembangan Utara': 17708, 'Kwitang': 25860, 'Kuningan Barat': 31231, 'Cilodo
ng': 58879, 'Pademangan Barat': 32585, 'Kebon Kelapa': 23452, 'Mekar Jaya': 5381
0, 'Kampung Bali': 1188894, 'Pajang': 30008, 'Sukamaju Baru': 53708, 'Benda Baru
': 19965, 'Sukabumi Selatan': 19095, 'Gandaria Utara': 28429, 'Setia Mulya': 635
34, 'Rawajati': 31724, 'Cireundeu': 28220, 'Cimuning': 55712, 'Lebak Bulus': 273
61, 'Kayuringin Jaya': 47560, 'Kedaung Kali Angke': 19171, 'Pagedangan': 16791,
'Karang Anyar': 171165, 'Petukangan Selatan': 18959, 'Rawabadak Selatan': 42765,
'Bojong Sari Baru': 26978, 'Padurenan': 53216, 'Jati Mekar': 2594703, 'Jatirang
ga': 51119}
Resolved the issue to include TypeError in the Try Except. And also use pass instead of continue
import pygmap
unique_location = pygmap.cleanWB('C:/Users/an_id/Documents/location.xlsx')
origin = 'alam sutera'
result = {}
#get getPlace
for i in range(len(unique_location)):
try:
result[unique_location[i]] = pygmap.getDistance(origin, unique_location[i])
except (KeyError, TypeError):
pass
I skipped some locations using this solution though.
I'm trying to write a python script to switch the primary monitor.
I have 3 Monitors (one is plugged into my i5's graphics chip, and 2 are plugged into a ATI HD7870)
I wrote the following script:
import win32api as w
import win32con as c
i = 0
workingDevices = []
def setPrimary(id):
global workingDevices
return w.ChangeDisplaySettingsEx(
workingDevices[id].DeviceName,
w.EnumDisplaySettings(
workingDevices[id].DeviceName,
c.ENUM_CURRENT_SETTINGS
),
c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_RESET) \
== c.DISP_CHANGE_SUCCESSFUL
while True:
try:
Device = w.EnumDisplayDevices(None, i, 1)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
break
print("Num Devices: ", len(workingDevices))
for dev in workingDevices:
print("Name: ", dev.DeviceName)
Invoking it leads to:
In [192]: %run test.py
Num Devices: 3
Name: \\.\DISPLAY1
Name: \\.\DISPLAY2
Name: \\.\DISPLAY7
In [193]: setPrimary(0)
Out[193]: True
In [194]: setPrimary(1)
Out[194]: True
In [195]: setPrimary(2)
Out[195]: True
So far it looks great, but the problem is: nothing changes. My monitors flicker shortly because of the CDS_RESET but the primary screen does not change, although ChangeDisplaySettingsEx returns DISP_CHANGE_SUCCESSFUL
Does anyone have an Idea why?
(I use Python 3.5.1 and PyWin32 build 220)
PS I use 1 as the third arg for EnumDisplayDevices because the msdn states it should be set to one, although the PyWin help says it should be set to 0.
But the behaviour of the script does not change independent of this value beeing one or zero
Ok, I found the solution.
Apperantly the primary monitor must always be at position (0, 0).
So when I tried to set another monitor to primary its position was set to (0, 0) which caused it to intersect with the old primary one.
It seems the way to go is to update the positions of all Monitors, and write those changes to the registry, and then once this is done apply the changes by calling ChangeDisplaySettingsEx() with default parameters.
This is my new (now working) code:
import win32api as w
import win32con as c
def load_device_list():
"""loads all Monitor which are plugged into the pc
The list is needed to use setPrimary
"""
workingDevices = []
i = 0
while True:
try:
Device = w.EnumDisplayDevices(None, i, 0)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
return workingDevices
def setPrimary(id, workingDevices, MonitorPositions):
"""
param id: index in the workingDevices list.
Designates which display should be the new primary one
param workingDevices: List of Monitors returned by load_device_list()
param MonitorPositions: dictionary of form {id: (x_position, y_position)}
specifies the monitor positions
"""
FlagForPrimary = c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_NORESET
FlagForSec = c.CDS_UPDATEREGISTRY | c.CDS_NORESET
offset_X = - MonitorPositions[id][0]
offset_Y = - MonitorPositions[id][1]
numDevs = len(workingDevices)
#get devmodes, correct positions, and update registry
for i in range(numDevs):
devmode = w.EnumDisplaySettings(workingDevices[i].DeviceName, c.ENUM_CURRENT_SETTINGS)
devmode.Position_x = MonitorPositions[i][0] + offset_X
devmode.Position_y = MonitorPositions[i][1] + offset_Y
if(w.ChangeDisplaySettingsEx(workingDevices[i].DeviceName, devmode,
FlagForSec if i != id else FlagForPrimary) \
!= c.DISP_CHANGE_SUCCESSFUL): return False
#apply Registry updates once all settings are complete
return w.ChangeDisplaySettingsEx() == c.DISP_CHANGE_SUCCESSFUL;
if(__name__ == "__main__"):
devices = load_device_list()
for dev in devices:
print("Name: ", dev.DeviceName)
MonitorPositions = {
0: (0, -1080),
1: (0, 0),
2: (1920, 0)
}
setPrimary(0, devices, MonitorPositions)