[X2Go-Commits] [x2gokdriveclient] 01/01: rootless mode for x2gokdriveclient
git-admin at x2go.org
git-admin at x2go.org
Mon Jan 31 16:48:05 CET 2022
This is an automated email from the git hooks/post-receive script.
x2go pushed a commit to branch feature/rootless-mode
in repository x2gokdriveclient.
commit a8f41b949861f972f2c89e0f163e5b507a6ea1a6
Author: Oleksandr Shneyder <o.shneyder at phoca-gmbh.de>
Date: Mon Jan 31 09:47:49 2022 -0600
rootless mode for x2gokdriveclient
---
client.cpp | 487 +++++++++++++++++++++++++++++++++++++++++++--------
client.h | 44 ++++-
displayarea.cpp | 146 ++++++++-------
displayarea.h | 11 +-
extwin.cpp | 332 +++++++++++++++++++++++++++++++++++
extwin.h | 80 +++++++++
menuframe.cpp | 8 +-
x2gokdriveclient.pro | 4 +-
8 files changed, 947 insertions(+), 165 deletions(-)
diff --git a/client.cpp b/client.cpp
index 6dba871..9e8aa29 100644
--- a/client.cpp
+++ b/client.cpp
@@ -54,6 +54,7 @@
#include <QMenu>
#include <QClipboard>
#include "screenidentifier.h"
+#include "extwin.h"
#ifdef Q_OS_LINUX
#include <xcbclip.h>
@@ -97,7 +98,7 @@ FrameRegion::~FrameRegion()
}
-Frame::Frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t numOfRegions, uint32_t crc)
+Frame::Frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t numOfRegions, uint32_t crc, uint32_t winId)
{
this->crc=crc;
@@ -105,6 +106,7 @@ Frame::Frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t nu
this->y=y;
this->width=width;
this->height=height;
+ this->winId=winId;
this->numOfRegions=numOfRegions;
}
@@ -159,17 +161,15 @@ Client::Client()
clipboard=new XCBClip(this);
#endif
- setGeometry(0,0,800,600);
-
- displayArea=new DisplayArea(this);
-
- displayArea->setObjectName("DisplayArea");
-
- displayArea->setStyleSheet("QFrame#DisplayArea{background-color:black;border-image:url(:res/x2gobg.svg) 0 0 0 0 stretch stretch;}");
+ parseOptions();
+ if(!rootless)
+ initDesktopMode();
+ else
+ {
+ hide();
+ ((QGuiApplication*)QGuiApplication::instance())->setQuitOnLastWindowClosed(false);
+ }
- displayArea->show();
- setCentralWidget(displayArea);
- setWindowIcon(QIcon(":res/x2goclient.png"));
clientSocket=new QTcpSocket(this);
@@ -201,18 +201,39 @@ Client::Client()
{
slotScreenAdded(screen);
}
+ QTimer::singleShot(10,this,SLOT(connectToServer()));
+}
+
+Client::~Client()
+{
+ KDRStdErr()<<"Client destructor"<<KDR_ENDL;
+
+ freeMessageBuffer();
+ if(currentFrame)
+ delete currentFrame;
+ if(currentCursor)
+ delete currentCursor;
+}
+void Client::initDesktopMode()
+{
+ setGeometry(0,0,800,600);
+ displayArea=new DisplayArea(this,this);
+ displayArea->setObjectName("DisplayArea");
+ displayArea->setStyleSheet("QFrame#DisplayArea{background-color:black;border-image:url(:res/x2gobg.svg) 0 0 0 0 stretch stretch;}");
+ displayArea->show();
+ setCentralWidget(displayArea);
+ setWindowIcon(QIcon(":res/x2goclient.png"));
QMenu* menuCon=menuBar()->addMenu(tr("&Connection"));
menu=menuBar()->addMenu(tr("&View"));
FSMenuBar=new MenuFrame(this, menu);
-// FSMenuBar->hide();
+ // FSMenuBar->hide();
menuBar()->hide();
connect(FSMenuBar, SIGNAL(editCaption()), this, SLOT(editWindowTitle()));
connect(this, SIGNAL(windowTitleChanged(const QString &)), FSMenuBar, SLOT(setCaption(const QString &)));
-
actRandr=menu->addAction(QIcon(":res/randr.svg"), tr("Multiple monitors"),this, SLOT(slotEnableRandr()));
actRandr->setCheckable(true);
menu->addSeparator();
@@ -227,28 +248,24 @@ Client::Client()
actRestore=menu->addAction(QIcon(":res/view-restore.svg"), tr("Restore") ,this, SLOT(slotRestore()));
menuBar()->addSeparator();
-
actDisconnect=menuCon->addAction( tr("Disconnect"),this, SLOT(slotDisconnect()));
actDisconnect->setIcon(QIcon(":res/network-disconnect.svg"));
actDisconnect->setToolTip(tr("Disconnect"));
-
- QTimer::singleShot(10,this,SLOT(connectToServer()));
-
connect(menu,SIGNAL(aboutToShow()), this, SLOT(slotSetupMenu()));
- setWindowTitle(tr("X2GoKDrive Client"));
-
+ setWindowTitle(mainWndTitle);
}
-
-Client::~Client()
+void Client::slotGrabDisplay()
{
- KDRStdErr()<<"Client destructor"<<KDR_ENDL;
-
- freeMessageBuffer();
-
- if(currentFrame)
- delete currentFrame;
- if(currentCursor)
- delete currentCursor;
+ if(hasUpdates)
+ {
+ // Client::KDRStdErr()<<"save display";
+ if(!rootless)
+ {
+ QScreen *screen = QGuiApplication::primaryScreen();
+ displayPix = screen->grabWindow(winId());
+ }
+ hasUpdates=false;
+ }
}
void Client::slotIdentifyScreen()
@@ -306,6 +323,9 @@ void Client::slotIdentifyScreen()
menu->show();
//hide the identifier, when no screen actions are hovered
QTimer::singleShot(100,this, SLOT(slotIdentifyScreen()));
+ QTimer *tm=new QTimer(this);
+ connect(tm, &QTimer::timeout, this, &Client::slotGrabDisplay);
+ tm->start(1000);
}
void Client::editWindowTitle()
@@ -382,7 +402,7 @@ void Client::resizeToSaved()
setWindowState(Qt::WindowNoState);
setWindowState(windowState() & ~Qt::WindowMaximized);
#endif
- KDRStdErr()<<"restore to "<<savedSize.width()<<"x"<<savedSize.height()<<" "<<savedPosition.x()<<","<<savedPosition.y();
+ KDRStdErr()<<"restore to "<<savedSize.width()<<"x"<<savedSize.height()<<" "<<savedPosition.x()<<","<<savedPosition.y()<<KDR_ENDL;
resize(savedSize);
move(savedPosition);
showNormal();
@@ -506,11 +526,13 @@ void Client::slotSetupMenu()
actDisp[i]->setVisible(false);
}
}
- displayArea->slotGrabDisplay();
+ slotGrabDisplay();
}
bool Client::isDisplayPointer(QMouseEvent* event)
{
+ if(rootless)
+ return true;
if(event->x() > FSMenuBar->x() && event->x() < FSMenuBar->x() + FSMenuBar->width() &&
event->y() > FSMenuBar->y() && event->y() < FSMenuBar->y() + FSMenuBar->height() &&
event->button()== Qt::NoButton && event->buttons() == 0)
@@ -531,19 +553,15 @@ void Client::freeMessageBuffer()
delete []messageBuffer;
messageBuffer=0l;
}
-void Client::connectToServer()
+
+void Client::parseOptions()
{
- setWindowTitle("X2GO SESSION");
+ mainWndTitle=tr("X2GoKDrive Client");
QStringList args=QCoreApplication::arguments();
- QString host="localhost";
- int port=15000;
QString optFile;
-
-
for(int i=0;i<args.count();++i)
{
KDRStdErr()<<args[i];
-
if(args[i]=="--debug")
{
debug=true;
@@ -562,17 +580,14 @@ void Client::connectToServer()
}
if(args[i]=="--title")
{
- setWindowTitle("X2GO-"+args[++i]);
- KDRStdErr()<<"set title to "<<windowTitle();
+ mainWndTitle=args[++i];
continue;
}
-
if(args[i]=="--width")
{
width=args[++i].toUInt();
continue;
}
-
if(args[i]=="--height")
{
height=args[++i].toUInt();
@@ -582,12 +597,15 @@ void Client::connectToServer()
{
fullscreen=true;
}
-
if(args[i]=="--randr")
{
useRandr=true;
}
-
+ if(args[i]=="--rootless")
+ {
+ rootless=true;
+ useRandr=true;
+ }
if(args[i]=="--screen")
{
multidisp=true;
@@ -617,7 +635,6 @@ void Client::connectToServer()
KDRStdErr()<<"Unsupported selections mode: "<<smode;
}
}
-
if(args[i].indexOf("option")!=-1)
{
QStringList parts=args[i].split(",");
@@ -626,13 +643,13 @@ void Client::connectToServer()
if(part.indexOf("options=")==0)
{
optFile=part.replace("options=","");
-#ifdef Q_OS_WIN
+ #ifdef Q_OS_WIN
QStringList parts=optFile.split("options:");
optFile=parts[0]+"options";
-#else
+ #else
QStringList parts=optFile.split(":");
optFile=parts[0];
-#endif
+ #endif
QString title=optFile;
title=title.replace("S-","X2GO-");
parts=title.split("/");
@@ -640,8 +657,8 @@ void Client::connectToServer()
{
if(title.indexOf("X2GO-")==0)
{
- setWindowTitle(title);
- break;
+ mainWndTitle=title;
+ break;
}
}
break;
@@ -649,16 +666,12 @@ void Client::connectToServer()
}
}
}
-
-
- KDRStdErr()<<"options file: "<<optFile;
-
+ KDRStdErr()<<"options file: "<<optFile<<KDR_ENDL;
if(optFile.length())
{
QFile fl(optFile);
if(fl.open(QIODevice::ReadOnly | QIODevice::Text))
{
-
QTextStream in(&fl);
QString str=in.readAll();
QStringList parts=str.split(",");
@@ -669,7 +682,6 @@ void Client::connectToServer()
host=part.replace("connect=","");
continue;
}
-
if(part.indexOf("cookie=")==0)
{
cookie=part.replace("cookie=","");
@@ -680,14 +692,12 @@ void Client::connectToServer()
}
continue;
}
-
if(part.indexOf("port=")==0)
{
port=part.replace("port=","").toInt();
continue;
}
}
-
}
else
{
@@ -695,8 +705,13 @@ void Client::connectToServer()
exitOnError(tr("Error! Can't open options File for reading"));
}
}
+}
- KDRStdErr(false)<<"Connecting to remote host "<<host<<":"<<port;
+void Client::connectToServer()
+{
+// setWindowTitle("X2GO SESSION");
+
+ KDRStdErr(false)<<"Connecting to remote host "<<host<<":"<<port<<KDR_ENDL;
clientSocket->connectToHost(host, port);
}
@@ -715,6 +730,21 @@ QPixmap Client::getPixmapFromCache(uint32_t crc)
return frameCache[crc];
}
+void Client::setDisplayPix(QPixmap pix, int32_t x, int32_t y)
+{
+ if(x==-1 || y==-1)
+ {
+ displayPix=pix;
+ }
+ else
+ {
+ QPainter pt;
+ pt.begin(&displayPix);
+ pt.drawPixmap(x,y,pix);
+ pt.end();
+ }
+}
+
void Client::renderFrame()
{
@@ -723,15 +753,18 @@ void Client::renderFrame()
//we got a whole display copy
if(currentFrame->x==-1)
{
- KDRStdErr()<<"got initial Image: "<<currentFrame->width<<"x"<<currentFrame->height<<" "<<QSizeToStr(currentFrame->regions[0]->pix.size());
- displayArea->resize(currentFrame->width, currentFrame->height);
- this->resize(currentFrame->width, currentFrame->height);
- displayArea->setDisplayPix(currentFrame->regions[0]->pix);
+ KDRStdErr()<<"got initial Image: "<<currentFrame->width<<"x"<<currentFrame->height<<" "<<QSizeToStr(currentFrame->regions[0]->pix.size())<<KDR_ENDL;
+ if(!rootless)
+ {
+ displayArea->resize(currentFrame->width, currentFrame->height);
+ this->resize(currentFrame->width, currentFrame->height);
+ }
+ setDisplayPix(currentFrame->regions[0]->pix);
}
else
{
- // KDRStdErr()<<"got Screen update:"<<currentFrame->width<< currentFrame->height<<currentFrame->regions[0]->pix.size();
- displayArea->setDisplayPix(currentFrame->regions[0]->pix, currentFrame->x, currentFrame->y);
+// KDRStdErr()<<"got Screen update: "<<currentFrame->x<<":"<< currentFrame->y<<" "<<KDR_ENDL;
+ setDisplayPix(currentFrame->regions[0]->pix, currentFrame->x, currentFrame->y);
}
}
else
@@ -778,13 +811,38 @@ void Client::renderFrame()
}
}
wantRepaint=true;
- displayArea->repaint(currentFrame->x, currentFrame->y, currentFrame->width, currentFrame->height);
- // KDRStdErr()<<"repaint: "<<currentFrame->x<<currentFrame->y<< currentFrame->width<< currentFrame->height<<displayArea->geometry();
+ if(!rootless)
+ displayArea->repaint(currentFrame->x, currentFrame->y, currentFrame->width, currentFrame->height);
+ else
+ {
+ if(currentFrame->winId)
+ {
+// KDRStdErr()<<"Paint currentFrame: "<<currentFrame->x<<":"<<currentFrame->y<<" "<< currentFrame->width<<"x"<< currentFrame->height<<KDR_HEX<<" for WIndow: "<<currentFrame->winId<<KDR_ENDL;
+ ExtWin* win=findExtWinById(currentFrame->winId);
+ if(win)
+ {
+ win->getDisplayArea()->repaint(currentFrame->x-win->geometry().x(), currentFrame->y-win->geometry().y(), currentFrame->width, currentFrame->height);
+ }
+ else
+ {
+ KDRStdErr()<<"Window not found: "<<KDR_HEX<<currentFrame->winId<<KDR_ENDL;
+ }
+ }
+ else
+ {
+ foreach(ExtWin* win, extWindows)
+ {
+ win->getDisplayArea()->repaint(currentFrame->x-win->geometry().x(), currentFrame->y-win->geometry().y(), currentFrame->width, currentFrame->height);
+ }
+ }
+ }
+ setUptodate();
}
void Client::setUptodate()
{
wantRepaint=false;
+ hasUpdates=true;
}
@@ -793,9 +851,12 @@ void Client::getImageFrame()
{
if(currentFrame)
delete currentFrame;
+ uint32_t winId=0;
+ if(rootless)
+ winId=*((uint32_t*)messageBuffer+7);
currentFrame=new Frame(*((uint32_t*)messageBuffer+1), *((uint32_t*)messageBuffer+2),*((uint32_t*)messageBuffer+3),
*((uint32_t*)messageBuffer+4),
- *((uint32_t*)messageBuffer+5), *((uint32_t*)messageBuffer+6));
+ *((uint32_t*)messageBuffer+5), *((uint32_t*)messageBuffer+6), winId);
// KDRStdErr()<<"got frame "<<currentFrame->crc<<currentFrame->numOfRegions;
if(!currentFrame->numOfRegions)
@@ -834,7 +895,8 @@ void Client::getCursorImage()
}
cursorCache.insert(currentCursor->serialNumber, cursor);
freeMessageBuffer();
- displayArea->setCursor(*cursor);
+ if(!rootless)
+ displayArea->setCursor(*cursor);
}
@@ -893,7 +955,8 @@ void Client::getCursor()
requestCacheRebuild();
return;
}
- displayArea->setCursor(*cursorCache[currentCursor->serialNumber]);
+ if(!rootless)
+ displayArea->setCursor(*cursorCache[currentCursor->serialNumber]);
}
else
{
@@ -1020,6 +1083,200 @@ void Client::getDeletedCursorsList()
freeMessageBuffer();
}
+ExtWin* Client::getExtWin(uint32_t id)
+{
+ foreach( ExtWin* win, extWindows)
+ {
+ if(win->getExtWinId()==id)
+ return win;
+ }
+ return NULL;
+}
+ExtWin* Client::findExtWinById(uint32_t extWinId)
+{
+ for(QList<ExtWin*>::iterator j=extWindows.begin(); j!=extWindows.end(); ++j)
+ {
+ if((*j)->getExtWinId()== extWinId)
+ {
+ return (*j);
+ }
+ }
+ return NULL;
+}
+
+void Client::getWinUpdateBuffer()
+{
+ //process window updates from messageBuffer
+ KDRStdErr()<<"get winupdate buffer size: "<<winUpdateSize<<KDR_ENDL;
+ int readFromBuf=0;
+ while(readFromBuf < winUpdateSize)
+ {
+ uint32_t extWinId=*((uint32_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint32_t);
+ uint8_t state=*((uint8_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint8_t);
+
+ ExtWin* win;
+ if(state!=2)
+ {
+ win=getExtWin(extWinId);
+ if(!win)
+ {
+ KDRStdErr()<<"Error: Wind "<<KDR_HEX<<extWinId<<" not found in the list"<<KDR_DEC<<KDR_ENDL;
+ freeMessageBuffer();
+ return;
+ }
+ }
+ if(state==3)
+ {
+ KDRStdErr()<<"win deleted: "<<KDR_HEX<<extWinId<<KDR_ENDL;
+ extWindows.removeAll(win);
+ win->close();
+ delete win;
+ }
+ else
+ {
+ int16_t x, y;
+ uint16_t w,h,bw;
+ uint8_t visibility;
+ uint8_t winType;
+ uint16_t nameSize;
+ QString name;
+ uint32_t parId=*((uint32_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint32_t);
+ uint32_t nextSibId=*((uint32_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint32_t);
+ uint32_t transWinId=*((uint32_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint32_t);
+ x=*((int16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+ y=*((int16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+ w=*((uint16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+ h=*((uint16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+ bw=*((uint16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+
+ visibility=*((uint8_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint8_t);
+
+ winType=*((uint8_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint8_t);
+
+ nameSize=*((uint16_t*)(messageBuffer+readFromBuf));
+ readFromBuf+=sizeof(uint16_t);
+ if(nameSize)
+ {
+ name=QString::fromUtf8(messageBuffer+readFromBuf, nameSize);
+ readFromBuf+=nameSize;
+ }
+ if(state==1)
+ {
+// KDRStdErr()<<"win changed: "<<KDR_HEX<<wptr;
+ }
+ else
+ {
+ Qt::WindowFlags flags;
+ switch(winType)
+ {
+ case WINDOW_TYPE_DIALOG:
+ flags=Qt::Dialog;
+ break;
+ case WINDOW_TYPE_SPLASH:
+ flags=Qt::SplashScreen;
+ break;
+ case WINDOW_TYPE_COMBO:
+ case WINDOW_TYPE_POPUP_MENU:
+ case WINDOW_TYPE_DROPDOWN_MENU:
+ flags=Qt::Window|Qt::FramelessWindowHint|Qt::BypassWindowManagerHint|Qt::X11BypassWindowManagerHint|Qt::WindowStaysOnTopHint;
+ break;
+ case WINDOW_TYPE_TOOLTIP:
+ flags=Qt::ToolTip;
+ break;
+ default:flags=Qt::Window ;
+ }
+
+ KDRStdErr()<<"new win: "<<KDR_HEX<<extWinId;
+ if(parId==0)
+ {
+ KDRStdErr()<<"win is top window: "<<KDR_HEX<<parId;
+ win=new ExtWin(extWinId,this, 0, flags);
+ win->setParent(0);
+ }
+ else
+ {
+ ExtWin* parentWin=findExtWinById(parId);
+ KDRStdErr()<<"win has parent!!!!!: "<<KDR_HEX<<parId;
+ if(!parentWin)
+ {
+ KDRStdErr()<<"parent Win not found in list: "<<KDR_HEX<<parId;
+ parentWin=(ExtWin*) this;
+ }
+ win=new ExtWin(extWinId,this, 0,flags);
+ win->setParent(0);
+ }
+ if(transWinId)
+ {
+ ExtWin* transWin=findExtWinById(transWinId);
+ if(!transWin)
+ {
+ KDRStdErr()<<"trans Win not found in list: "<<KDR_HEX<<transWinId;
+ }
+ else
+ {
+ KDRStdErr()<<"trans Window: "<<KDR_HEX<<transWinId;
+// win->setParent(transWin);
+ win->setTransWinId(transWinId);
+ if(winType==WINDOW_TYPE_DIALOG)
+ {
+ win->setModality(ExtWin::MOD_SINGLE);
+ }
+ }
+ }
+// KDRStdErr()<<"my Geometry: "<<KDR_HEX<<QRectToStr(win->geometry());
+
+ win->setWindowType(winType);
+
+ win->setParentId(parId);
+// KDRStdErr()<<"Place above"<<KDR_HEX<<nextSibPtr;
+ win->setNextSibId(nextSibId);
+ extWindows.append(win);
+ win->resize(w,h);
+ win->move(x,y);
+ win->showNormal();
+ win->raise();
+ win->activateWindow();
+// win->update();
+ }
+ KDRStdErr()<<KDR_DEC<<name<<" "<<x<<":"<<y<<" "<<w<<"x"<<h<<" bw - "<<bw<<" "<<visibility<<KDR_ENDL;
+ if(win->geometry().width() != w || win->geometry().height() != h)
+ win->resize(w,h);
+ if(win->geometry().x()!=x || win->geometry().y()!=y)
+ win->move(x,y);
+ if(win->windowTitle()!=name)
+ win->setWindowTitle(name);
+// win->raise();
+ if(win->getParentId()!=parId)
+ {
+ #warning inplement this
+ //set new parent and remap window
+ win->setParentId(parId);
+ KDRStdErr()<<"Reparent window";
+ }
+ if(win->getNextSibId()!=nextSibId)
+ {
+ #warning inplement this
+ // set sib and restack windows
+ win->setNextSibId(nextSibId);
+ KDRStdErr()<<"Check if need to Restack window???";
+ }
+ }
+ }
+ freeMessageBuffer();
+}
+
void Client::getDeletedFramesList()
{
//process list from messageBuffer
@@ -1046,6 +1303,28 @@ void Client::getDeletedFramesList()
freeMessageBuffer();
}
+const QList<ExtWin*> Client::getSiblings(ExtWin* win)
+{
+ QList<ExtWin*> siblings;
+ for(int i=0;i<extWindows.count();++i)
+ {
+ if((extWindows[i] != win) && (win->getParentId() == extWindows[i]->getParentId()))
+ {
+ siblings<<extWindows[i];
+ }
+ }
+ return siblings;
+}
+
+
+void Client::getWinUpdate()
+{
+ //get list of updated windows
+ bytesReady=0;
+ winUpdateSize=bytesLeftToRead=*((uint32_t*)messageBuffer+1);
+ currentDataType=WINUPDATEBUFFER;
+ freeMessageBuffer();
+}
void Client::getDeletedCursors()
{
@@ -1257,6 +1536,11 @@ void Client::readDataHeader()
reinitCaches();
break;
}
+ case WINUPDATE:
+ {
+ getWinUpdate();
+ break;
+ }
default:
{
KDRStdErr()<<"Unsupported header type: "<<data_type;
@@ -1334,6 +1618,11 @@ void Client::dataArrived()
getDeletedFramesList();
break;
}
+ case WINUPDATEBUFFER:
+ {
+ getWinUpdateBuffer();
+ break;
+ }
default:
{
KDRStdErr()<<"not ready";
@@ -1349,7 +1638,8 @@ void Client::dataArrived()
void Client::socketConnected()
{
- displayArea->setStyleSheet("QFrame#DisplayArea{background-color:black;}");
+ if(!rootless)
+ displayArea->setStyleSheet("QFrame#DisplayArea{background-color:black;}");
KDRStdErr(false)<<"Connected to server"<<KDR_ENDL<<"Established X server connection"<<KDR_ENDL;
if(cookie.length())
@@ -1359,7 +1649,7 @@ void Client::socketConnected()
KDRStdErr(false)<<"Wrong length of cookie should be 32, not "<<cookie.length()<<KDR_ENDL;
exitOnError(tr("Wrong cookie length"));
}
- KDRStdErr()<<"Sending Cookie to server";
+ KDRStdErr()<<"Sending Cookie to server"<<KDR_ENDL;
if(clientSocket->write(cookie.toLatin1().data(), 32)!=32)
{
KDRStdErr(false)<<"Failed to send auth cookie to server"<<KDR_ENDL;
@@ -1390,6 +1680,11 @@ void Client::checkServerVersion()
void Client::initGeometry()
{
+ if(rootless)
+ {
+ geometryChanged();
+ return;
+ }
if(geometry().width() != width || geometry().height() != height )
resize(width, height);
currentGeometry=geometry();
@@ -1446,6 +1741,8 @@ void Client::sendEvent(char* event)
void Client::moveEvent(QMoveEvent* )
{
+ if(rootless)
+ return;
if(geometryDelay->isActive())
geometryDelay->stop();
geometryDelay->start();
@@ -1454,6 +1751,8 @@ void Client::moveEvent(QMoveEvent* )
void Client::resizeEvent(QResizeEvent* )
{
+ if(rootless)
+ return;
if(geometryDelay->isActive())
geometryDelay->stop();
geometryDelay->start();
@@ -1551,6 +1850,31 @@ void Client::sendClientVersion()
sendEvent(evmsg);
}
+
+void Client::changeWindow(ExtWin* win)
+{
+ char evmsg[EVLENGTH]{};
+ uint32_t etype;
+ uint32_t extWinId=win->getExtWinId();
+ uint32_t sibId=win->getNextSibId();
+ uint16_t x,y,w,h;
+ x=win->adjustGeometry().x();
+ y=win->adjustGeometry().y();
+ w=win->adjustGeometry().width();
+ h=win->adjustGeometry().height();
+ etype=WINCHANGE;
+ KDRStdErr()<<"Request change for "<<KDR_HEX<<extWinId<<KDR_ENDL;
+ memcpy(evmsg,(char*)&etype,4);
+ memcpy(evmsg+4,(char*)&extWinId,4);
+ memcpy(evmsg+8,(char*)&sibId,4);
+ memcpy(evmsg+12,(char*)&x,2);
+ memcpy(evmsg+14,(char*)&y,2);
+ memcpy(evmsg+16,(char*)&w,2);
+ memcpy(evmsg+18,(char*)&h,2);
+ sendEvent(evmsg);
+ QTimer::singleShot(1,win,SLOT(update()));
+}
+
//requesting on demand selection
void Client::requestSelectionFromServer(SelectionType sel)
{
@@ -1572,13 +1896,21 @@ void Client::geometryChanged()
return;
}
+ QGuiApplication* app=(QGuiApplication*)QGuiApplication::instance();
QRect newGeometry;
- newGeometry.setTopLeft(geometry().topLeft());
- newGeometry.setSize(geometry().size());
+ if(rootless)
+ {
+ newGeometry=app->screens()[0]->availableVirtualGeometry();
+ hide();
+ }
+ else
+ {
+ newGeometry.setTopLeft(geometry().topLeft());
+ newGeometry.setSize(geometry().size());
+ }
- KDRStdErr()<<"geometry changed: "<<QRectToStr(newGeometry)<<" "<<QRectToStr(currentGeometry);
+ KDRStdErr()<<"geometry changed: "<<QRectToStr(newGeometry)<<" "<<QRectToStr(currentGeometry)<<KDR_ENDL;
- QGuiApplication* app=(QGuiApplication*)QGuiApplication::instance();
QRect newScreens[4];
bool screensChanged=false;
@@ -1900,5 +2232,6 @@ void Client::reinitCaches()
delete currentCursor;
currentFrame=0;
currentCursor=0;
- displayArea->repaint(0, 0, displayArea->width(), displayArea->height());
+ if(!rootless)
+ displayArea->repaint(0, 0, displayArea->width(), displayArea->height());
}
diff --git a/client.h b/client.h
index 344eaf7..9e98cc0 100644
--- a/client.h
+++ b/client.h
@@ -61,6 +61,7 @@ enum OS_VERSION{OS_LINUX, OS_WINDOWS, OS_DARWIN};
//This event only sent by web client at the moment
#define KEEPALIVE 12
#define CACHEREBUILD 13
+#define WINCHANGE 14
#define ShiftMask (1<<0)
#define LockMask (1<<1)
@@ -84,7 +85,9 @@ enum SelectionMime{STRING,UTF_STRING,PIXMAP};
enum SelectionType{PRIMARY,CLIPBOARD};
enum ClipboardMode{CLIP_BOTH, CLIP_SERVER, CLIP_CLIENT, CLIP_NONE};
-
+enum WinType{WINDOW_TYPE_DESKTOP, WINDOW_TYPE_DOCK, WINDOW_TYPE_TOOLBAR, WINDOW_TYPE_MENU, WINDOW_TYPE_UTILITY, WINDOW_TYPE_SPLASH,
+ WINDOW_TYPE_DIALOG, WINDOW_TYPE_DROPDOWN_MENU, WINDOW_TYPE_POPUP_MENU, WINDOW_TYPE_TOOLTIP, WINDOW_TYPE_NOTIFICATION,
+ WINDOW_TYPE_COMBO, WINDOW_TYPE_DND, WINDOW_TYPE_NORMAL};
#include <QMainWindow>
#include <QAbstractSocket>
@@ -100,11 +103,13 @@ class XCBClip;
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
-#define KDR_ENDL Qt::endl
+#define KDR_ENDL Qt::endl>>Qt::dec
#define KDR_HEX Qt::hex
+#define KDR_DEC Qt::dec
#else
-#define KDR_ENDL endl
+#define KDR_ENDL endl>>dec
#define KDR_HEX hex
+#define KDR_DEC dec
#endif
@@ -122,9 +127,9 @@ public:
class Frame
{
public:
- Frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t numOfRegions, uint32_t crc);
+ Frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t numOfRegions, uint32_t crc, uint32_t winId);
~Frame();
- uint32_t width, height, crc, numOfRegions;
+ uint32_t width, height, crc, numOfRegions, winId;
int32_t x, y;
QVector<FrameRegion*> regions;
};
@@ -163,6 +168,7 @@ class QMenu;
class QAction;
class QLabel;
class ScreenIdentifier;
+class ExtWin;
class Client : public QMainWindow
{
@@ -176,6 +182,7 @@ public:
void setUptodate();
QPixmap getPixmapFromCache(uint32_t crc);
QPixmap addPixmapToCache();
+ QPixmap getDisplayPix(){return displayPix;}
bool isDisplayPointer(QMouseEvent* event);
void addToSelectionOutput(OutputChunk* chunk);
bool serverSupportsExtSelection(){return serverExtSelection;}
@@ -187,9 +194,16 @@ public:
static QTextStream& KDRStdErr(bool dbg=true);
static QString QRectToStr(const QRect& rec);
static QString QSizeToStr(const QSizeF& sz);
+ void changeWindow(ExtWin* win);
+ bool isRootless(){return rootless;}
+ const QList<ExtWin*> getExtWindows(){return extWindows;}
+ const QList<ExtWin*> getSiblings(ExtWin* win);
+ ExtWin* findExtWinById(uint32_t extWinId);
public slots:
void sendOutputSelChunk();
+ void slotGrabDisplay();
+
private slots:
@@ -224,8 +238,8 @@ public slots:
private:
- enum{ HEADER, FRAMEREGION, REGIONDATA ,CURSORDATA, CURSORLIST, FRAMELIST, SELECTIONBUFFER } currentDataType;
- enum HeaderType{ FRAME, DELETEDFRAMES, CURSOR, DELETEDCURSORS, SELECTION, SERVER_VERSION, DEMANDCLIENTSELECTION,REINIT};
+ enum{ HEADER, FRAMEREGION, REGIONDATA ,CURSORDATA, CURSORLIST, FRAMELIST, SELECTIONBUFFER, WINUPDATEBUFFER } currentDataType;
+ enum HeaderType{ FRAME, DELETEDFRAMES, CURSOR, DELETEDCURSORS, SELECTION, SERVER_VERSION, DEMANDCLIENTSELECTION,REINIT,WINUPDATE};
void getServerversion();
void getClientSelection();
@@ -243,6 +257,8 @@ private:
void getDeletedCursorsList();
void getSelection();
void getSelectionBuffer();
+ void getWinUpdate();
+ void getWinUpdateBuffer();
void renderFrame();
void freeMessageBuffer();
void setCursor();
@@ -250,16 +266,24 @@ private:
void setFS(int screenNumber);
void reinitCaches();
void initGeometry();
+ void setDisplayPix(QPixmap pix, int32_t x=-1, int32_t y=-1);
bool wantRepaint=false;
+ bool hasUpdates=false;
#ifndef Q_OS_LINUX
void sendSelectionToServer(SelectionType selection);
void setInputSelectionData(SelectionType selection, SelectionMime mime, bool firstChunk, bool lastChunk, uint32_t compressed, uint size, char* data, bool notify=false);
#endif
+ void parseOptions();
+ void initDesktopMode();
+ ExtWin* getExtWin(uint32_t id);
static bool debug;
//initial values
int width=800;
int height=600;
+ QString host="localhost";
+ int port=15000;
+
//feature version of server
quint16 serverVersion=0;
@@ -268,8 +292,11 @@ private:
bool multidisp=false;
int dispNumber=1;
bool serverExtSelection=false;
+ bool rootless=false;
QString cookie;
+ QString mainWndTitle;
+
MenuFrame *FSMenuBar;
QMenu* menu;
@@ -320,10 +347,12 @@ private:
uint32_t deletedFramesSize=0;
uint32_t deletedCursorsSize=0;
+ int winUpdateSize=0;
QHash <uint32_t, QPixmap> frameCache;
QHash <uint32_t, QCursor*> cursorCache;
QList <OutputChunk*> outputSelectionQueue;
+ QList <ExtWin*> extWindows;
int frameCount=0;
@@ -336,6 +365,7 @@ private:
int cacheSize=0;
ScreenIdentifier *screenIdentifier=0l;
QLabel* fr;
+ QPixmap displayPix;
//selection
#ifdef Q_OS_LINUX
diff --git a/displayarea.cpp b/displayarea.cpp
index c4622e7..de09197 100644
--- a/displayarea.cpp
+++ b/displayarea.cpp
@@ -18,6 +18,7 @@
*
*/
#include "displayarea.h"
+#include "extwin.h"
#include <QPainter>
#include <QPaintEvent>
#include <QMouseEvent>
@@ -77,21 +78,19 @@ LRESULT CALLBACK LowLevelKeyboardProc(
memcpy(evmsg,(char*)&etype,4);
memcpy(evmsg+4,(char*)&mods,4);
memcpy(evmsg+8,(char*)&key,4);
- display->parent->sendEvent(evmsg);
+ display->client->sendEvent(evmsg);
return -1;
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
#endif
-DisplayArea::DisplayArea(Client* parent):QFrame(parent)
+DisplayArea::DisplayArea(Client* client, QWidget* parentWidget):QFrame(parentWidget)
{
- this->parent=parent;
+ this->client=client;
+ this->parentWidget=parentWidget;
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
- QTimer *tm=new QTimer(this);
- connect(tm, &QTimer::timeout, this, &DisplayArea::slotGrabDisplay);
- tm->start(1000);
grabKeyboard();
}
@@ -117,90 +116,95 @@ DisplayArea::~DisplayArea()
{
}
-void DisplayArea::slotGrabDisplay()
-{
- if(hasUpdates)
- {
-// Client::KDRStdErr()<<"save display";
- QScreen *screen = QGuiApplication::primaryScreen();
- displayPix = screen->grabWindow(winId());
- hasUpdates=false;
- }
-}
-
-
-void DisplayArea::setDisplayPix(QPixmap pix, int32_t x, int32_t y)
-{
- if(x==-1 || y==-1)
- {
- displayPix=pix;
- }
- else
- {
- QPainter pt;
- pt.begin(&displayPix);
- pt.drawPixmap(x,y,pix);
- pt.end();
- }
-}
-
-
-
void DisplayArea::paintEvent(QPaintEvent* ev)
{
-// Client::KDRStdErr()<<"paint event:"<<ev->rect();
QPainter painter;
- if(! displayPix.isNull())
+ bool disp=false;
+ if(! client->getDisplayPix().isNull())
{
painter.begin(this);
- if(parent->needUpdate())
+ if(client->needUpdate())
{
- Frame* currentFrame=parent->getCurrentFrame();
+ Frame* currentFrame=client->getCurrentFrame();
QPixmap pix;
if(!currentFrame->crc)
{
- pix=displayPix;
+// Client::KDRStdErr()<<"Draw DISPLAY PIX "<<KDR_ENDL;
+ pix=client->getDisplayPix();
+ disp=true;
}
else
{
- pix=parent->getPixmapFromCache(currentFrame->crc);
+// Client::KDRStdErr()<<"Draw PIX from cache"<<KDR_ENDL;
+ pix=client->getPixmapFromCache(currentFrame->crc);
}
if(currentFrame->x==-1 || currentFrame->y==-1)
{
currentFrame->x=currentFrame->y=0;
}
- painter.drawPixmap(currentFrame->x,currentFrame->y,pix);
- parent->setUptodate();
- hasUpdates=true;
+ if(!client->isRootless())
+ {
+ if(!disp)
+ painter.drawPixmap(currentFrame->x,currentFrame->y,pix);
+ else
+ painter.drawPixmap(currentFrame->x,currentFrame->y,pix,currentFrame->x,currentFrame->y,currentFrame->width,currentFrame->height);
+ }
+ else
+ {
+ if(!disp)
+ {
+ painter.drawPixmap(currentFrame->x-((ExtWin*)parentWidget)->adjustGeometry().x(),currentFrame->y-((ExtWin*)parentWidget)->adjustGeometry().y(),pix);
+ }
+ else
+ painter.drawPixmap(currentFrame->x-((ExtWin*)parentWidget)->adjustGeometry().x(),currentFrame->y-((ExtWin*)parentWidget)->adjustGeometry().y(),pix,
+ currentFrame->x,currentFrame->y,ev->rect().width(),ev->rect().height());
+ }
}
else
{
- painter.drawPixmap(ev->rect(),displayPix,ev->rect());
-
+// Client::KDRStdErr()<<"Win update event: "<<KDR_HEX<<((ExtWin*)parentWidget)->getPtr()<< " "<<Client::QRectToStr(ev->rect()) <<KDR_ENDL;
char evmsg[EVLENGTH]={};
int32_t etype, x, y, width, height;
etype=UPDATE;
+ width=ev->rect().width();
+ height=ev->rect().height();
- width=ev->rect().width()+ev->rect().x();
- height=ev->rect().height()+ev->rect().y();
- x=0;
- y=0;
-
-
+ if(!client->isRootless())
+ {
+ x=ev->rect().x();
+ y=ev->rect().y();
+ painter.drawPixmap(ev->rect(),client->getDisplayPix(),ev->rect());
+ }
+ else
+ {
+ x=((ExtWin*)parentWidget)->adjustGeometry().x()+ev->rect().x();
+ y=((ExtWin*)parentWidget)->adjustGeometry().y()+ev->rect().y();
+// painter.drawPixmap(0,0,client->getDisplayPix(),((ExtWin*)parentWidget)->adjustGeometry().x(),((ExtWin*)parentWidget)->adjustGeometry().y(),ev->rect().width(),ev->rect().height());
+
+ #warning check this later
+ //this is making the window to flicker a bit, but it's the best I can do at the moment. We should try to get the displaypix not from the main image in
+ //x2gokdrive, but maybe directly from the window drawable to get the image not covered by windows on top and save it for every window separately
+ painter.drawPixmap(ev->rect().x(),ev->rect().y(), ev->rect().width(), ev->rect().height(),
+ client->getDisplayPix(), ev->rect().x()+((ExtWin*)parentWidget)->adjustGeometry().x(),
+ ev->rect().y()+((ExtWin*)parentWidget)->adjustGeometry().y(), ev->rect().width(), ev->rect().height());
+ }
+// Client::KDRStdErr()<<"Request update:"<<KDR_HEX<<((ExtWin*)parentWidget)->getExtWinId() <<KDR_DEC<<" "<<x<<":"<<y<<" - "<<width<<"x"<<height<<KDR_ENDL<<"====================="<<KDR_ENDL;
memcpy(evmsg,(char*)&etype,4);
memcpy(evmsg+4,(char*)&width,4);
memcpy(evmsg+8,(char*)&height,4);
memcpy(evmsg+12,(char*)&x,4);
memcpy(evmsg+16,(char*)&y,4);
-
- parent->sendEvent(evmsg);
-
-
+ if(client->isRootless())
+ {
+ uint32_t win_id=(((ExtWin*)parentWidget)->getExtWinId());
+ memcpy(evmsg+20,(char*)&win_id,4);
+ }
+ client->sendEvent(evmsg);
}
painter.end();
}
else
- Client::KDRStdErr()<<"DISPLAY PIX IS NULL";
+ Client::KDRStdErr()<<"DISPLAY PIX IS NULL"<<KDR_ENDL;
}
uint32_t DisplayArea::X11MouseButtonsState(Qt::MouseButtons qtMouseButtons)
@@ -237,7 +241,7 @@ uint32_t DisplayArea::X11MouseButton(Qt::MouseButton qtMouseButton)
void DisplayArea::mouseMoveEvent(QMouseEvent* event)
{
- if(!parent->isDisplayPointer(event))
+ if(!client->isDisplayPointer(event))
return;
char evmsg[EVLENGTH]={};
uint32_t etype, x, y;
@@ -245,14 +249,22 @@ void DisplayArea::mouseMoveEvent(QMouseEvent* event)
// Client::KDRStdErr()<<"kbd mods"<<event->modifiers();
- x=event->x();
- y=event->y();
+ if(!client->isRootless())
+ {
+ x=event->x();
+ y=event->y();
+ }
+ else
+ {
+ x=event->x()+parentWidget->geometry().x();
+ y=event->y()+parentWidget->geometry().y();
+ }
memcpy(evmsg,(char*)&etype,4);
memcpy(evmsg+4,(char*)&x,4);
memcpy(evmsg+8,(char*)&y,4);
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
// Client::KDRStdErr()<<"mouse move"<<event->x()<<event->y();
@@ -272,7 +284,7 @@ void DisplayArea::mousePressEvent(QMouseEvent* event)
memcpy(evmsg+4,(char*)&state,4);
memcpy(evmsg+8,(char*)&button,4);
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
// Client::KDRStdErr()<<"mouse press"<<event->button()<<event->buttons()<<button<<state;
}
@@ -291,7 +303,7 @@ void DisplayArea::mouseReleaseEvent(QMouseEvent* event)
memcpy(evmsg+4,(char*)&state,4);
memcpy(evmsg+8,(char*)&button,4);
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
// Client::KDRStdErr()<<"mouse release"<<event->button()<<event->buttons()<<button<<state;
}
@@ -320,7 +332,7 @@ void DisplayArea::wheelEvent(QWheelEvent* event)
memcpy(evmsg+8,(char*)&button,4);
// Client::KDRStdErr()<<etype<<state<<button;
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
etype=MOUSERELEASE;
state=X11MouseButtonsState(event->buttons());
@@ -341,7 +353,7 @@ void DisplayArea::wheelEvent(QWheelEvent* event)
memcpy(evmsg+8,(char*)&button,4);
// Client::KDRStdErr()<<etype<<state<<button;
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
}
/*
@@ -390,7 +402,7 @@ void DisplayArea::keyPressEvent(QKeyEvent* event)
memcpy(evmsg,(char*)&etype,4);
memcpy(evmsg+4,(char*)&state,4);
memcpy(evmsg+8,(char*)&key,4);
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
}
void DisplayArea::keyReleaseEvent(QKeyEvent* event)
@@ -414,7 +426,7 @@ void DisplayArea::keyReleaseEvent(QKeyEvent* event)
memcpy(evmsg+4,(char*)&state,4);
memcpy(evmsg+8,(char*)&key,4);
- parent->sendEvent(evmsg);
+ client->sendEvent(evmsg);
}
uint32_t DisplayArea::qtModifiers2pc105(Qt::KeyboardModifiers qtModifiers)
diff --git a/displayarea.h b/displayarea.h
index 337689c..e32bc9b 100644
--- a/displayarea.h
+++ b/displayarea.h
@@ -36,17 +36,12 @@ class DisplayArea : public QFrame
#endif
Q_OBJECT
public:
- DisplayArea(Client* parent);
+ DisplayArea(Client* client, QWidget* parentWidget);
~DisplayArea();
- void setDisplayPix(QPixmap pix, int32_t x=-1, int32_t y=-1);
private:
QPainter* painter=0l;
- Client* parent;
- QPixmap displayPix;
- bool hasUpdates=false;
-
-public slots:
- void slotGrabDisplay();
+ Client* client;
+ QWidget* parentWidget;
protected:
void paintEvent(QPaintEvent *);
diff --git a/extwin.cpp b/extwin.cpp
new file mode 100644
index 0000000..354e212
--- /dev/null
+++ b/extwin.cpp
@@ -0,0 +1,332 @@
+/*
+ * QT Client for X2GoKDrive
+ * Copyright (C) 2018 Oleksandr Shneyder <o.shneyder at phoca-gmbh.de>
+ * Copyright (C) 2018 phoca-GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "extwin.h"
+#include "displayarea.h"
+#include "client.h"
+#include <QApplication>
+#include <QTimer>
+ExtWin::ExtWin(uint32_t extWinId, Client *client, QWidget* parent, Qt::WindowFlags flags): QMainWindow(parent, flags)
+{
+ displayArea=new DisplayArea((Client*)client,this);
+ displayArea->setObjectName("DisplayArea");
+ displayArea->setStyleSheet("QFrame#DisplayArea{background-color:black;}");
+ displayArea->show();
+ setCentralWidget(displayArea);
+ setWindowIcon(QIcon(":res/x2goclient.png"));
+ this->extWinId=extWinId;
+ this->client=client;
+ setFocusPolicy(Qt::StrongFocus);
+// QTimer::singleShot(10,this,SLOT(update()));
+ switch(windowType)
+ {
+ case WINDOW_TYPE_DROPDOWN_MENU:
+ setAttribute(Qt::WA_X11NetWmWindowTypeDropDownMenu);
+ break;
+ case WINDOW_TYPE_POPUP_MENU:
+ setAttribute(Qt::WA_X11NetWmWindowTypePopupMenu);
+ break;
+ case WINDOW_TYPE_DIALOG:
+ setAttribute(Qt::WA_X11NetWmWindowTypeDialog);
+ break;
+ case WINDOW_TYPE_TOOLTIP:
+ setAttribute(Qt::WA_X11NetWmWindowTypeToolTip);
+ break;
+ }
+}
+
+void ExtWin::setWinSize(int w, int h)
+{
+ displayArea->resize(w,h);
+}
+
+void ExtWin::moveEvent(QMoveEvent* ev)
+{
+ if((windowType != WINDOW_TYPE_DROPDOWN_MENU)&&(windowType != WINDOW_TYPE_POPUP_MENU))
+ {
+ Client::KDRStdErr()<<"Move "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ client->changeWindow(this);
+ }
+ QMainWindow::moveEvent(ev);
+}
+
+
+void ExtWin::resizeEvent(QResizeEvent* ev)
+{
+ if((windowType != WINDOW_TYPE_DROPDOWN_MENU)&&(windowType != WINDOW_TYPE_POPUP_MENU))
+ {
+ Client::KDRStdErr()<<"Resize "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ client->changeWindow(this);
+ }
+ QMainWindow::resizeEvent(ev);
+}
+
+void ExtWin::showEvent(QShowEvent *ev)
+{
+ Client::KDRStdErr()<<"Show "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ QMainWindow::showEvent(ev);
+}
+
+void ExtWin::hideEvent(QHideEvent *ev)
+{
+ Client::KDRStdErr()<<"Hide "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ QMainWindow::hideEvent(ev);
+}
+
+void ExtWin::focusInEvent(QFocusEvent *ev)
+{
+ Client::KDRStdErr()<<"Focus In "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ QMainWindow::focusInEvent(ev);
+}
+
+void ExtWin::focusOutEvent(QFocusEvent *ev)
+{
+ Client::KDRStdErr()<<"Focus Out "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ QMainWindow::focusOutEvent(ev);
+}
+
+xcb_window_t getRootNativeId(xcb_window_t winId)
+{
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ xcb_window_t root_id=0;
+ xcb_connection_t *connection = QX11Info::connection();
+ cookie = xcb_query_tree(connection, winId);
+ if ((reply = xcb_query_tree_reply(connection, cookie, NULL)))
+ {
+ root_id=reply->root;
+ free(reply);
+ }
+ return root_id;
+}
+
+xcb_window_t getParentNativeId(xcb_window_t winId)
+{
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ xcb_window_t parent_id=0;
+ xcb_connection_t *connection = QX11Info::connection();
+ cookie = xcb_query_tree(connection, winId);
+ if ((reply = xcb_query_tree_reply(connection, cookie, NULL)))
+ {
+ parent_id=reply->parent;
+ free(reply);
+ }
+ return parent_id;
+}
+
+xcb_window_t getCommonParent(xcb_window_t win1, xcb_window_t win2)
+{
+ QList<xcb_window_t> win1_preds;
+ xcb_window_t root=getRootNativeId(win1);
+ xcb_window_t w_next_pred=getParentNativeId(win1);
+ while(w_next_pred!=0)
+ {
+ win1_preds<<w_next_pred;
+ if(w_next_pred==root)
+ break;
+ w_next_pred=getParentNativeId(w_next_pred);
+ }
+ //now we have all preds of w1
+ w_next_pred=getParentNativeId(win2);
+ while(w_next_pred!=0)
+ {
+ if(win1_preds.indexOf(w_next_pred)!=-1)
+ {
+ return w_next_pred;
+ }
+ w_next_pred=getParentNativeId(w_next_pred);
+ }
+ return 0;
+}
+
+xcb_window_t getTopWinId(xcb_window_t myId, xcb_window_t commonParentId)
+{
+ xcb_window_t parent_id=getParentNativeId(myId);
+ while(parent_id!=commonParentId)
+ {
+ myId=parent_id;
+ parent_id=getParentNativeId(myId);
+ }
+ return myId;
+}
+
+ExtWin* ExtWin::findWinByTopWinId(xcb_window_t topWinId, QList<ExtWin*> &siblings)
+{
+ for(int i=0; i< siblings.count(); ++i)
+ {
+ if(siblings[i]->topWinId==topWinId)
+ {
+ return siblings[i];
+ }
+ }
+ return 0;
+}
+
+ExtWin* ExtWin::findWinByZInd(int zInd, QList<ExtWin*> &siblings)
+{
+ for(int i=0; i< siblings.count(); ++i)
+ {
+ if(siblings[i]->zOrderInd==zInd)
+ {
+ return siblings[i];
+ }
+ }
+ return 0;
+}
+
+QRect ExtWin::adjustGeometry()
+{
+ return geometry();
+ /*
+ if(transWinId)
+ {
+ ExtWin* trwin=client->findExtWinById(transWinId);
+ if(!trwin)
+ {
+ Client::KDRStdErr()<<"Error finding trans window "<<transWinId<<KDR_ENDL;
+ return geometry();
+ }
+ QRect trGeom=trwin->adjustGeometry();
+ QRect geom=geometry();
+ return QRect(trGeom.x()+geom.x(), trGeom.y()+geom.y(),geom.width(),geom.height());
+ }
+ return geometry();*/
+}
+
+void ExtWin::slotCheckStackOrder()
+{
+ QList<ExtWin*> siblings=client->getSiblings(this);
+ // Client::KDRStdErr()<<"Have Siblings: "<<siblings.count()<<KDR_ENDL;
+ if(siblings.count())
+ {
+ xcb_window_t commonParent=getCommonParent(this->winId(), siblings[0]->winId());
+ // Client::KDRStdErr()<<"common parent: "<<KDR_HEX<<commonParent<<KDR_ENDL;
+ siblings<<this;
+ xcb_connection_t *connection = QX11Info::connection();
+ xcb_query_tree_cookie_t cookie;
+ xcb_query_tree_reply_t *reply;
+ for(int i=0;i<siblings.count();++i)
+ siblings[i]->topWinId=getTopWinId(siblings[i]->winId(),commonParent);
+ cookie = xcb_query_tree(connection, commonParent);
+ if ((reply = xcb_query_tree_reply(connection, cookie, NULL)))
+ {
+ xcb_window_t *children = xcb_query_tree_children(reply);
+ int z=0;
+ // Client::KDRStdErr()<<"Current stack for parent: "<<KDR_ENDL;
+ for (int i = 0; i < xcb_query_tree_children_length(reply); i++)
+ {
+ ExtWin* win=findWinByTopWinId(children[i], siblings);
+ if(win)
+ {
+ win->zOrderInd=z++;
+ // Client::KDRStdErr()<<win->zOrderInd<<" - "<<KDR_HEX<< win->extWinId<<" "<<win->windowTitle()<<"->";
+ }
+ }
+ free(reply);
+ // Client::KDRStdErr()<<"End of stack "<<KDR_ENDL;
+ uint32_t newNextSib;
+ if(zOrderInd==0)
+ {
+ newNextSib=0;
+ }
+ else
+ {
+ ExtWin* win=findWinByZInd(zOrderInd-1, siblings);
+ if(!win)
+ {
+ Client::KDRStdErr()<<"Error finding window with z-order "<<zOrderInd-1<<KDR_ENDL;
+ return ;
+ }
+ newNextSib=win->extWinId;
+ }
+ if(nextSibId != newNextSib)
+ {
+ //if some modal windows are not ordered correct, fix it and try again
+ if(!checkModality(siblings))
+ {
+ QTimer::singleShot(5,this,SLOT(slotCheckStackOrder()));
+ return ;
+ }
+ Client::KDRStdErr()<<"Need to restack "<<KDR_HEX<<extWinId<<" Above "<<newNextSib<<KDR_ENDL;
+ nextSibId=newNextSib;
+ client->changeWindow(this);
+ }
+ /*else
+ * {
+ * Client::KDRStdErr()<<"Stack order is ok"<<KDR_ENDL;
+ }*/
+ }
+ }
+}
+
+bool ExtWin::checkModality(QList<ExtWin*> &siblings)
+{
+ bool mod_res=true;
+
+ for(int i=0;i<siblings.count();++i)
+ {
+ ExtWin* w=siblings[i];
+ if(w->modality==MOD_SINGLE)
+ {
+ if(w->transWinId)
+ {
+ ExtWin* trwin=client->findExtWinById(w->transWinId);
+ if(!trwin)
+ {
+ Client::KDRStdErr()<<"Error finding trans window "<<w->transWinId<<KDR_ENDL;
+ }
+ else
+ {
+ if(trwin->zOrderInd > w->zOrderInd)
+ {
+ Client::KDRStdErr()<<"Transwin "<<KDR_HEX<<w->transWinId<< " on top of modal win "<<w->extWinId<<KDR_ENDL;
+// QTimer::singleShot(1,trwin,SLOT(update()));
+// QTimer::singleShot(2,w,SLOT(update()));
+// trwin->update();
+ w->raise();
+ mod_res=false;
+ }
+ }
+ }
+ }
+ }
+
+ return mod_res;
+}
+
+bool ExtWin::nativeEvent(const QByteArray &eventType, void *message, long *result)
+{
+
+/* if((windowType == WINDOW_TYPE_DROPDOWN_MENU)||(windowType == WINDOW_TYPE_POPUP_MENU))
+ {
+ return QMainWindow::nativeEvent(eventType, message, result);
+ }*/
+ if(!eventType.compare("xcb_generic_event_t") && parentId==0)
+ {
+ slotCheckStackOrder();
+ /* xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
+
+ Client::KDRStdErr()<<"XCB EV "<<(ev->response_type & ~0x80) <<" "<<Client::QRectToStr(geometry())<<KDR_ENDL;
+ return QMainWindow::nativeEvent(eventType, message, result);*/
+
+// Client::KDRStdErr()<<"Check win: "<<KDR_HEX<<extWinPtr<<KDR_ENDL;
+ }
+ return QMainWindow::nativeEvent(eventType, message, result);
+}
diff --git a/extwin.h b/extwin.h
new file mode 100644
index 0000000..b9fad18
--- /dev/null
+++ b/extwin.h
@@ -0,0 +1,80 @@
+/*
+ * QT Client for X2GoKDrive
+ * Copyright (C) 2018 Oleksandr Shneyder <o.shneyder at phoca-gmbh.de>
+ * Copyright (C) 2018 phoca-GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef EXTWIN_H
+#define EXTWIN_H
+
+#include <QMainWindow>
+#ifdef Q_OS_LINUX
+#include <QX11Info>
+#else
+#warning add code for WIN EVENTS
+#endif
+
+#include "client.h"
+
+class DisplayArea;
+class Client;
+class ExtWin : public QMainWindow
+{
+ Q_OBJECT
+public:
+ enum {MOD_NONE,MOD_SINGLE, MOD_GROUP};
+ ExtWin(uint32_t extWinId, Client *client, QWidget* parent, Qt::WindowFlags flags = Qt::WindowFlags());
+ uint32_t getPtr(){return extWinId;}
+ void setWinSize(int w, int h);
+ void setParentId(uint32_t id){parentId=id;}
+ void setTransWinId(uint32_t id){transWinId=id;}
+ void setNextSibId(uint32_t id){nextSibId=id;}
+ void setWindowType(uint8_t tp){windowType=tp;}
+ uint64_t getParentId(){return parentId;}
+ uint64_t getNextSibId(){return nextSibId;}
+ uint64_t getExtWinId(){return extWinId;}
+ DisplayArea* getDisplayArea(){return displayArea;}
+ void setModality(int mod){modality=mod;}
+ QRect adjustGeometry();
+
+private:
+ ExtWin* findWinByTopWinId(xcb_window_t topWinId, QList<ExtWin*> &siblings);
+ ExtWin* findWinByZInd(int zInd, QList<ExtWin*> &siblings);
+ bool checkModality(QList<ExtWin*> &siblings);
+ DisplayArea* displayArea;
+ Client* client;
+ uint32_t extWinId;
+ uint32_t parentId=0;
+ uint32_t nextSibId=0;
+ uint32_t transWinId=0;
+ uint8_t windowType=WINDOW_TYPE_NORMAL;
+ xcb_window_t topWinId=0;
+ int zOrderInd;
+ int modality=MOD_NONE;
+
+private slots:
+ void slotCheckStackOrder();
+
+protected:
+ void resizeEvent(QResizeEvent*);
+ void moveEvent(QMoveEvent*);
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ bool nativeEvent(const QByteArray &eventType, void *message, long *result);
+};
+#endif //EXTWIN_H
diff --git a/menuframe.cpp b/menuframe.cpp
index a15b0a9..576185d 100644
--- a/menuframe.cpp
+++ b/menuframe.cpp
@@ -305,13 +305,13 @@ void MenuFrame::setCaption(const QString& text)
{
case TOP:
case BOTTOM:
- setMinimumWidth(defaultSpacing*4+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4);
- setMaximumWidth(defaultSpacing*4+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4);
+ setMinimumWidth(defaultSpacing*4+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4+4);
+ setMaximumWidth(defaultSpacing*4+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4+4);
break;
case LEFT:
case RIGHT:
- setMinimumHeight(defaultSpacing*5+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4);
- setMaximumHeight(defaultSpacing*5+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4);
+ setMinimumHeight(defaultSpacing*5+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4+4);
+ setMaximumHeight(defaultSpacing*5+defaultMargin*2+capt->sizeHint().width()+bPin->sizeHint().width()*4+4);
break;
}
diff --git a/x2gokdriveclient.pro b/x2gokdriveclient.pro
index e106f41..903bf63 100644
--- a/x2gokdriveclient.pro
+++ b/x2gokdriveclient.pro
@@ -20,8 +20,8 @@ RESOURCES += resources.qrc
# Input
-SOURCES += main.cpp client.cpp displayarea.cpp menuframe.cpp screenidentifier.cpp
-HEADERS += client.h displayarea.h menuframe.h screenidentifier.h
+SOURCES += main.cpp client.cpp displayarea.cpp menuframe.cpp screenidentifier.cpp extwin.cpp
+HEADERS += client.h displayarea.h menuframe.h screenidentifier.h extwin.h
linux {
SOURCES += xcbclip.cpp
--
Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdriveclient.git
More information about the x2go-commits
mailing list