I am trying to make a very simple window that doesn't get resized or positioned by a window manager. I thought what I wrote below would work, am I missing something?
// Create a window
xcb_window_t \
window = xcb_generate_id(connection);
uint32_t \
mask = \
XCB_CW_BACK_PIXEL | \
XCB_CW_BORDER_PIXEL | \
XCB_CW_EVENT_MASK | \
XCB_CW_OVERRIDE_REDIRECT;
uint32_t \
win_values[] = {
default_screen->white_pixel,
0,
XCB_EVENT_MASK_EXPOSURE,
1
};
xcb_create_window(
connection,
default_screen->root_depth,
window,
default_screen->root,
0, 0, 500, 500, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
default_screen->root_visual,
mask, win_values
);
it seems to work if I remove the event mask, how can I handle events then?
You have to switch the event mask and override redirect:
uint32_t \
win_values[] = {
default_screen->white_pixel,
0,
1,
XCB_EVENT_MASK_EXPOSURE
};
For clarity, you should also switch the order in mask, but it does not really matter there. The value would not change.
How did I find this? I look at /usr/include/xcb/xproto.h and search for XCB_CW_BACK_PIXEL. This leads to the xcb_cw_t enum. The values you provide must be in the same order as in this enum.
(And no, I do not know a simpler way to figure this out. I know other ways, but no simpler one.)
Related
For some reason, I'm not able to draw at all on a X11 window with a depth of 32 in my reparenting WM. I've tried using Xft for drawing text, drawing rectangles, the inbuilt functionality for drawing text... nothing shows up on depth 32 windows. This is how I draw the window, using the X11rb library:
let win_aux = xproto::CreateWindowAux::new()
.event_mask(
xproto::EventMask::EXPOSURE
| xproto::EventMask::SUBSTRUCTURE_REDIRECT
| xproto::EventMask::SUBSTRUCTURE_NOTIFY
| xproto::EventMask::BUTTON_PRESS
| xproto::EventMask::BUTTON_RELEASE
| xproto::EventMask::POINTER_MOTION
| xproto::EventMask::ENTER_WINDOW
| xproto::EventMask::PROPERTY_CHANGE,
)
.background_pixel(self.config.background_pixel)
.border_pixel(self.config.active_border_pixel)
.colormap(attr.colormap);
self.conn.create_window(
geom.depth,
frame_win,
screen.root,
geom.x,
geom.y,
geom.width,
geom.height + self.config.title_height as u16,
self.config.border_width as u16,
xproto::WindowClass::INPUT_OUTPUT,
attr.visual,
&win_aux,
)?;
self.conn.grab_server()?.check()?;
self.conn
.change_save_set(xproto::SetMode::INSERT, ev.window)?
.check()?;
self.conn
.reparent_window(ev.window, frame_win, 0, self.config.title_height as i16)?
.check()?;
self.conn.map_window(ev.window)?.check()?;
self.conn.map_window(frame_win)?.check()?;
How do I resolve this issue?
I haven't fully figured out what is going on, but I ran your code under xtrace and found this:
000:<:005c: 20: RENDER-Request(139,4): CreatePicture pid=0x00200001 drawable=0x00200002 format=0x00000029 values={}
000:<:005d: 16: Request(53): CreatePixmap depth=0x20 pid=0x00200003 drawable=0x0000051f width=1 height=1
000:<:005e: 24: RENDER-Request(139,4): CreatePicture pid=0x00200004 drawable=0x00200003 format=0x00000025 values={repeat=true(0x01)}
000:<:005f: 8: Request(54): FreePixmap drawable=0x00200003
000:>:005c:Error 8=Match: major=139, minor=4, bad=0x00000029, seq=005c
So, something you are doing causes an Error. I guess this then also explains the missing drawing.
So, my first suggestion is to not silently ignore errors:
diff --git a/src/wm.rs b/src/wm.rs
index 68e43f5..bc95d20 100644
--- a/src/wm.rs
+++ b/src/wm.rs
## -240,7 +240,10 ## where
let ev = match self.conn.wait_for_event() {
Ok(ev) => ev,
- Err(_) => continue,
+ Err(e) => {
+ eprintln!("Error: {:?}", e);
+ continue;
+ }
};
let _ = self.dispatch_event(&ev);
}
## -293,6 +296,7 ## where
protocol::Event::DestroyNotify(ev) => self.handle_destroy_notify(ev)?,
protocol::Event::ClientMessage(ev) => self.handle_client_message(ev)?,
protocol::Event::ConfigureNotify(ev) => self.handle_configure_notify(ev)?,
+ protocol::Event::Error(ev) => eprintln!("X11 error: {:?}", ev),
_ => {}
}
Ok(())
(Only the second change is necessary here, but I came across the first one first and only later figured out that I was wrong.)
I am not quite sure what the second problem is, but I would guess that it is the following code:
xft::XftDrawCreate(
self.xlib_conn,
frame_win.into(),
xlib::XDefaultVisual(self.xlib_conn, 0),
xlib::XDefaultColormap(self.xlib_conn, 0),
)
Here, you are telling xft that your frame window uses the screen's default visual and colormap. However, for depth=32 windows, this cannot be true (and I checked - your frame window is also depth=32 in this case).
So... you somehow have to give the right visual to Xft and colormap to Xft. Apparently, you use a GetWindowAttributes request to create your frame window with the same values as the contained client window.
So, now you'll somehow have to translate this visual XID to a Xlib Visual* pointer, which sounds like some hairy code....
I need to be able to determine the size of the edit box according to the text I have, and a maximum width.
There are similar questions and answers, which suggest GetTextExtentPoint32 or DrawTextEx.
GetTextExtentPoint32 doesn't support multiline edit controls, so it doesn't fit.
DrawTextEx kind of works, but sometimes the edit box turns out to be larger than necessary, and, what's worse, sometimes it's too small.
Then there's EM_GETRECT and EM_GETMARGINS. I'm not sure whether I should use one of them, or maybe both.
What is the most accurate method for calculating the size? This stuff is more complicated then it should be... and I prefer not to resort to reading the source code of Wine or ReactOS.
Thanks.
Edit
Here's my code and a concrete example:
bool AutoSizeEditControl(CEdit window, LPCTSTR lpszString, int *pnWidth, int *pnHeight, int nMaxWidth = INT_MAX)
{
CFontHandle pEdtFont = window.GetFont();
if(!pEdtFont)
return false;
CClientDC oDC{ window };
CFontHandle pOldFont = oDC.SelectFont(pEdtFont);
CRect rc{ 0, 0, nMaxWidth, 0 };
oDC.DrawTextEx((LPTSTR)lpszString, -1, &rc, DT_CALCRECT | DT_EDITCONTROL | DT_WORDBREAK);
oDC.SelectFont(pOldFont);
::AdjustWindowRectEx(&rc, window.GetStyle(), (!(window.GetStyle() & WS_CHILD) && (window.GetMenu() != NULL)), window.GetExStyle());
UINT nLeftMargin, nRightMargin;
window.GetMargins(nLeftMargin, nRightMargin);
if(pnWidth)
*pnWidth = rc.Width() + nLeftMargin + nRightMargin;
if(pnHeight)
*pnHeight = rc.Height();
return true;
}
I call it with nMaxWidth = 143 and the following text (below), and get nHeight = 153, nWidth = 95. But the numbers are too small for the text to fit, on both axes.
The text (two lines):
Shopping
https://encrypted.google.com/search?q=winapi+resize+edit+control+to+text+size&source=lnms&tbm=shop&sa=X&ved=0ahUKEwiMyNaWxZjLAhUiLZoKHQcoDqUQ_AUICigE
Edit 2
I found out that the word wrapping algorithm of DrawTextEx and of the exit control are different. For example, the edit control wraps on ?, DrawTextEx doesn't. What can be done about it?
Is there a reliable way to get the inner and outer rectangle of a top
level window with XCB/Xlib? (IOW frame and client rectangle).
Here's what I tried:
xcb_get_geometry always returns the initial dimensions even after
the window gets resized (what gives?)
I figured I would call xcb_query_tree repeatedly until I find the
window's frame window - is this the way to do it? I figure ICCCM/EWMH
should provide this but couldn't find anything. Is there any other
standard/non-standard for this? Anyway that doesn't work with
compiz/ubuntu10 because xcb_query_tree reports the client window as
having root = parent (under normal ubuntu wm the window gets properly
reparented).
xcb_translate_coordinates() seemed to be the only reliable way to
get root-based coords[1] in 2007 -- is this still the case? I.e. is
XCB_CONFIGURE_NOTIFY non-standard with WMs?
[1] http://fixunix.com/xwindows/91652-finding-position-top-level-windows.html
This is a partial answer as it only explains how to find the inner dimensions of a window. Also I am not sure if this is the canonical way to go but it works for me.
You can subscribe to the XCB_EVENT_MASK_RESIZE_REDIRECT event when creating a window:
xcb_window_t window = xcb_generate_id (connection);
const xcb_setup_t *setup = xcb_get_setup (connection);
xcb_screen_t *screen = xcb_setup_roots_iterator (setup).data;
uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t valwin[1] = { XCB_EVENT_MASK_EXPOSURE
| XCB_EVENT_MASK_RESIZE_REDIRECT };
xcb_create_window(
connection,
XCB_COPY_FROM_PARENT,
window,
screen->root,
0, 0,
800, 600,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, valwin);
xcb_map_window(connection, window);
xcb_flush(connection);
In the event loop you can then keep track of resizes:
xcb_generic_event_t *event;
uint16_t width = 0, height = 0;
while ((event = xcb_wait_for_event(connection)) != NULL) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE: {
/* ... */
break;
}
case XCB_RESIZE_REQUEST: {
auto resize = (xcb_resize_request_event_t*) event;
if (resize->width > 0) width = resize->width;
if (resize->height > 0) height = resize->height;
break;
}
default:
break;
}
free(event);
xcb_flush(connection);
}
Note that I am not sure whether this event is emitted when you initiate the resize from your application code using xcb_configure_window for example. I never tested it and just update the width and height in a wrapper function for xcb_configure_window.
The scenario is that I have a list of window handles to top level windows and I want to shift them around so they are arranged in the z-order of my choosing. I started off by iterating the list (with the window I want to end up on top last), calling SetForegroundWindow on each one. This seemed to work some of the time but not always, improving a little when I paused slightly in between each call.
Is there a better way to do this?
Edit:
It looks like the BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos route is the way to go. However, I can't seem to get it to work with more than one window at a time. When I limit the window list to a single window, it works correctly. When the list has multiple windows, it only seems to get one of them. Here is pseudo code of what I'm doing:
HWND[] windows;
HWND lastWindowHandle = 0;
HDWP positionStructure = BeginDeferWindowPos(windows.length);
for (int i = 0; i < windows.length; i++)
{
positionStructure = DeferWindowPos(positionStructure, windows[i],
lastWindowHandle, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
EndDeferWindowPos(positionStructure);
I'm sure it's something small/obvious I'm missing here but I'm just not seeing it.
There is a special set of api's for setting window positions for multiple windows: BeginDeferWindowPos + DeferWindowPos + EndDeferWindowPos (SetWindowPos in a loop will also work of course, but it might have more flicker)
You can use SetWindowPos to order your top-level windows.
// Hypothetical function to get an array of handles to top-level windows
// sorted with the window that's supposed to be topmost at the end of array.
HWND* windows = GetTopLevelWindowsInOrder();
int numWindows = GetTopLevelWindowCount();
for(int i = 0; i < numWindows; ++i)
{
::SetWindowPos(windows[i], HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
I'm trying to learn to use the different ffmpeg libs with Cocoa, and I'm trying to get frames to display with help of Core Video. It seems I have gotten the CV callbacks to work, and it gets frames which I try to put in a CVImageBufferRef that I later draw with Core Image.
The problem is I'm trying to get PIX_FMT_YUYV422 to work with libswscale, but as soon as I change the pixel format to anything other than PIX_FMT_YUV420P it crashes with EXC_BAD_ACCESS.
As long as I use YUV420P the program runs, allthough it doesn't display properly. I suspected that the pixel format isn't supported, so I wanted to try PIX_FMT_YUYV422.
I have had it running before and successfully wrote PPM files with PIX_FMT_RGB24. For some reason it just crashes on me now, and I don't see what might be wrong.
I'm a bit in over my head here, but that is how I prefer to learn. :)
Here's how I allocate the AVFrames:
inFrame = avcodec_alloc_frame();
outFrame = avcodec_alloc_frame();
int frameBytes = avpicture_get_size(PIX_FMT_YUYV422, cdcCtx->width, cdcCtx->height);
uint8_t *frameBuffer = malloc(frameBytes);
avpicture_fill((AVPicture *)outFrame, frameBuffer, PIX_FMT_YUYV422, cdcCtx->width, cdcCtx->height);
Then I try to run it through swscale like so:
static struct SwsContext *convertContext;
if (convertContext == NULL) {
int w = cdcCtx->width;
int h = cdcCtx->height;
convertContext = sws_getContext(w, h, cdcCtx->pix_fmt, outWidth, outHeight, PIX_FMT_YUYV422, SWS_BICUBIC, NULL, NULL, NULL);
if (convertContext == NULL) {
NSLog(#"Cannot initialize the conversion context!");
return NO;
}
}
sws_scale(convertContext, inFrame->data, inFrame->linesize, 0, outHeight, outFrame->data, outFrame->linesize);
And finally I try to write it to a pixel buffer for use with Core Image:
int ret = CVPixelBufferCreateWithBytes(0, outWidth, outHeight, kYUVSPixelFormat, outFrame->data[0], outFrame->linesize[0], 0, 0, 0, ¤tFrame);
With 420P it runs, but it doesnt match up with the kYUVSPixelformat for the pixel buffer, and as I understand it doesnt accept YUV420.
I would really appreciate any help, no matter how small, as it might help me struggle on. :)
This certainly isn't a complete code sample, since you never decode anything into the input frame. If you were to do that, it looks correct.
You also don't need to fill the output picture, or even allocate an AVFrame for it, really.
YUV420P is a planar format. Therefore, AVFrame.data[0] is not the whole story. I see a mistake in
int ret = CVPixelBufferCreateWithBytes(0, outWidth, outHeight, kYUVSPixelFormat, outFrame->data[0], outFrame->linesize[0], 0, 0, 0, ¤tFrame);
For planar formats, you will have to read data blocks from AVFrame.data[0] up to AVFrame.data[3]