好吧,你的意思是让我获取主窗口的像素值,和旋转后的子窗口里的像素值混合。这是很复杂的。。。
多谢了
【已解决】有懂x11的吗,如何创建一个背景透明的子窗口?
- wxf
- 帖子: 53
- 注册时间: 2008-05-28 8:50
- wxf
- 帖子: 53
- 注册时间: 2008-05-28 8:50
Re: 有懂x11的吗,如何创建一个背景透明的子窗口?
我后来用cairo库解决了这个问题,可以简单地倾斜输出了。不过字迹看上去有点模糊,换字体也一样,还是模糊
上次由 wxf 在 2023-09-06 10:53,总共编辑 1 次。
-
- 帖子: 1
- 注册时间: 2023-09-05 10:53
Re: 【已解决】有懂x11的吗,如何创建一个背景透明的子窗口?
大哥,你的这段代码如何实现的hook,学习一下wxf 写了: ↑2022-11-12 11:30 需求是这样的,我做了一个hook so,通过 LD_PRELOAD=/opt/dss/dsshook.so /opt/kingsoft/wps-office/office6/wps 的方式,让so进入wps进程空间,我在XMapWindow 的hook函数内判断要映射的窗口是不是wps主窗口,是的话就创建一个子窗口,并且让这个子窗口背景透明,但我还要在上面输出一些文字作为假水印。此外,我还要使鼠标键盘事件穿透下去
现在子窗口可以加,鼠标键盘事件可以穿透到主窗口,但是没办法让其背景透明。
用子窗口的目的,是使其跟着主窗口移动,省去自己管理的麻烦。
用top-level窗口也行,但是toplevel的会切换z序,用瞬态窗口(设置transient-for属性的窗口)可以达到不切换z序的目的,但是有标题栏,而不我不需要标题栏,而且透明后,输出的文字也跟着透明了。
我的代码如下,请指点:效果是这样的代码: 全选
int XMapWindow(Display* display, Window w) { static void* handle = NULL; static Func_XMapWindow old_XMapWindow = NULL; if (!handle) { handle = dlopen("libX11.so", RTLD_LAZY); old_XMapWindow = (Func_XMapWindow)dlsym(handle, "XMapWindow"); } //获得窗口标题 char title[300] = { '\0' }; get_window_title4(display, w, title); if (strstr(title, "WPS文字")) //“WPS文字”是无文档时的标题 随后打开文档了会变成“11.doc - WPS 文字 - 兼容模式” 这样的形式。 再此切回无文档tab页时,标题会变成“WPS 文字 - WPS文字” { int ret = old_XMapWindow(display, w); //如果不存在水印窗口, 创建,让鼠标键盘事件穿透,背景透明,让主窗口变化大小时也跟着变化 if (g_water_print_window_exist == False) { XVisualInfo vinfo; XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo); XSetWindowAttributes attr; attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone); attr.border_pixel = 0; attr.background_pixel = 0x00ffffff;// 0x80808080; attr.event_mask = StructureNotifyMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | ExposureMask; //attr.override_redirect = True; g_water_print_window = XCreateWindow(display, w , 0, 0, 400, 400, 0, vinfo.depth, InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel | CWEventMask , &attr); //g_water_print_window = XCreateSimpleWindow(display, w, 0, 0, 400, 400, 1, BlackPixel(display, DefaultScreen(display)),0x00ffffff ); printf("%s,%d,g_water_print_window:%lx\n", __FILE__, __LINE__, g_water_print_window); //使事件穿透下去 XShapeCombineRectangles(display, g_water_print_window, ShapeInput, 0, 0, NULL, 0, ShapeSet, YXBanded); //使子窗口背景透明 Pixmap mask = XCreatePixmap(display, g_water_print_window, 400, 400, 1); XShapeCombineMask(display, g_water_print_window, ShapeBounding, 0, 0, mask, ShapeSet);// ShapeClip ShapeBounding old_XMapWindow(display, g_water_print_window); GC gc = XCreateGC(display, g_water_print_window, 0, 0); XDrawString(display, g_water_print_window, gc, 190, 190, "test", 4); XFlushGC(display, gc); ////设置半透明,对子窗口无效。大约是因为子窗口不归窗口管理器管理? //double alpha = 0.1; //unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha); //Atom XA_NET_WM_WINDOW_OPACITY = XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False); //XChangeProperty(display, g_water_print_window, XA_NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&opacity, 1L); g_water_print_window_exist = True; } return ret; } return old_XMapWindow(display, w); }
请高手指点
另外,我还要做阻止截图的功能,为什么我把几种最常用的截图相关函数hook了,还是拦截不住截图程序,比如xGetImage 、xcb_get_image_reply 等。是不是这些截图程序静态链接x11库了,还是用了别的方法截图了?
- wxf
- 帖子: 53
- 注册时间: 2008-05-28 8:50
Re: 【已解决】有懂x11的吗,如何创建一个背景透明的子窗口?
对于Qt程序,拦截xcb_copy_area 函数就行:
代码: 全选
// Qt's screenshot function is filterd by this code
typedef xcb_void_cookie_t(*Func_xcb_copy_area)(
xcb_connection_t* c,
xcb_drawable_t src_drawable,
xcb_drawable_t dst_drawable,
xcb_gcontext_t gc,
int16_t src_x,
int16_t src_y,
int16_t dst_x,
int16_t dst_y,
uint16_t width,
uint16_t height
);
static Func_xcb_copy_area old_xcb_copy_area = NULL;
static xcb_pixmap_t g_pixmap_t3 = 0;
xcb_void_cookie_t xcb_copy_area(
xcb_connection_t* c,
xcb_drawable_t src_drawable,
xcb_drawable_t dst_drawable,
xcb_gcontext_t gc,
int16_t src_x,
int16_t src_y,
int16_t dst_x,
int16_t dst_y,
uint16_t width,
uint16_t height)
{
if (!old_xcb_copy_area)
{
old_xcb_copy_area = (Func_xcb_copy_area)dlsym(RTLD_NEXT, "xcb_copy_area");
if (old_xcb_copy_area == NULL)
printf("%s,%d, old_xcb_copy_area == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_xcb_copy_area found\n", __FILE__, __LINE__);
}
xcb_get_geometry_reply_t* georeply = xcb_get_geometry_reply(c, xcb_get_geometry(c, src_drawable), NULL);
//if not a window
if (!georeply)
{
printf("%s,%d, src_drawable is not a window id\n", __FILE__, __LINE__);
return old_xcb_copy_area(c, src_drawable, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
uint8_t depth = georeply->depth;
free(georeply);
//if src_drawable is root window
Display* display = XOpenDisplay(NULL);
if (src_drawable == DefaultRootWindow(display))
{
printf("%s,%d, src_drawable is root window:%08x\n", __FILE__, __LINE__, (unsigned int)src_drawable);
//if exists crypter process
int count = 0;
if (DssGetCryptProcessCount(&count) && count > 0)
{
printf("%s,%d, screenshot is not allowed, a fake bitmap is gave\n", __FILE__, __LINE__);
if (g_pixmap_t3 != 0)
xcb_free_pixmap(c, g_pixmap_t3);
//return fake data
g_pixmap_t3 = xcb_generate_id(c);
xcb_create_pixmap(c, depth, g_pixmap_t3, src_drawable, width, height);
/* Generate a Graphics Context and fill the pixmap with background color (for images that are smaller than your screen) */
xcb_gcontext_t gc = xcb_generate_id(c);
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
uint32_t value[1];
value[0] = screen->black_pixel;
xcb_create_gc(c, gc, g_pixmap_t3, XCB_GC_FOREGROUND, value);
xcb_rectangle_t rect = { 0, 0, width, height };
xcb_poly_fill_rectangle(c, g_pixmap_t3, gc, 1, &rect);
xcb_free_gc(c, gc);
return old_xcb_copy_area(c, g_pixmap_t3, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
else
return old_xcb_copy_area(c, src_drawable, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
//get destination window's pid
pid_t pid;
if (GetWindowPid(display, src_drawable, &pid))
{
printf("%s,%d, pid:%d\n", __FILE__, __LINE__, pid);
//query permission value
Bool flag = False;
if (pid != getpid() && isCryptProcess(pid))
{
DWORD dwpermission = 0;
if (getpermission(pid, &dwpermission) && !(dwpermission & DSS_PRIVILEGE_SAVEAS))
{
printf("%s,%d, permission:%ld\n", __FILE__, __LINE__, dwpermission);
flag = true;
}
}
//if screenshot is not allowed
if (flag)
{
printf("%s,%d, 禁止截图\n", __FILE__, __LINE__);
//通知托盘
if (g_pixmap_t3 != 0)
xcb_free_pixmap(c, g_pixmap_t3);
//return fake data
g_pixmap_t3 = xcb_generate_id(c);
xcb_create_pixmap(c, depth, g_pixmap_t3, src_drawable, width, height);
/* Generate a Graphics Context and fill the pixmap with background color (for images that are smaller than your screen) */
xcb_gcontext_t gc = xcb_generate_id(c);
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
uint32_t value[1];
value[0] = screen->black_pixel;
xcb_create_gc(c, gc, g_pixmap_t3, XCB_GC_FOREGROUND, value);
xcb_rectangle_t rect = { 0, 0, width, height };
xcb_poly_fill_rectangle(c, g_pixmap_t3, gc, 1, &rect);
xcb_free_gc(c, gc);
return old_xcb_copy_area(c, g_pixmap_t3, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
else
{
return old_xcb_copy_area(c, src_drawable, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
}
else
{
printf("%s,%d, old_xcb_copy_area was called\n", __FILE__, __LINE__);
return old_xcb_copy_area(c, src_drawable, dst_drawable, gc, src_x, src_y, dst_x, dst_y, width, height);
}
}
代码: 全选
//gtk 's screenshot function is filterd by this code
typedef GdkDisplay* (*Func_gdk_display_get_default)();
static Func_gdk_display_get_default old_gdk_display_get_default = NULL;
typedef GdkScreen* (*Func_gdk_display_get_default_screen)(GdkDisplay* display);
static Func_gdk_display_get_default_screen old_gdk_display_get_default_screen = NULL;
typedef GdkWindow* (*Func_gdk_screen_get_root_window)(GdkScreen* screen);
static Func_gdk_screen_get_root_window old_gdk_screen_get_root_window = NULL;
typedef GdkPixbuf* (*Func_gdk_pixbuf_get_from_surface)(cairo_surface_t* surface,gint src_x,gint src_y,gint width,gint height);
static Func_gdk_pixbuf_get_from_surface old_gdk_pixbuf_get_from_surface = NULL;
typedef GdkPixbuf* (*Func_gdk_pixbuf_get_from_window)(GdkWindow* window,gint src_x,gint src_y,gint width,gint height);
static Func_gdk_pixbuf_get_from_window old_gdk_pixbuf_get_from_window = NULL;
//static GdkWindow* g_win = NULL;
GdkPixbuf* gdk_pixbuf_get_from_window(GdkWindow* window, gint src_x, gint src_y, gint width, gint height)
{
if (!old_gdk_pixbuf_get_from_window)
{
old_gdk_pixbuf_get_from_window = (Func_gdk_pixbuf_get_from_window)dlsym(RTLD_NEXT, "gdk_pixbuf_get_from_window");
if (old_gdk_pixbuf_get_from_window == NULL)
printf("%s,%d, old_gdk_pixbuf_get_from_window == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_gdk_pixbuf_get_from_window found\n", __FILE__, __LINE__);
}
if (!old_gdk_display_get_default)
{
old_gdk_display_get_default = (Func_gdk_display_get_default)dlsym(RTLD_NEXT, "gdk_display_get_default");
if (old_gdk_display_get_default == NULL)
printf("%s,%d, old_gdk_display_get_default == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_gdk_display_get_default found\n", __FILE__, __LINE__);
}
if (!old_gdk_display_get_default_screen)
{
old_gdk_display_get_default_screen = (Func_gdk_display_get_default_screen)dlsym(RTLD_NEXT, "gdk_display_get_default_screen");
if (old_gdk_display_get_default_screen == NULL)
printf("%s,%d, old_gdk_display_get_default_screen == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_gdk_display_get_default_screen found\n", __FILE__, __LINE__);
}
if (!old_gdk_screen_get_root_window)
{
old_gdk_screen_get_root_window = (Func_gdk_screen_get_root_window)dlsym(RTLD_NEXT, "gdk_screen_get_root_window");
if (old_gdk_screen_get_root_window == NULL)
printf("%s,%d, old_gdk_screen_get_root_window == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_gdk_screen_get_root_window found\n", __FILE__, __LINE__);
}
if (!old_gdk_pixbuf_get_from_surface)
{
old_gdk_pixbuf_get_from_surface = (Func_gdk_pixbuf_get_from_surface)dlsym(RTLD_NEXT, "gdk_pixbuf_get_from_surface");
if (old_gdk_pixbuf_get_from_surface == NULL)
printf("%s,%d, old_gdk_pixbuf_get_from_surface == NULL\n", __FILE__, __LINE__);
else
printf("%s,%d, old_gdk_pixbuf_get_from_surface found\n", __FILE__, __LINE__);
}
GdkDisplay* display = old_gdk_display_get_default();
GdkScreen* screen = old_gdk_display_get_default_screen(display);
GdkWindow* root = old_gdk_screen_get_root_window(screen);
//printf("%s,%d, %08x, %08x\n", __FILE__, __LINE__, root, window);
if (window == root)
{
printf("%s,%d, gdk_pixbuf_get_from_window, root window\n", __FILE__, __LINE__);
//printf("%s,%d, gdk_pixbuf_get_from_window, x:%d,y:%d,w:%d,h:%d\n", __FILE__, __LINE__, src_x, src_y, width, height);
int count = 0;
if (DssGetCryptProcessCount(&count) && count > 0)
{
printf("%s,%d, screenshot is not allowed, a fake bitmap is gave\n", __FILE__, __LINE__);
//give a fake pixbuf
cairo_surface_t* fake_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
return old_gdk_pixbuf_get_from_surface(fake_surface, 0, 0, width, height);
}
else
{
return old_gdk_pixbuf_get_from_window(window, src_x, src_y, width, height);
}
}
return old_gdk_pixbuf_get_from_window(window, src_x, src_y, width, height);
}
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/XShm.h>
//#include <X11/Xft/Xft.h>
#include <xcb/xproto.h>
#include <xcb/shm.h>
#include <xcb/composite.h>
#include <list>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
#include <gdk/gdkx.h>
#include <gtk/gtkunixprint.h>
编译选项主要是这些
-lX11 -lXtst `pkg-config --libs gtk+-3.0`
别的函数,比如x_get_image之类的都差不多这个样子实现的。
可能有错误,请指出来