How to control X11 app level window stacking? - x11

Is there any way to have 2 windows in X11, with the following criteria:
Second window always stays on top of the first one
Second window doesn't stay on top of other applications' windows
No flickering when switching windows
Both windows need to be top level windows (not parented under each other) and not blocking
Making the second one modal almost works, but it blocks the first one, which is not desired.

Here's how one may do this in Qt by creating non-modal QDialog widgets.
#include <QObject>
#include <QApplication>
#include <QPushButton>
#include <QDialog>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
QPushButton p1("moo", 0);
QDialog d1(&p1);
QPushButton p2("roo", &d1);
QDialog d2(&p1);
QPushButton p3("goo", &d2);
QObject::connect(&p1, &QPushButton::clicked, [&](){p2.setText("w00t!");});
QObject::connect(&p2, &QPushButton::clicked, [&](){p1.setText("n00t!");});
QObject::connect(&p3, &QPushButton::clicked, [&](){p1.setText("eh?"); p2.setText("meh!");});
p1.resize(400, 400);
p2.resize(200, 200);
p3.resize(200, 200);
p1.show();
p2.show();
p3.show();
d1.show();
d2.show();
return a.exec();
}
All of your conditions are met as far as I can tell.

Related

QChart with QAreaSeries with large data is very slow

I am playing around with QCharts (using area chart example as a template).
I am drawing an area chart with 10000 points in each of the series, and am finding that it is very slow, 30s for the window to appear and resizing the window results in the process hanging, its unusable for this dataset . Any ideas what could be wrong here ? I have seen that disabling anti aliasing might help, however it doesn't.
I have the folllowing code
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QAreaSeries>
#include <QRandomGenerator>
#include <QDateTime>
#include <QtCharts/QHXYModelMapper>
#include <QTimer>
#include "boost/range/irange.hpp"
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto *upper = new QLineSeries;
auto *lower = new QLineSeries;
auto *generator = QRandomGenerator::global();
const auto maxSamples = 10000;
for(auto x : boost::irange(0, maxSamples))
{
lower->append(QPointF(x, 0));
upper->append(QPointF(x, generator->bounded(0, 100)));
}
auto *series = new QAreaSeries(upper, lower);
QChart *chart = new QChart();
chart->addSeries(series);
chart->createDefaultAxes();
chart->legend()->setVisible(false);
chart->axisY(series)->setRange(0, 100);
QChartView *chartView = new QChartView(chart);
//chartView->setRenderHint(QPainter::Antialiasing);
QMainWindow window;
window.setCentralWidget(chartView);
window.resize(800, 600);
window.show();
return a.exec();
}
Any ideas what could be the problem here?
We have bounced into this times ago and found that the implementation of append() in a QXYSeries was suboptimal and was consuming a lot of time with large datasets.
To improve the performance, we now use:
void QXYSeries::replace(QVector<QPointF> points)
with a local vector that we first allocate to the dataset size, and then fill with the actual data.
With large datasets, you may still have performance issues, depending on the type of series, due to the construction of the graphics items used to render the series.

SDL in Xcode on MacMini M1 - Window not showing

I know this is similar to some other posts but still a little different...
I'm using the newest version of Xcode with SDL. The following code should show me a window but nothing happens except that I get the following message: Metal API Validation Enabled
Program ended with exit code: 0
When I disable this validation nothing happens at all. Any ideas on what might be wrong?
#include <SDL2/SDL.h>
#include <iostream>
int main() {
SDL_Init((SDL_INIT_VIDEO) <0);
SDL_Window *window;
window = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); //also tried different WINDOW_ input here
if (window == NULL) {
// In the case that the window could not be made...
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(3000);
}
````
I don't have enough reputation to comment, but for a start, the int main() should be replaced with int main(int argc, char* argv[]) and i'm not sure about SDL_Init((SDL_INIT_VIDEO) <0); just try SDL_Init(SDL_INIT_VIDEO); also, im not 100% about this I don't use mac, but if there are .dll on mac make sure you have the correct .dll files aswell (note what you're compiling (64bit or 32bit) use the corresponding .dll files)

QPrinter + QPainter writes invalid PDF file

I am simply trying to draw a rectangle to a PDF file using QPrinter + QPainter:
#include <QtWidgets>
#include <QPrinter>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QPrinter printer(QPrinter::HighResolution);
printer.setOutputFileName("/Users/jason/Desktop/example.pdf");
printer.setOutputFormat(QPrinter::PdfFormat);
QPainter painter;
painter.begin(&printer);
int width = painter.viewport().width();
int height = painter.viewport().height();
painter.setPen(Qt::black);
painter.drawRect(0.25*width, 0.25*height, 0.5*width, 0.5*height);
painter.end();
}
Using MacOS 10.15.4 and Qt 5.15.2 this results in a blank/invalid PDF file. The same code without the QPrinter.setOutputFormat and QPrinter.setOutputFileName correctly prints a rectangle on paper.
How can I using QPrinter/QPdfWriter + QPainter to draw to a PDF file?
I am a fool. I thought the PDF was blank, but it turns out if I zoom in really really far, I can see a faint grey line. Apparently the resolution of a PDF is much higher than that of my printer!
Using painter.setPen(QPen(QBrush(Qt::red), 100.0)) shows a clear rectangle as expected.

XReparentWindow works sporadically

I'm experimenting with XReparentWindow with the end goal to aggregate windows of multiple processes into one "cockpit" simulating process. Experiments with XReparentWindow works sporadically; sometimes the window is reparented successfully, sometimes not. When unsuccessfully reparented the (not) grabbed window flickers for a second and then proceedes as usual, and the grabber show undefined window content. It is successfull every other time (tempted to brute-force the problem away by always trying two times).
Edit 1: Checking output of XQueryTree right after XReparentWindow shows the grabbed window is properly reparented, but would appear to keep its frame origin where grabbed from on display rather than being moved to the grabber window.
The grabbed window is from a real-time OpenGL rendering application, compiled from source. The application does not anticipate the grabbing in any way (maybe it should?). I have also tried grabbing glxgears and a GNOME Terminal, same result.
The experimental code, taking window to grab as program argument (e.g. using xwininfo | grep "Window id"):
#include <X11/Xlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h> // usleep
int main(int argc, char** argv) {
assert(argc==2);
Window window, extwin;
sscanf(argv[1], "%p", &extwin);
Display* display = XOpenDisplay(0);
window = XCreateWindow(display, RootWindow(display, 0), 0, 0, 500, 500, 0, DefaultDepth(display, 0), InputOutput, DefaultVisual(display, 0), 0, 0);
XMapWindow(display, window);
XReparentWindow(display, extwin, window, 0, 0);
while(1) {
XFlush(display);
usleep(3e5);
}
return 0;
}
(Code is manually exported from a restricted environment. Sorry for any typos made during export.)
Looking forward for suggestions of what to try out next.
Edit 2: Having captured the event stream of the grabbed window using xev I notice something odd; after being reparented to the grabber window, it reparents itself back to root window after less than a second (restricted environment, typing what's seen on other window with anticipated significance):
UnmapNotify event ...
ReparentNotify event ... parent 0x4000001 (grabber window)
MapNotify event ...
ConfigureNotify event ... synthetic YES (what is this?)
UnmapNotify event ...
ReparentNotify event ... parent 0xed (reparenting back to parent window, but why?)
MapNotify event ...
VisibilityNotify event ...
Expose event ...
PropertyNotify event ... _NET_WM_DESKTOP state PropertyDelete
PropertyNotify event ... _NET_WM_STATE state PropertyDelete
PropertyNotify event ... WM_STATE state PropertyNewValue
I quit the program and try again a second time, at which the output that continues is:
UnmapNotify event ...
ReparentNotify event ... parent 0x4000001 (grabber window)
MapNotify event ...
VisibilityNotify event ...
Expose event ...
What is going on?
I am a newbie in the GUI world and I don't know X11 internals. But I've just read a very interesting documentation (https://www.x.org/releases/current/doc/libX11/libX11/libX11.html)
Most of the functions in Xlib just add requests to an output buffer. These requests later execute asynchronously on the X server. Functions that return values of information stored in the server do not return (that is, they block) until an explicit reply is received or an error occurs. You can provide an error handler, which will be called when the error is reported.
If a client does not want a request to execute asynchronously, it can follow the request with a call to XSync, which blocks until all previously buffered asynchronous events have been sent and acted on. As an important side effect, the output buffer in Xlib is always flushed by a call to any function that returns a value from the server or waits for input.
So I guess what you have is a race condition between reparenting and something.
This works for me:
// gcc -lX11 -lXcomposite a.c && ./a.out 0x1a00001
// IDs can be gotten from
// `wmctrl -l` (shows only the parent windows) or `xwininfo`.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <X11/Xlib.h> // -lX11
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h> // optional, -lXcomposite
void reparent (Display *d, Window child, Window new_parent)
{
XUnmapWindow(d, child);
XMapWindow(d, new_parent);
XSync(d, False);
XReparentWindow(d, child, new_parent, 0, 0);
XMapWindow(d, child);
// 1 ms seems to be enough even during `nice -n -19 stress -c $cpuThreadsCount` (pacman -S stress) on linux-tkg-pds.
// Probably can be decreased even further.
usleep(1e3);
XSync(d, False);
}
int main (int argc, char **argv)
{
Display *d = XOpenDisplay(XDisplayName(NULL));
int s = DefaultScreen(d);
Window root = RootWindow(d, s);
if (argc != 2)
{
printf("Wrong number of arguments, exiting.");
exit(1);
}
Window child = strtol(argv[1], NULL, 0);
Window new_parent = XCreateSimpleWindow(
d, root, 0, 0, 500, 500, 0, 0, 0
);
// (Optional)
// Allow grabbing by `ffmpeg -f x11grab -window_id`
// while being on the same virtual screen
// AND (focused or unfocused)
// AND (seen or unseen)
// AND no other window is both fullscreen and focused.
XCompositeRedirectWindow(d, child, CompositeRedirectAutomatic);
// After `new_parent` is destroyed (when the program exists),
// don't make `child` unmapped/invisible.
XAddToSaveSet(d, child);
reparent(d, child, new_parent);
XEvent e;
while (1)
{
XNextEvent(d, &e);
}
return 0;
}
Also it's possible to use xdotool:
xdotool windowunmap $CHID
xdotool windowreparent $CHID $NEWPID
xdotool windowmap --sync $CHID
Brute force solution, grabbing the window repeatedly:
#include <X11/Xlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h> // usleep
int main(int argc, char** argv) {
assert(argc==2);
Window window, extwin;
sscanf(argv[1], "%p", &extwin);
Display* display = XOpenDisplay(0);
window = XCreateWindow(display, RootWindow(display, 0), 0, 0, 500, 500, 0, DefaultDepth(display, 0), InputOutput, DefaultVisual(display, 0), 0, 0);
XMapWindow(display, window);
while(1) {
Window root, parent, *ch;
unsigned int nch;
XQueryTree(display, extwin, &root, &parent, &ch, &nch);
if(parent!=window) {
XReparentWindow(display, extwin, window, 0, 0);
}
if(nch>0) { XFree(ch); }
XFlush(display);
usleep(3e5);
}
return 0;
}
Assuming this only happens once the clause can be disabled after two calls to reparent. Works on my machine. Would appreciate full explaination of what is really going on.
I have never tried with an OpenGL application and do not have the environment here.
Maybe try first with a simple X app (like xclock) and observe if you get the same behaviour.
If yes, that's your code, if no, probably OpenGL interaction.
From your snippset, two comments though:
In the while loop, you should consume the X events
XEvent e;
while(1) {
XNextEvent(d, &e);
}
Then the XAddToSaveSet function does not work properly.
You will need to use the XFixes in order to properly restore that window in case of a crash.
#include <X11/extensions/Xfixes.h>
...
// The Xorg API is buggy in certain areas.
// Need to use the XFixes extensions to address them
// Initializes these extensions
int event_base_return = 0;
int error_base_return = 0;
Bool result = XFixesQueryExtension(display, &event_base_return);
printf("XFixesQueryExtension result: %d. eventbase: %d - errorbase: %d\n", result, event_base_return, error_base_return);
// We actually only need version 1.0. But if 4.0 is not there then something is really wrong
int major = 4;
int minor = 0;
result = XFixesQueryVersion(display, &major, &minor);
printf("XFixesQueryVersion result: %d - version: %d.%d\n", result, major, minor);
...
XReparentWindow(display, childWindowId, parentWindowId, 0, 0);
XFixesChangeSaveSet(display, childWindowId, SetModeInsert, SaveSetRoot, SaveSetUnmap);
...

Resizing a cell's height and Witdth and loading an image in QTableWidget

I want to make a 8*8 table with square cells ( a chess board ). Now I have the code to make the table but don't know how to resize the cells to be square shaped.
I also want to put pictures of pieces into the cells. How should I do these?
here is the code i have:
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QHBoxLayout>
#include <QTableWidget>
class Table : public QWidget
{
public:
Table(QWidget *parent = 0);
};
Table::Table(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *hbox = new QHBoxLayout(this);
QTableWidget *table = new QTableWidget(8 , 8 , this);
hbox->addWidget(table);
setLayout(hbox);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Table t;
t.show();
return a.exec();
}
EDIT:
If anyone can help me with loading an image as the background of cell too, it would be very appreciated!
I use this code and compiler does not generate an error but program fails to run. I think the problem is with the table->item(0,0). Should I initialize it first?
QString fileName = "1.bmp";
QPixmap pic (fileName);
QIcon icon (pic);
table->item(0,0)->setIcon(icon);
To make the cells square shaped do something like this:
// set the default size, here i've set it to 20px by 20x
table->horizontalHeader()->setDefaultSectionSize(20);
table->verticalHeader()->setDefaultSectionSize(20);
// set the resize mode to fixed, so the user cannot change the height/width
table->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
Edit: To set the images, set the icon attribute on your QTableWidgetItems
after searching and searching and searching.... I finally got the answer. I should first make a QBrush object and set it as a background of a QtableWidgetItem and then use table->setItem !!!
QString fileName = "/1.bmp";
QPixmap pic (fileName);
QBrush brush(pic);
QTableWidgetItem* item = new QTableWidgetItem();
item->setBackground(brush);
table->setItem(0,0,item);

Resources