Я работал над оконным менеджером и смог получить значок из x окна через его идентификатор. Этот скрипт правильно возвращает объект изображения подушки, который я могу использовать, чтобы получить значок окна. Тем не менее, попытка использовать этот скрипт в моем оконном менеджере не работает должным образом. Я передаю идентификатор окна (я подтвердил, что это правильно) к сценарию, и он не возвращает нет. Вот сценарий, который я использую: < /p>
import ctypes
import os
from PIL import Image
import io
class IconData(ctypes.Structure):
_fields_ = [
("width", ctypes.c_ulong),
("height", ctypes.c_ulong),
("pixels", ctypes.POINTER(ctypes.c_ulong)),
("num_icons", ctypes.c_int),
]
lib_paths = [
os.path.join(os.path.dirname(__file__), "libgeticon.so"), # Linux
os.path.join(os.path.dirname(__file__), "libgeticon.dylib"), # macOS (ewwww)
os.path.join(os.path.dirname(__file__), "geticon.dll"), # Windows (EWWWWW)
]
lib = None
for path in lib_paths:
if os.path.exists(path):
try:
lib = ctypes.CDLL(path)
break
except OSError as e:
print(f"Warning: Could not load {path}: {e}")
lib = None
if lib is None:
raise RuntimeError("Could not find or load libgeticon shared library. "
"Please ensure it's compiled and in the same directory as xicon.py "
"or in a system-wide library path.")
lib.get_window_icon.argtypes = [ctypes.c_void_p, ctypes.c_ulong]
lib.get_window_icon.restype = ctypes.POINTER(IconData)
lib.free_icon_data.argtypes = [ctypes.POINTER(IconData)]
lib.free_icon_data.restype = None
def get_window_icon(window_id: int) -> Image.Image | None:
"""
Retrieves the icon for a given X Window ID.
Args:
window_id: The ID of the X Window (integer).
Returns:
A PIL.Image.Image object if an icon is found, otherwise None.
The image will be in RGBA format.
"""
dpy = ctypes.cdll.LoadLibrary('libX11.so.6').XOpenDisplay(None) # Linux
if not dpy:
print("Error: Could not open X display.")
return None
icon_data_ptr = lib.get_window_icon(dpy, ctypes.c_ulong(window_id))
if icon_data_ptr and icon_data_ptr.contents.pixels:
icon_data = icon_data_ptr.contents
width = icon_data.width
height = icon_data.height
pixels_ptr = icon_data.pixels
raw_pixels = [pixels_ptr for i in range(width * height)]
rgba_pixels = []
for pixel_val in raw_pixels:
a = (pixel_val >> 24) & 0xFF
r = (pixel_val >> 16) & 0xFF
g = (pixel_val >> 8) & 0xFF
b = pixel_val & 0xFF
rgba_pixels.extend([r, g, b, a])
img = Image.frombytes("RGBA", (width, height), bytes(rgba_pixels))
lib.free_icon_data(icon_data_ptr)
ctypes.cdll.LoadLibrary('libX11.so.6').XCloseDisplay(dpy)
return img
else:
ctypes.cdll.LoadLibrary('libX11.so.6').XCloseDisplay(dpy)
print(f"No icon found for window ID: {window_id}")
return None
if __name__ == '__main__':
try:
test_window_id = input("Enter a window ID: ")
icon_image = get_window_icon(test_window_id)
if icon_image:
print(f"Icon is {icon_image.width}x{icon_image.height} pixels")
icon_image.save("window_icon.png")
else:
print("Failed to retrieve icon")
except Exception as e:
print(e)
< /code>
и библиотека Geticon: < /p>
// geticon.c
#include "geticon.h"
#include
#include
#include
#include // serial, ev->error_code, ev->request_code, ev->minor_code);
return 0;
}
IconData* get_window_icon(Display *dpy, Window win) {
Atom actual_type;
int actual_format;
unsigned long nitems;
unsigned long bytes_after;
unsigned char *prop = NULL;
IconData *icon_data = NULL;
// Set error handler to avoid Xlib exiting on BadWindow
old_error_handler = XSetErrorHandler(ignore_x_errors);
Atom net_wm_icon_atom = XInternAtom(dpy, "_NET_WM_ICON", False);
if (net_wm_icon_atom == None) {
fprintf(stderr, "Error: _NET_WM_ICON atom not found.\n");
goto cleanup;
}
// Get the _NET_WM_ICON property
// The property data is typically an array of CARDINAL, where each CARDINAL
// represents a width, then a height, followed by width*height CARDINALs for the pixels.
// This can repeat for multiple icon sizes.
int status = XGetWindowProperty(dpy, win, net_wm_icon_atom,
0, // offset
~0L, // length (get all data)
False, // delete
XA_CARDINAL, // desired type
&actual_type,
&actual_format,
&nitems,
&bytes_after,
&prop);
// Restore old error handler
XSetErrorHandler(old_error_handler);
if (status != Success || prop == NULL || actual_type != XA_CARDINAL || actual_format != 32) {
if (status == BadWindow) {
fprintf(stderr, "Error: Window ID 0x%lx does not exist.\n", win);
} else if (status != Success) {
fprintf(stderr, "Error: XGetWindowProperty failed with status %d.\n", status);
} else if (prop == NULL) {
fprintf(stderr, "Error: No _NET_WM_ICON property found or property is empty.\n");
} else if (actual_type != XA_CARDINAL) {
fprintf(stderr, "Error: _NET_WM_ICON property has wrong type (expected XA_CARDINAL, got %lu).\n", actual_type);
} else if (actual_format != 32) {
fprintf(stderr, "Error: _NET_WM_ICON property has wrong format (expected 32-bit, got %d-bit).\n", actual_format);
}
goto cleanup;
}
if (nitems == 0) {
fprintf(stderr, "Warning: _NET_WM_ICON property is empty.\n");
goto cleanup; // No icon data
}
icon_data = (IconData*) malloc(sizeof(IconData));
if (!icon_data) {
perror("Failed to allocate IconData");
goto cleanup;
}
icon_data->width = 0;
icon_data->height = 0;
icon_data->pixels = NULL;
icon_data->num_icons = 0;
unsigned long *data_ptr = (unsigned long *)prop;
unsigned long remaining_items = nitems;
// The _NET_WM_ICON property can contain multiple icon images.
// Each image starts with width, then height, then width*height pixels.
// We will extract the first valid icon found.
while (remaining_items >= 2) { // Need at least width and height
unsigned long current_width = *data_ptr++;
unsigned long current_height = *data_ptr++;
remaining_items -= 2;
if (current_width == 0 || current_height == 0) {
fprintf(stderr, "Warning: Encountered icon with zero dimension (%lu x %lu).\n", current_width, current_height);
// Skip to the next potential icon if dimensions are invalid
data_ptr += (current_width * current_height); // Attempt to skip based on reported size
remaining_items -= (current_width * current_height);
continue;
}
unsigned long pixel_count = current_width * current_height;
if (remaining_items < pixel_count) {
fprintf(stderr, "Error: Incomplete icon data. Expected %lu pixels, but only %lu remaining.\n",
pixel_count, remaining_items);
// This indicates a malformed property, try to clean up.
if (icon_data->pixels) free(icon_data->pixels);
free(icon_data);
icon_data = NULL;
XFree(prop); // Free the X property data
return NULL;
}
// We'll take the first valid icon we find. If the user wants to choose,
// we'd return a list of IconData, but the prompt asked for "the icon".
// It's common to take the largest or a specific size. For simplicity, we'll take the first.
icon_data->width = current_width;
icon_data->height = current_height;
icon_data->pixels = (unsigned long *) malloc(pixel_count * sizeof(unsigned long));
if (!icon_data->pixels) {
perror("Failed to allocate pixels");
if (icon_data) free(icon_data);
icon_data = NULL;
goto cleanup;
}
memcpy(icon_data->pixels, data_ptr, pixel_count * sizeof(unsigned long));
icon_data->num_icons = 1; // We extracted one icon
// Successfully extracted one icon, we can stop here.
break;
}
cleanup:
if (prop) {
XFree(prop); // Always free data returned by XGetWindowProperty
}
return icon_data;
}
void free_icon_data(IconData *data) {
if (data) {
if (data->pixels) {
free(data->pixels);
}
free(data);
}
}
< /code>
Этот код работает нормально, но в моем оконном менеджере это не так (я показываю только это, потому что эта вещь похожа на более 1000 строк): < /p>
def _draw_text_on_window(self, target_window, text, x, y, max_width=None, text_color=None, target_window_for_icon=None):
"""
Draws text on a given Xlib window.
Clears the area before drawing.
If text_color is provided, sets the GC's foreground to that color.
"""
if not target_window or not text:
return
target_window.clear_area(0, 0, 0, 0, False) # Clear full window for simplicity
if text_color is not None:
self.gc.change(foreground=text_color)
else:
# If no text_color is specified, use a default black (monochrome text is required)
self.gc.change(foreground=self.screen.black_pixel)
text_bytes = text.encode('utf-8')
# Simple truncation if text is too long (can be improved with font metrics)
# Assuming ~6 pixels per character for a rough estimate
if max_width:
max_chars = int(max_width / 6) # Rough character width
if len(text_bytes) > max_chars:
text_bytes = text_bytes[:max_chars - 3] + b".."
target_window.draw_text(self.gc, x + 18, y, text_bytes)
import utils.xicon as xr
print(target_window_for_icon.id)
print(target_window_for_icon.get_wm_name())
icon_image = xr.get_window_icon(int(target_window_for_icon.id))
if icon_image:
icon_image = icon_image.resize((16, 16), resample=Image.Resampling.NEAREST)
gcx = target_window.create_gc(foreground = 0xFFFFFF, background = 0x000000)
try:
target_window.put_pil_image(gcx, BUTTON_PADDING, BUTTON_PADDING, icon_image)
except Exception as e:
print(f"Error putting PIL image on window: {e}", file=sys.stderr)
else:
print("No icon image available to draw.", file=sys.stderr)
self.disp.flush()
Подробнее здесь: https://stackoverflow.com/questions/796 ... ut-it-retu
Я передаю идентификатор окна в сценарий, который возвращает значок окна, но он не возвращает ни одного при импорте и исп ⇐ Python
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Проблема Джанго, когда я передаю идентификатор продукта по методу получить
Anonymous » » в форуме Python - 0 Ответы
- 9 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Проблема Джанго, когда я передаю идентификатор продукта по методу получить
Anonymous » » в форуме Python - 0 Ответы
- 4 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Проблема Джанго, когда я передаю идентификатор продукта по методу получить
Anonymous » » в форуме Python - 0 Ответы
- 2 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Проблема Джанго, когда я передаю идентификатор продукта по методу получить
Anonymous » » в форуме Python - 0 Ответы
- 6 Просмотры
-
Последнее сообщение Anonymous
-