aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp')
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp474
1 files changed, 474 insertions, 0 deletions
diff --git a/src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp b/src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp
new file mode 100644
index 00000000..84ff2ffd
--- /dev/null
+++ b/src-qt5/core/lumina-desktop-unified/src-WM/LWindow.cpp
@@ -0,0 +1,474 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LWindow.h"
+
+LWindowFrame::LWindowFrame(WId client, QWidget *parent) : QFrame(parent, Qt::X11BypassWindowManagerHint){
+ activeState = LWindowFrame::Normal;
+ CID = client;
+ lastAction = LWM::WA_NONE;
+ Closing = false;
+ //qDebug() << "New Window:" << CID << "Frame:" << this->winId();
+ this->setMouseTracking(true); //need this to determine mouse location when not clicked
+ this->setObjectName("LWindowFrame");
+ this->setStyleSheet("LWindowFrame#LWindowFrame{ border: 2px solid white; border-radius:3px; } QWidget#TitleBar{background: grey; } QLabel{ color: black; }");
+ InitWindow(); //initially create all the child widgets
+ //LWM::SYSTEM->setupEventsForFrame(this->winId());
+ updateAppearance(); //this loads the appearance based on window/theme settings
+ //QApplication::processEvents();
+ //Now set the frame size on this window
+ SyncSize();
+ SyncText();
+ this->show();
+}
+
+LWindowFrame::~LWindowFrame(){
+}
+
+// =================
+// PRIVATE
+// =================
+void LWindowFrame::InitWindow(){
+ anim = new QPropertyAnimation(this); //For simple window animations
+ anim->setTargetObject(this);
+ anim->setDuration(ANIMTIME); //In milliseconds
+ connect(anim, SIGNAL(finished()), this, SLOT(finishedAnimation()) );
+ titleBar = new QLabel(this); //This is the "container" for all the title buttons/widgets
+ titleBar->setObjectName("TitleBar");
+ titleBar->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
+ titleBar->setFocusPolicy(Qt::NoFocus);
+ titleBar->setCursor(Qt::ArrowCursor);
+ title = new QLabel(this); //Shows the window title/text
+ title->setObjectName("Title");
+ title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ title->setCursor(Qt::ArrowCursor);
+ title->setFocusPolicy(Qt::NoFocus);
+ icon = new QLabel(this); //Contains the window icon
+ icon->setObjectName("Icon");
+ icon->setCursor(Qt::ArrowCursor);
+ icon->setFocusPolicy(Qt::NoFocus);
+ minB = new QToolButton(this); //Minimize Button
+ minB->setObjectName("Minimize");
+ minB->setCursor(Qt::ArrowCursor);
+ minB->setFocusPolicy(Qt::NoFocus);
+ connect(minB, SIGNAL(clicked()), this, SLOT(minClicked()) );
+ maxB = new QToolButton(this); //Maximize Button
+ maxB->setObjectName("Maximize");
+ maxB->setCursor(Qt::ArrowCursor);
+ maxB->setFocusPolicy(Qt::NoFocus);
+ connect(maxB, SIGNAL(clicked()), this, SLOT(maxClicked()) );
+ closeB = new QToolButton(this);
+ closeB->setObjectName("Close");
+ closeB->setCursor(Qt::ArrowCursor);
+ closeB->setFocusPolicy(Qt::NoFocus);
+ connect(closeB, SIGNAL(clicked()), this, SLOT(closeClicked()) );
+ otherB = new QToolButton(this); //Button to place any other actions
+ otherB->setObjectName("Options");
+ otherB->setCursor(Qt::ArrowCursor);
+ otherB->setPopupMode(QToolButton::InstantPopup);
+ otherB->setStyleSheet("QToolButton::menu-indicator{ image: none; }");
+ otherB->setFocusPolicy(Qt::NoFocus);
+ otherM = new QMenu(this); //menu of "other" actions for the window
+ otherB->setMenu(otherM);
+ connect(otherM, SIGNAL(triggered(QAction*)), this, SLOT(otherClicked(QAction*)) );
+ //Now assemble the titlebar
+ QHBoxLayout *HL = new QHBoxLayout(this);
+ HL->setContentsMargins(0,0,0,0);
+ HL->addWidget(otherB);
+ HL->addWidget(icon);
+ HL->addWidget(title);
+ HL->addWidget(minB);
+ HL->addWidget(maxB);
+ HL->addWidget(closeB);
+ titleBar->setLayout(HL);
+ QVBoxLayout *VL = new QVBoxLayout(this);
+ this->setLayout(VL);
+ //The WinWidget container appears shifted right/down by 1 pixel for some reason
+ // Adjust the margins to account for this variation
+ VL->setContentsMargins(1,1,2,2);
+ VL->setSpacing(0);
+ //Have the window take the same initial size of the client window
+ QRect geom = LWM::SYSTEM->WM_Window_Geom(CID);
+ qDebug() << " - Load Size Hints" << "initial size:" << geom.size();
+ icccm_size_hints SH = LWM::SYSTEM->WM_ICCCM_GetNormalHints(CID);
+ qDebug() << " - - Got Normal Hints";
+ if(!SH.isValid()){ SH = LWM::SYSTEM->WM_ICCCM_GetSizeHints(CID); }
+ qDebug() << " - - Start resizing...";
+ if(SH.base_width>geom.width() && SH.base_height>geom.height()){ this->resize(SH.base_width, SH.base_height); }
+ else if(SH.min_width>geom.width() && SH.min_height>geom.height()){ this->resize(SH.min_width, SH.min_height); }
+ else if(SH.width>geom.width() && SH.height>geom.height()){ this->resize(SH.width, SH.height); }
+ else if(geom.isNull()){ this->resize(100,80); }
+ else{ this->resize( geom.size() ); }
+ qDebug() << " - done";
+
+ //Now embed the native window into the frame
+ WIN = QWindow::fromWinId(CID);
+ WinWidget = QWidget::createWindowContainer( WIN, this);
+ WinWidget->setCursor(Qt::ArrowCursor); //this is just a fallback - the window itself will adjust it
+ //WINBACK = new QBackingStore(WIN); //create a data backup for the widget
+
+ //Now assemble te initial layout for the window (all while still invisible)
+ /*VL->addWidget(titleBar);
+ VL->addWidget(WinWidget);
+ VL->setStretch(1,1);*/
+}
+
+LWindowFrame::ModState LWindowFrame::getStateAtPoint(QPoint pt, bool setoffset){
+ //Note: pt should be in widget-relative coordinates, not global
+ if(!this->layout()->geometry().contains(pt)){
+ //above the frame itself - need to figure out which quadrant it is in (8-directions)
+ if(pt.y() < 3){
+ //One of the top options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()); } //difference from top-left corner
+ return ResizeTopLeft;
+ }else if(pt.x() > (this->width()-3)){
+ if(setoffset){ offset.setX(this->width()-pt.x()); offset.setY(pt.y()); } //difference from top-right corner
+ return ResizeTopRight;
+ }else{
+ if(setoffset){ offset.setX(0); offset.setY(pt.y()); } //difference from top edge (X does not matter)
+ return ResizeTop;
+ }
+ }else if(pt.y() > (this->height()-3) ){
+ //One of the bottom options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(this->height()-pt.y()); } //difference from bottom-left corner
+ return ResizeBottomLeft;
+ }else if(pt.x() > (this->width()-3)){
+ if(setoffset){ offset.setX(this->width()-pt.x()); offset.setY(this->height()-pt.y()); } //difference from bottom-right corner
+ return ResizeBottomRight;
+ }else{
+ if(setoffset){ offset.setX(0); offset.setY(this->height() - pt.y()); } //difference from bottom edge (X does not matter)
+ return ResizeBottom;
+ }
+ }else{
+ //One of the side options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(0); } //difference from left edge (Y does not matter)
+ return ResizeLeft;
+ }else if(pt.x() > (this->width()-3) ){
+ if(setoffset){ offset.setX(this->width()-pt.x()); offset.setY(0); } //difference from right edge (Y does not matter)
+ return ResizeRight;
+ }else{
+ return Normal;
+ }
+ }
+ }
+ return Normal;
+}
+
+void LWindowFrame::setMouseCursor(ModState state, bool override){
+ Qt::CursorShape shape;
+ switch(state){
+ case Normal:
+ shape = Qt::ArrowCursor;
+ break;
+ case Move:
+ shape = Qt::SizeAllCursor;
+ break;
+ case ResizeTop:
+ shape = Qt::SizeVerCursor;
+ break;
+ case ResizeTopRight:
+ shape = Qt::SizeBDiagCursor;
+ break;
+ case ResizeRight:
+ shape = Qt::SizeHorCursor;
+ break;
+ case ResizeBottomRight:
+ shape = Qt::SizeFDiagCursor;
+ break;
+ case ResizeBottom:
+ shape = Qt::SizeVerCursor;
+ break;
+ case ResizeBottomLeft:
+ shape = Qt::SizeBDiagCursor;
+ break;
+ case ResizeLeft:
+ shape = Qt::SizeHorCursor;
+ break;
+ case ResizeTopLeft:
+ shape = Qt::SizeFDiagCursor;
+ break;
+ }
+ if(override){
+ QApplication::setOverrideCursor(QCursor(shape));
+ }else{
+ this->setCursor(shape);
+ }
+}
+
+// ==========================
+// WINDOW INTERACTIONS
+//==========================
+void LWindowFrame::SyncSize(bool fromwin){
+ //sync the window/frame geometries (generally only done before embedding the client window)
+ int frame = this->frameWidth();
+ int TH = titleBar->height();
+ //Now load the information about the window and adjust the frame to match
+ if(fromwin){ lastGeom = LWM::SYSTEM->WM_Window_Geom(CID); }
+ else{ lastGeom = this->geometry(); }
+ qDebug() << "Initial Size:" << lastGeom << frame << TH;
+ //Add in the frame size
+ lastGeom.moveTop(lastGeom.y()-frame-TH);
+ lastGeom.setHeight(lastGeom.height()+(2*frame)+TH);
+ lastGeom.moveLeft(lastGeom.x()-frame);
+ lastGeom.setWidth( lastGeom.width()+(2*frame));
+ QList<unsigned int> margins;
+ margins << frame << frame << frame+TH << frame; //L/R/Top/Bottom
+ qDebug() << " - With Frame:" << lastGeom;
+ //Now adjust for a out-of-bounds location
+ if(lastGeom.x() < 0){ lastGeom.moveLeft(0); }
+ if(lastGeom.y() < 0){ lastGeom.moveTop(0); }
+ qDebug() << " - Adjusted:" << lastGeom;
+ this->setGeometry(lastGeom);
+ LWM::SYSTEM->WM_Set_Frame_Extents(CID, margins);
+}
+
+void LWindowFrame::SyncText(){
+ QString txt = WIN->title();
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowName(CID); }
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->OldWindowName(CID); }
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowVisibleName(CID); }
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowIconName(CID); }
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowVisibleIconName(CID); }
+ if(txt.isEmpty()){ txt = LWM::SYSTEM->WM_ICCCM_GetClass(CID); }
+ title->setText(txt);
+}
+
+// SIMPLE ANIMATIONS
+void LWindowFrame::showAnimation(LWM::WindowAction act){
+ bool useanimation = (act!=lastAction);
+ if(anim->state()==QAbstractAnimation::Running){
+ qDebug() << "New Animation Event:" << act;
+ return;
+ }
+ //Setup the animation routine
+ if(act==LWM::Show){
+ if(useanimation){
+ lastGeom = this->geometry();
+ //Expand out from center point
+ anim->setPropertyName("geometry");
+ anim->setStartValue( QRect(lastGeom.center(), QSize(0,0) ) );
+ anim->setEndValue( this->geometry() );
+ //Fade in gradually
+ //anim->setPropertyName("windowOpacity");
+ //anim->setStartValue( 0.0 );
+ //anim->setEndValue( 1.0 );
+ }else{
+ ShowClient(true);
+ this->raise();
+ this->show(); //just show it right away
+ }
+
+ }else if(act==LWM::Hide){
+ if(useanimation){
+ //Collapse in on center point
+ lastGeom = this->geometry();
+ anim->setPropertyName("geometry");
+ anim->setStartValue( QRect(this->geometry()) );
+ anim->setEndValue( QRect(this->geometry().center(), QSize(0,0) ) );
+ }else{
+ this->hide(); //just hide it right away
+ }
+ }else if(act==LWM::Closed){
+ //Need to clean up the container widget first to prevent XCB errors
+ //qDebug() << "Window Closed:" << WIN->winId() << CID;
+ if(useanimation){
+ //Collapse in on center line
+ lastGeom = this->geometry();
+ anim->setPropertyName("geometry");
+ anim->setStartValue( QRect(this->geometry()) );
+ anim->setEndValue( QRect(this->geometry().x(), this->geometry().center().y(), this->width(), 0 ) );
+ }else{
+ CloseAll(); //just hide it right away
+ }
+ }
+ if(useanimation){
+ ShowClient(false);
+ this->show();
+ qDebug() << " - Starting Animation:" << act;
+ lastAction = act;
+ anim->start();
+ };
+}
+
+void LWindowFrame::ShowClient(bool show){
+ if(show && this->layout()->indexOf(WinWidget)<0 && !Closing){
+ while(this->layout()->count()>0){ this->layout()->removeItem(0); }
+ this->layout()->addWidget(titleBar);
+ this->layout()->setAlignment(titleBar, Qt::AlignTop);
+ this->layout()->addWidget(WinWidget);
+ static_cast<QVBoxLayout*>(this->layout())->setStretch(1,1);
+ LWM::SYSTEM->WM_ShowWindow(CID);
+ }else if( !show && this->layout()->indexOf(WinWidget)>=0){
+ LWM::SYSTEM->WM_HideWindow(CID);
+ this->layout()->removeWidget(WinWidget);
+ }
+}
+
+void LWindowFrame::finishedAnimation(){
+ //Also set any final values
+ qDebug() << " - Finished Animation:" << lastAction;
+ switch(lastAction){
+ case LWM::Show:
+ ShowClient(true);
+ break;
+ case LWM::Closed:
+ case LWM::Hide:
+ this->lower();
+ this->hide();
+ LWM::SYSTEM->WM_HideWindow(this->winId());
+ default:
+ break;
+ }
+ if(Closing){
+ qDebug() << "Emitting finished signal";
+ emit Finished();
+ }
+}
+
+// =================
+// PUBLIC SLOTS
+// =================
+void LWindowFrame::updateAppearance(){
+ //Reload any button icons and such
+ minB->setIcon(LXDG::findIcon("window-suppressed",""));
+ maxB->setIcon(LXDG::findIcon("view-fullscreen",""));
+ closeB->setIcon(LXDG::findIcon("application-exit",""));
+ otherB->setIcon(LXDG::findIcon("configure",""));
+}
+
+void LWindowFrame::windowChanged(LWM::WindowAction act){
+ //A window property was changed - update accordingly
+ switch(act){
+ case LWM::Closed:
+ Closing = true;
+ case LWM::Hide:
+ case LWM::Show:
+ showAnimation(act);
+ break;
+ case LWM::MoveResize:
+ //Re-adjust to the new position/size of the window
+ SyncSize(true);
+ break;
+ default:
+ break; //do nothing
+ }
+}
+// =================
+// PRIVATE SLOTS
+// =================
+void LWindowFrame::closeClicked(){
+ qDebug() << "Closing Window" << LWM::SYSTEM->WM_ICCCM_GetClass(CID);
+ //First try the close event to let the client app do cleanup/etc
+ LWM::SYSTEM->WM_CloseWindow(CID);
+}
+
+void LWindowFrame::minClicked(){
+ qDebug() << "Minimize Window";
+ windowChanged(LWM::Hide);
+}
+
+void LWindowFrame::maxClicked(){
+ if(normalGeom.isNull()){
+ qDebug() << "Maximize Window";
+ normalGeom = this->geometry(); //save for later
+ this->showMaximized();
+ }else{
+ qDebug() << "Restore Window";
+ this->showNormal();
+ this->setGeometry(normalGeom);
+ normalGeom = QRect(); //clear it
+ }
+}
+
+void LWindowFrame::otherClicked(QAction* act){
+ QString action = act->whatsThis();
+}
+
+void LWindowFrame::CloseAll(){
+ qDebug() << " - Closing Frame";
+ this->hide();
+ emit Finished();
+}
+// =====================
+// PROTECTED
+// =====================
+void LWindowFrame::mousePressEvent(QMouseEvent *ev){
+ qDebug() << "Frame Mouse Press Event";
+ offset.setX(0); offset.setY(0);
+ if(activeState != Normal){ return; } // do nothing - already in a state of grabbed mouse
+ this->activateWindow();
+ LWM::SYSTEM->WM_Set_Active_Window(CID);
+ if(this->childAt(ev->pos())!=0){
+ //Check for any non-left-click event and skip it
+ if(ev->button()!=Qt::LeftButton){ return; }
+ activeState = Move;
+ offset.setX(ev->pos().x()); offset.setY(ev->pos().y());
+ }else{
+ //Clicked on the frame somewhere
+ activeState = getStateAtPoint(ev->pos(), true); //also have it set the offset variable
+ }
+ setMouseCursor(activeState, true); //this one is an override cursor
+
+}
+
+void LWindowFrame::mouseMoveEvent(QMouseEvent *ev){
+ ev->accept();
+ if(activeState == Normal){
+ setMouseCursor( getStateAtPoint(ev->pos()) ); //just update the mouse cursor
+
+ }else{
+ //Currently in a modification state
+ QRect geom = this->geometry();
+ switch(activeState){
+ case Move:
+ geom.moveTopLeft(ev->globalPos()-offset); //will not change size
+ break;
+ case ResizeTop:
+ geom.setTop(ev->globalPos().y()-offset.y());
+ break;
+ case ResizeTopRight:
+ geom.setTopRight(ev->globalPos()-offset);
+ break;
+ case ResizeRight:
+ geom.setRight(ev->globalPos().x()-offset.x());
+ break;
+ case ResizeBottomRight:
+ geom.setBottomRight(ev->globalPos()-offset);
+ break;
+ case ResizeBottom:
+ geom.setBottom(ev->globalPos().y()-offset.y());
+ break;
+ case ResizeBottomLeft:
+ geom.setBottomLeft(ev->globalPos()-offset);
+ break;
+ case ResizeLeft:
+ geom.setLeft(ev->globalPos().x()-offset.x());
+ break;
+ case ResizeTopLeft:
+ geom.setTopLeft(ev->globalPos()-offset);
+ break;
+ default:
+ break;
+ }
+ this->setGeometry(geom);
+ }
+}
+
+void LWindowFrame::mouseReleaseEvent(QMouseEvent *ev){
+ //Check for a right-click event
+ qDebug() << "Frame Mouse Release Event";
+ ev->accept();
+ if( (activeState==Normal) && (this->childAt(ev->pos())==titleBar) && (ev->button()==Qt::RightButton) ){
+ otherM->popup(ev->globalPos());
+ return;
+ }
+ activeState = Normal;
+ QApplication::restoreOverrideCursor();
+ setMouseCursor( getStateAtPoint(ev->pos()) );
+}
bgstack15