I am trying to change a mouse cursor for the entire system (for each window on a display) with the help of XCursor and XInput2.
In the code below, the cursor changes. However, only for browser window =>
When I focus on other windows, the cursor is still default.
As I understand, XTranslateCoordinates() function has to return the window which is under the cursor and then I just DefineCursor for this window. It also does not work if I replace XTranslateCoordinates by XGetInputFocus(d, &w, &revert_to).
Probably I do not understand the way cursors are going to be changed on windows. Would be extremely glad for helping!
int main(int argc, char **argv)
{
Display *display;
Window root_window;
display = XOpenDisplay(0);
root_window = XRootWindow(display, 0);
Cursor cursorDefault;
Cursor CursorClickR;
Cursor CursorClickL;
CreateCursor("1.png", cursorDefault, display);
unsigned char mask_bytes[(XI_LASTEVENT + 7) / 8] = {0}; /* must be zeroed! */
XISetMask(mask_bytes, XI_RawMotion);
XIEventMask evmasks[1];
evmasks[0].deviceid = XIAllMasterDevices;
evmasks[0].mask_len = sizeof(mask_bytes);
evmasks[0].mask = mask_bytes;
XISelectEvents(display, root_window, evmasks, 1);
XEvent xevent;
while (1)
{
XNextEvent(display, &xevent);
XGetEventData(display, &xevent.xcookie);
Window root_return, child_return;
int root_x_return, root_y_return;
int win_x_return, win_y_return;
unsigned int mask_return;
XQueryPointer(display, root_window, &root_return, &child_return,
&root_x_return, &root_y_return,
&win_x_return, &win_y_return,
&mask_return);
int local_x, local_y;
XTranslateCoordinates(display, root_window, child_return,
root_x_return, root_y_return,
&local_x, &local_y, &child_return);
if (child_return)
XDefineCursor(display, child_return, cursorDefault);
}
XCloseDisplay(display);
return 0;
}
Related
I am using arch linux and a basic cpp xlib custom window manager. However, every time I right click to open the context menu it just flickers and disappears. I cannot use it at all. I also cannot use top drop down menus (file, edit, about, ect.) on any application. Is there anything in Xlib which I have to look out for to ensure I may use the context menus normally?
This is the case in every application I have tried. Only clue I have is in brave it occasionally displays the following message:
XGetWindowAttributes failed for window [WINDOW_ID]
The following simplified example also has this issue:
int main()
{
display = XOpenDisplay(nullptr);
root = DefaultRootWindow(display);
XSelectInput(display, root, SubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask);
XGrabServer(display);
Window returned_root;
Window returned_parent;
Window* top_level_windows;
unsigned int num_top_level_windows;
XQueryTree(display, root, &returned_root, &returned_parent, &top_level_windows, &num_top_level_windows);
for(unsigned int i = 0; i < num_top_level_windows; ++i)
{
Frame(top_level_windows[i], true);
}
XFree(top_level_windows);
XUngrabServer(display);
for(;;)
{
XEvent event;
XNextEvent(display, &event);
switch (event.type)
{
case MapRequest:
{
Frame(event.xmaprequest.window, false);
XMapWindow(display, event.xmaprequest.window);
break;
}
case ButtonPress:
XRaiseWindow(display, event.xbutton.window);
break;
}
}
return true;
}
void Frame(Window window, bool created_before_manager)
{
//Retrieve attributes of window to frame
XWindowAttributes attr = {0};
XGetWindowAttributes(display, window, &attr);
//If window was created before window manager started, we should frame it only if it is visible and does not set override_redirect
if(created_before_manager && (attr.override_redirect || attr.map_state != IsViewable))
{
return;
}
//Create frame
Window frame = XCreateSimpleWindow(display, root, attr.x, attr.y, attr.width, attr.height, 5, 0xff0000, 0xffffff);
XReparentWindow(display, window, frame, 0, 0);
XMapWindow(display, frame);
XGrabButton(display, Button1Mask, Mod1Mask, window, None, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
}
To be clear it also works with a super simple example such as:
int main()
{
Display* display = XOpenDisplay(nullptr);
for(;;) {}
return true;
}
The reason I believe the window manager is at fault is because this issue only occurs after I run the window manager.
I expected this to work out of the box. I have not found any information on context menus needing special treatment. They do have the override_redirect flag set to true, so I do not frame them. I cannot find information on any other special treatment required.
It is necessary to make sure the client window has input. I had the input set to whatever was clicked (frame, title bar, or client) because it worked fine as far as normal input is concerned. However, the context menus will only work if you make sure the input is set to the client window directly.
I'm building a project like uLauncher where I can pop out a window and focus on the textbox right away. I was able to get the window out using libkeybinder for the shortcut and get the window out with win->show(), but the problem is that the keyboard cursor is in the window behind the window.
How do I get the focus to be on the textbox window?
This is the main code:
void shortcutHandler(const char *keystring, void *user_data) {
winroot->show();
}
int main(int argc, char *argv[]) {
Gtk::Main kit(argc, argv);
winroot = new MainWindow();
auto app = Gtk::Application::create(GTK_ID);
app->hold();
keybinder_init();
keybinder_bind(KEY_SHORTCUT, shortcutHandler, NULL);
return app->run(*winroot);
}
``
I want to test a flash application running on browser. I need to drag pieces around in the application. I want to do this by simulating mouse movements using windows api.
Here is my navie solution to simulate a mouse drag:
void MoveMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
}
void LeftDownMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
}
void LeftUpMouse(LPINPUT input, int x, int y) {
input->type = INPUT_MOUSE;
input->mi.dx = x*(65536/GetSystemMetrics(SM_CXSCREEN));
input->mi.dy = y*(65536/GetSystemMetrics(SM_CYSCREEN));
input->mi.dwFlags = MOUSEEVENTF_LEFTUP;
}
void DragMouse(LPINPUT inputs, int startX, int startY, int dropX, int dropY) {
MoveMouse(&inputs[0], startX, startY);
LeftDownMouse(&inputs[1], startX, startY);
LeftUpMouse(&inputs[2], startX, startY);
LeftDownMouse(&inputs[3], startX, startY);
MoveMouse(&inputs[4], dropX, dropY);
LeftUpMouse(&inputs[5], dropX, dropY);
}
int _tmain(int argc, _TCHAR* argv[])
{
INPUT inputs [6] = {};
// Assume there is a maximized window, mouse drags the window from 40, 10 to 100,100 coordinates.
DragMouse(inputs, 40, 10, 100, 100);
SendInput(6, inputs, sizeof(INPUT));
Sleep(1000);
return 0;
}
This code mostly doesn't work, sometimes works, it has undefined behaviour. What could be the problem? How can i solve this?
I had a similar problem with drag and drop, although my results were consistent in that the mouse was moving but not the item being dragged.
Your MoveMouse function is missing the MOUSEEVENTF_LEFTDOWN flag. Try input->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN;
Without the flag setting you are just asking the mouse to move without the left mouse button being down.
Edit
I just checked my implementation and I don't set coordinates when pressing or releasing the mouse buttons. Only when moving.
As for variance in results, you may stop these by zeroing out the INPUT before setting fields.
I'd like to have width and height of the currently focussed window. The selection of the window works like a charm whereas the height and width are always returning 1.
#include <X11/Xlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
Display *display;
Window focus;
XWindowAttributes attr;
int revert;
display = XOpenDisplay(NULL);
XGetInputFocus(display, &focus, &revert);
XGetWindowAttributes(display, focus, &attr);
printf("[0x%x] %d x %d\n", (unsigned)focus, attr.width, attr.height);
return 0;
}
Is this not the "real" window but the currently active component (like a textbox or a button?) And why would it have the size of 1x1 anyways then? If this is the case, how do i get the main window of the application containig this control? Means... kinda the top-level window, the top-most window except the root window.
PS: Don't know whether it's really important; I use Ubuntu 10.04 32 and 64 bit.
You're right - you're seeing a child window. GTK applications, in particular, create a child window under the "real" window, which is always 1x1, and that always gets the focus when the application has the focus. If you're just running your program using the GNOME terminal, you'll always be seeing a GTK application with the focus (the terminal).
If you run your program in such a way that a non-GTK program happens to have the focus, then this doesn't happen, but you could still end up finding a child window with the focus instead of the top-level window. (One way of doing this is to run sleep before your program like this: sleep 4; ./my_program - this gives you a chance to change the focus.)
To find the top-level window, I think XQueryTree will help - it returns the parent window.
This worked for me:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
/*
Returns the parent window of "window" (i.e. the ancestor of window
that is a direct child of the root, or window itself if it is a direct child).
If window is the root window, returns window.
*/
Window get_toplevel_parent(Display * display, Window window)
{
Window parent;
Window root;
Window * children;
unsigned int num_children;
while (1) {
if (0 == XQueryTree(display, window, &root,
&parent, &children, &num_children)) {
fprintf(stderr, "XQueryTree error\n");
abort(); //change to whatever error handling you prefer
}
if (children) { //must test for null
XFree(children);
}
if (window == root || parent == root) {
return window;
}
else {
window = parent;
}
}
}
int main(int argc, char *argv[])
{
Display *display;
Window focus, toplevel_parent_of_focus;
XWindowAttributes attr;
int revert;
display = XOpenDisplay(NULL);
XGetInputFocus(display, &focus, &revert);
toplevel_parent_of_focus = get_toplevel_parent(display, focus);
XGetWindowAttributes(display, toplevel_parent_of_focus, &attr);
printf("[0x%x] %d x %d\n", (unsigned)toplevel_parent_of_focus,
attr.width, attr.height);
return 0;
}
So I'm in a situation where I need to know when a top level window gets created. I'm working at the Xlib/Xt level and on a Window Manager that doesn't support the EWMH specification. My idea is to hook into the root window's SubstructureNotify events. But things are not as simple as just that.
The problem is that not every CreateNotify event corresponds to the creation of a [b]top level[/b] window. So what I think I need to do is test the window I get from the event somehow to confirm that it is a top level window. I've got close, but some spurious windows still make it through my net. For example, in a GTK application if you have a dropdown box and you click it, a new window is created that I can't figure out how to catch and ignore. Such a window is troublesomely indistinguishable from a typical top level application window.
Here's what I have so far:
// I am omiting (tons of) cleanup code and where I set the display and toplevel variables.
Display* display;
Widget toplevel;
bool has_name(Window window)
{
XTextProperty data = XTextProperty ();
return (!XGetWMName (display, window, &data));
}
bool has_client_leader(Window window)
{
unsigned long nitems = 0;
unsigned char* data = 0;
Atom actual_type;
int actual_format;
unsigned long bytes;
// WM_CLIENT_LEADER is an interned Atom for the WM_CLIENT_LEADER property
int status = XGetWindowProperty (display, window, WM_CLIENT_LEADER, 0L, (~0L), False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &data);
if (status != Success || acutal_type == None) return false;
Window* leader = reinterpret_cast<Window*> (data);
return (*leader != 0);
}
bool has_class(Window window)
{
XClassHint data = XClassHint ();
return (!GetClassHint (display, window, &data));
}
void handle_event(Widget widget, XtPointer, XEvent* event, Boolean*)
{
if (event->type != CreateNotify) return;
Window w = event->xcreatewindow.window;
// confirm window has a name
if (!has_name (w)) return;
// confirm window is a client window
Window client = XmuClientWindow (display, w);
if (!client || client != w) return;
// confirm window has a client leader that is not 0x0
if (!has_client_leader (client)) return;
// confirm window has a class
if (!has_class (client)) return;
// The window has passed all our checks!
// Go on to do stuff with the window ...
}
int main(int argc, char* argv[])
{
// ...
// Setting up the event handler for SubstructureNotify on root window
Window root_window = XDefaultRootWindow (display);
Widget dummy = XtCreateWidget ("dummy", coreWidgetClass, toplevel, 0, 0);
XtRegisterDrawable (display, root_window, dummy);
XSelectInput (display, root_window, SubstructureNotifyMask);
XtAddRawEventHandler (dummy, SubstructureNotifyMask, False, handle_event, 0);
// ...
}
A long shot, but does anyone have any ideas I could try? I can't think of much else I can really do here.
I assume you're familiar with the ICCCM and its long-winded discussion.
Have you checked the WM_TRANSIENT_FOR property?