X11/XCB/Xlib: Copy root window to pixmap - linux

I can copy the contents of the root window to an xcb_image_t in client (ie. CPU) memory using xcb_image_get() (regardless of its map status, although presumably the root window is always mapped?). Eg:
xcb_image_t* xcb_img = xcb_image_get(xcb_connection, xcb_screen->root, 0, 0, xcb_screen->width_in_pixels, xcb_screen->height_in_pixels, 0x00ffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
Now the pixels of the root window are in xcb_img->data.
But I'm trying to copy the contents of the root window to an xcb_pixmap_t (in server memory), and it's not working (the call doesn't
fail, but it returns garbage, as if the window wasn't mapped):
xcb_void_cookie_t copy_cookie = xcb_copy_area_checked(xcb_connection, xcb_screen->root, xcb_pixmap, xcb_gc_null, 0, 0, 0, 0, xcb_screen->width_in_pixels, xcb_screen->height_in_pixels);
xcb_generic_error_t* copy_error = xcb_request_check(xcb_connection, copy_cookie);
if(copy_error)
exit(1);
However, it works for other windows that happen to be mapped (and it fails for subregions of those windows that are occluded by other windows, in the sense that the copy returns garbage.)
I understand that a window needs to be mapped in order to have meaninful contents. This leads me to think that the root window is never mapped (or something).
All I want is to copy the contents of the display (ie. the pixels that are currently being shown in the physical display/monitor) to an xcb_pixmap_t (or, equivalently, to an Xlib Pixmap). How can I do this? (It works so easily for xcb_get_image()...)

You want your GC to have SubwindowMode set to IncludeInferiors (default is ClipByChildren).
From the X11 protocol description:
For ClipByChildren, both source and destination windows are additionally clipped by all viewable InputOutput children. For IncludeInferiors, neither source nor destination window is clipped by inferiors. This will result in including subwindow contents in the source and drawing through subwindow boundaries of the destination. The use of IncludeInferiors with a source or destination window of one depth with mapped inferiors of differing depth is not illegal, but the semantics is undefined by the core protocol.
https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html
What this means is that with ClipByChildren, you are only copying from the window that you used as the source. If the window has subwindows, the pixels "in there" are not owned by the window you are using as the source. Thus, X11 assumes you do not want those pixels.

Related

Get numbers of all screens in Xlib

I've been googling for quite a long time and I just can't find any information on how to get screen_number for every screen connected to computer. Here I found a list of macros and some of them (like for example ScreenOfDisplay(display, screen_number) ) use argument screen_number. However there is no such macro that could give me a list of those numbers (one for every connected screen). I know how to get number of default screen (DefaultScreen() ) and count of all screens ( ScreenCount() ) but what about other screens? I noticed that screen_number of default screen is 0, although I have only one screen connected to my computer so I can't really test what happens when there are more of them. I think that screen_number could be assigned in a very simple way which is screen_number=0 for first screen,screen_number=1 for second,screen_number=2 for third and so on but as I said... I can't test wheather it's true and even if I had multiple screens how could I be sure that it works like this for all computers .Please ,if anyone of you has more experience with X11 and knows all details about how it works,tell me if I am right.
The ScreenCount(dpy) macro and int XScreenCount(Display*) function both return the number of screens connected to the display. Valid screen numbers are 0 to ScreenCount(dpy)-1. Macros in Xlib.h confirm:
#define ScreenCount(dpy) (((_XPrivDisplay)dpy)->nscreens)
#define ScreenOfDisplay(dpy, scr) (&((_XPrivDisplay)dpy)->screens[scr])
Your source (2.2.1. Display Macros) provides enough information. Normally the default screen-number is 0, e.g., when connecting to the local host you could use :0.0 as indicated in the documentation for XOpenDisplay.
That is "normally". If you run VNC, normally that runs on a different display (the first 0 in the simple connection string shown).
But (reading the documentation), when an application calls XOpenDisplay, it asks for the given screen-number (which the X server may/may not honor):
screen_number
Specifies the screen to be used on that server. Multiple screens can be controlled by a single X server. The screen_number sets an internal variable that can be accessed by using the DefaultScreen() macro or the XDefaultScreen() function if you are using languages other than C (see "Display Macros").

JavaFX proximity detection not working

I have been trying to figure out how to get two nodes to sense when they are close to each other and then snap together but can't make it work correctly. Basically, I have an AnchorPane that I am dropping new Nodes onto. The new nodes are also anchor panes with several other components on them. When I drop the Node I save anchor points along the outer edge. Then, when I drag another Node next to it, the sides will light up indicating the other node is in range.
I am attempting to make a node that is being dragged next to another node snap to that node. I cannot seem to get the coordinates to translate correctly between each other and I am just ending up with random placement and edge detection.
Here is my code where I am saving the anchor points for the nodes:
double kromaDeviceWidth = kromaDevice.getBoundsInParent().getWidth();
double kromaDeviceHeight = kromaDevice.getBoundsInParent().getHeight();
//This x,y represents the top left corner of the node
double kromaDeviceX = kromaDevice.localToParent(0.0, 0.0).getX();
double kromaDeviceY = kromaDevice.localToParent(0.0, 0.0).getY();
kromaDevice.setTopAnchorPoint(new double[]{kromaDeviceX + kromaDeviceWidth / 2, kromaDeviceY});
kromaDevice.setRightAnchorPoint(new double[]{kromaDeviceX + kromaDeviceWidth, kromaDeviceY + kromaDeviceHeight / 2});
kromaDevice.setBottomAnchorPoint(new double[]{kromaDeviceX + kromaDeviceWidth / 2, kromaDeviceY + kromaDeviceHeight});
kromaDevice.setLeftAnchorPoint(new double[]{kromaDeviceX, kromaDeviceY + kromaDeviceHeight / 2});
The code is identical for when I initially drop a new node and when I am dragging the node. Then, I compare the two node's anchor positions to tell if they are within range:
if (Math.abs(bottomAnchorX - topAnchorPointX) <= ANCHOR_DISTANCE && Math.abs(bottomAnchorY - topAnchorY) <= ANCHOR_DISTANCE) {
....show correct edge highlight
}
I simplified the above if statement as I am using arrays to store and recall the anchor points.
Here is an image of what I am seeing:
You can see the slight yellow highlight when I drag one node over the other when it is offset. It should detect the other node when it is in the position in the second image. My next issue is trying to get them to snap to the right coordinates.
droppedKromaDevice.setLayoutX(parentKromaDevice.getLayoutX());
droppedKromaDevice.setLayoutY(parentKromaDevice.getLayoutY() - droppedKromaDevice.getBoundsInParent().getHeight());
I tried the above with both getLayoutX() and localToParent(0,0).getX() and they produce the same result. If I place two nodes that are exactly the same size than it actually works but if the are different sizes at all than it places them offset from each other. If I subtract the height from the y it should matter the size.
Please help. I have been trying to get this to work right for 3 days now and have tried everything I can think of.
Update:
I figured out my proximity issue. The layout for the new node was not being set right. I tried doing a Platform.runLater before I saved the anchor points of the new node but that had no impact. I fixed it by setting the anchor points for all of the nodes in the pane when I click on a node to drag it. That saved the anchor points correctly.
This however did not fix my issue of nodes of different sizes not laying out in the pane correctly. Here is a screenshot of two nodes of the same size snapping together correctly and two nodes of different sizes not snapping correctly. This makes no sense as the math should be the same.
Here is the code to set the layout for the dropped node relative to the other node:
droppedKromaDevice.setLayoutX(parentKromaDevice.getLayoutX());
droppedKromaDevice.setLayoutY(parentKromaDevice.getLayoutY() - droppedKromaDevice.getBoundsInParent().getHeight());
I found the solution to my two problems.
First, when I was creating new nodes and dropping them on the panel the bounds were not being evaluated correctly so my anchor points were off. I just changed it so when I click on a node to drag it around I loop through all of the other nodes on the panel and build their anchors instead of when I first drop/create it.
Second, in order to get the snap positioning to work accurately I had to base their layout on the delta between the opposite anchor points and not on the bounds of the node. Basically, I get the current x/y of the node I am dropping and than move it using the delta between the dropped node and the node I need to snap it to. The code below is what I used. 0 represents the x coordinate and 1 represents the y coordinate in the array
droppedKromaDevice.setLayoutX(droppedKromaDevice.getLayoutX() - droppedKromaDevice.getBottomAnchorPoint()[0] + parentKromaDevice.getTopAnchorPoint()[0]);
droppedKromaDevice.setLayoutY(droppedKromaDevice.getLayoutY() - droppedKromaDevice.getBottomAnchorPoint()[1] + parentKromaDevice.getTopAnchorPoint()[1]);

Linux: Xautomation with fake mouse pointer

I have created a fake mouse pointer using the xinput command as outlined here which produces a second pointer that hovers in the center of my screen.
I would now like to automate it using the xte command, but unfortunately xte only seems grab control of the hardware mouse that I wish to keep free.
The man page for xte does not have any flags to specify which pointer to take control of.
I was wondering if anybody had any ideas?
NB: The second pointer is purely for me to able to work on the same computer whilst running the graphical pipeline
Edit: So by looking at the xte source I've found references to XQueryPointer
Bool XQueryPointer(display, w, root_return, child_return, root_x_return, root_y_return,
win_x_return, win_y_return, mask_return)
Display *display;
Window w;
Window *root_return, *child_return;
int *root_x_return, *root_y_return;
int *win_x_return, *win_y_return;
unsigned int *mask_return;
//Arguments:
display Specifies the connection to the X server.
w Specifies the window.
root_return Returns the root window that the pointer is in.
child_return Returns the child window that the pointer is located in, if any.
root_x_return
root_y_return Return the pointer coordinates relative to the root window's origin.
win_x_return
win_y_return Return the pointer coordinates relative to the specified window.
mask_return Returns the current state of the modifier keys and pointer buttons.
from the Xlib class, which as you can see returns only the first mouse pointer and does not give option for another.
Edit2: Looking through the libx11-dev source I'm finding mentions of it at ./src/QuPntr.c and Xlibint.h, but the code is getting harder to read and I'm out of my depth here
xinput makes use of the XI2 extension to allow for multiple pointers.
This library (X11/extensions/XInput2.h) provides functions prefixed by "XI" which accept a device parameter (the same referenced by xinput --list), for instance XIQueryPointer, XIWarpPointer or XIGetClientPointer.
Thus you can control your fake pointer programmatically if your automation tool doesn’t support XI2.
In a simpler way, it could suffice to xinput --reattach the hardware device (a slave device) to the new pointer (a master device).
Very late answer I know, but I came across this question via web search so I add what I know for reference.
Actually there isn't any mention of XQueryPointer inside the source code of xte.c (there are only a few inside xmousepos.c, which is code for a different tool).
I checked a few older versions that existed before you asked the question.
The relevant functions are XIWarpPointer and XTestFakeDeviceButtonEvent. As seen here in the reduced source code:
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XTest.h>
int main (int argc, char *argv[])
{
int delta_x = 500, delta_y = 160;
Display *display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
XIWarpPointer(display, 14, None, root, 0, 0, 0, 0, delta_x, delta_y);
XDevice *device = NULL;
device = XOpenDevice(display, 16);
XTestFakeDeviceButtonEvent(display, device, 1, True, 0, 0, CurrentTime);
XTestFakeDeviceButtonEvent(display, device, 1, False, 0, 0, CurrentTime);
XCloseDisplay(display);
}
which does the same thing as xte -i 16 "mousemove 500 160" "mouseclick 1".
But what might bother you (at least it bothers me): Windows that got clicked gain focus, effectively unfocusing the window that you were working on.
Actually I asked a question that asks for an alternative to XTestFakeDeviceButtonEvent just recently (Sending a button press event for a second pointing device; I also provided some example code that actually performs mouse clicks without giving focus to a window, so it's possible but dunno how it's done with another pointing device)..
An alternative might be to work with multiple X sessions like this user did it: Controlling multiple pointers with Xlib or xinput in ubuntu/linux. Sadly he hasn't shared any code.
I have some hope with uinput (https://www.kernel.org/doc/html/v4.12/input/uinput.html) but haven't tried it yet.

Height of tab (JTabbedPane) does not change

As the title says, the height of my tabs is not increasing as it should, my code looks like this:
JTabbedPane jtp = new JTabbedPane();
JLabel iconInTab = new JLabel(new ImageIcon("myImage.png"));
iconInTab.setPreferredSize(new Dimension(100,80)); // is the size of my Image, I've also try to do this using getSize
jtp.addTab(null,new JPanel());
jtp.setTabComponentAt(0,iconInTab);
I've also try this using html but it did not work either:
jtp.addTab("<html><p><p><p></html>",new ImageIcon("myImage.png"),new JPanel());
with the first code the problem is not the change of the size horizontally (the width change correctly), the problem is only on the height, with the second code, if I add multiple lines inside the html code, the text appear incomplete (just show the middle line) (also the width behaves as expected, the problem is the height). . .
why is this happening? or how could I get this done?
Note: S.O.: Mac OS X 10.8.1
Solved!!! The problem was that the default UI over MAC OS X (com.apple.laf.AquaTabbedPaneContrastUI), you only need to change it to the basicTabbedPaneUI (or the one of your preference), in my particular case I need to extend this class (it was a pain in the *, because what I wanted was really complex) to get the look & feel that I was expecting, if you have the same trouble just do this before adding your tabs:
myTabbedPane.setUI(new BasicTabbedPaneUI());
Note: Checking the default UI of your TabbedPane, may solve many different problems.

How to print DIB backbuffer on printer - GDI, MFC

I'm using MFC's doc/view architecture to implement printing. I use double buffering, I draw everything onto my backbuffer which is DIB bitmap. Than I use StretchBlt to copy that DIB onto printer DC.
The strange thing is - print preview is working well! When I print on virtual PDF printer, it is working well! But when I print on actual printer (I'm testing on two different printers - same results) - it just prints "garbage". The "garbage" means sometimes it prints totally black page, sometimes it prints the first few pages repeatedly, i.e. it prints wrong part of DIB, just like if I messed up coordinates to StretchBlt, but I didn't mess anything up, I checked multiple times, plus why is print preview is working flawlessly then?
I tried many variations:
Using memory DC compatible to screen DC, when printing.
Using memory DC compatible to printer DC, and selecting my DIB into it.
Using memory DC compatible to printer DC, and using dedicated DIB onto which I copy my original backbuffer DIB.
etc.
But the results are same. Below is the code where i create the DIB. I think the DIB format might be the problem, so please advice if there is something wrong with it. I tried both 24 bits and 32 bits as values for bmiHeader.biBitCount.
// Setup proper backbuffer:
_CleanupBackBufferStuff();
_pMemDc = new CDC;
_pMemDc->CreateCompatibleDC(&aDC);
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = _sizeBackBuffer.cx;
bmi.bmiHeader.biHeight = -_sizeBackBuffer.cy; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24; // Tried 32 as well
bmi.bmiHeader.biCompression = BI_RGB;
unsigned char *pBitmapRawBits = 0;
HANDLE hMemBitmap = CreateDIBSection(aDC.GetSafeHdc(), &bmi, DIB_RGB_COLORS, (void**)&pBitmapRawBits, 0, 0);
_hOldSelBitmap = (HBITMAP)_pMemDc->SelectObject(hMemBitmap);
Also here is the code for StretchBlt (nothing special here):
pDC->SetStretchBltMode(HALFTONE);
SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, 0);
BOOL bSuccess = pDC->StretchBlt(rectClipBoxPlayground.left, rectClipBoxPlayground.top, rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(),
_pMemDc, rectClipBoxBackBuffer.left, rectClipBoxBackBuffer.top, rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(), SRCCOPY);
StretchBlt returns true, also (pDC->GetDeviceCaps(RASTERCAPS) & RC_STRETCHBLT) is true as well.
UPDATE: After Adrian's comment, I changed my code to use StretchDIBits. The problem is still the same! Below is the code I'm using currently:
// Copy back buffer to screen dc:
pDC->SetStretchBltMode(HALFTONE);
SetBrushOrgEx(pDC->GetSafeHdc(), 0, 0, 0);
HBITMAP hMemBitmap = (HBITMAP)_pMemDc->SelectObject(_hOldSelBitmap);
DWORD dwLines = StretchDIBits(pDC->GetSafeHdc(),
rectClipBoxPlayground.left, rectClipBoxPlayground.top, rectClipBoxPlayground.Width(), rectClipBoxPlayground.Height(),
rectClipBoxBackBuffer.left, _sizeBackBuffer.cy - rectClipBoxBackBuffer.top - rectClipBoxBackBuffer.Height(), rectClipBoxBackBuffer.Width(), rectClipBoxBackBuffer.Height(),
_pBitmapRawBits, &_bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
_pMemDc->SelectObject(hMemBitmap);
It still behaives like the source coordinates are incorrect. It either prints one of first few pages (no matter what page I select), or prints almost-fully-black pages. The print preview is working perfectly, so this makes me think there should be no problems with my coordinate-calculation code. It works in preview, it works with virtual (pdf) printer, it fails when printing on actual printer. What the hell?....
Make sure you don't have the DIBSECTION selected into more than one DC at a time. That can cause all sorts of unpredictable behavior.
For printing, you can probably bypass the memory DC altogether if you keep your bmi and pBitmapRawBits handy. Make sure the DIBSECTION is not selected into any DC, and then call SetDIBitsToDevice or StretchDIBits to transfer the image to the printer DC.
If you're still having problems, you might want to check the capabilities of your printers. Not all the drivers support all the bitmap transfer methods. I believe the printing system is supposed to hide those differences from you, but perhaps not. Call GetDeviceCaps on your printer DC, and check the RASTERCAPS for RC_BITBLT and friends.

Resources