Skip to content

Commit

Permalink
Begin windowlist rebuild and start using KWindowSystem
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas Yoder committed Dec 28, 2022
1 parent b45acc5 commit 4bef603
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 24 deletions.
4 changes: 4 additions & 0 deletions forest-panel/forest-panel/forest-panel.pro
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ CONFIG += plugin

#LIBS += -lX11

LIBS += -L/usr/lib/x86_64-linux-gnu/ -lKF5WindowSystem
INCLUDEPATH += /usr/include/KF5/KWindowSystem
DEPENDPATH += /usr/include/KF5/KWindowSystem

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
Expand Down
4 changes: 4 additions & 0 deletions forest-panel/plugins/deskswitch/deskswitch.pro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ CONFIG += plugin
INCLUDEPATH += ../../library
INCLUDEPATH += ../../../library

LIBS += -L/usr/lib/x86_64-linux-gnu/ -lKF5WindowSystem
INCLUDEPATH += /usr/include/KF5/KWindowSystem
DEPENDPATH += /usr/include/KF5/KWindowSystem

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
Expand Down
15 changes: 14 additions & 1 deletion forest-panel/plugins/windowlist/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include "button.h"

#include <KWindowInfo>

button::button(xcb_window_t window, QIcon icon, QString type, QString text){
bttype = type;
bttext = text;
Expand Down Expand Up @@ -114,14 +116,25 @@ void button::mouseMoveEvent(QMouseEvent *event){
if (mousepressed){
if ((event->pos() - startdragpos).manhattanLength() > 20){
demaximizewindow();

//Move window so top of window (title bar) is on screen
KWindowInfo info(btwindow, NET::WMGeometry);
QRect screengeo = qApp->primaryScreen()->geometry();
QRect windowgeo = info.geometry();
int x = (windowgeo.width() > screengeo.width()) ? 50 : screengeo.width()/2 - windowgeo.width()/2;
int y = (windowgeo.height() > screengeo.height()) ? 50 : screengeo.height()/2 - windowgeo.height()/2;
Xcbutills::moveWindow(btwindow, x, y);

mousepressed = false;
}
}
}

void button::updatedata(){ //get rid of this somehow...
if (this->property("buttontype") != "Icon"){
QString newtext = Xcbutills::getWindowTitle(btwindow);
KWindowInfo info(btwindow, NET::WMVisibleName | NET::WMName);
QString newtext = info.visibleName().isEmpty() ? info.name() : info.visibleName();

if (bttext != newtext){
bttext = newtext;
setText(bttext);
Expand Down
62 changes: 62 additions & 0 deletions forest-panel/plugins/windowlist/windowbutton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "windowbutton.h"

#include "xcbutills/xcbutills.h"

windowbutton::windowbutton(ulong windowid, int desktop, QIcon icon, QString text) : window_id(windowid), window_desktop(desktop){
setupIconAndTextButton(text, icon, 16);

pmenu = new popupmenu(this, CenteredOnWidget);

pmenuitem *item = new pmenuitem("Raise", QIcon::fromTheme("arrow-up"));
connect(item, &pmenuitem::clicked, this, &windowbutton::raise_w);
pmenu->additem(item);
pmenuitem *item2 = new pmenuitem("Maximize", QIcon::fromTheme("arrow-up-double"));
connect(item2, &pmenuitem::clicked, this, &windowbutton::maximize_w);
pmenu->additem(item2);
pmenuitem *item3 = new pmenuitem("Demaximize", QIcon::fromTheme("arrow-down"));
connect(item3, &pmenuitem::clicked, this, &windowbutton::demaximize_w);
pmenu->additem(item3);
pmenuitem *item4 = new pmenuitem("Minimize", QIcon::fromTheme("arrow-down-double"));
connect(item4, &pmenuitem::clicked, this, &windowbutton::minimize_w);
pmenu->additem(item4);
pmenuitem *item5 = new pmenuitem("Close", QIcon::fromTheme("application-exit"));
connect(item5, &pmenuitem::clicked, this, &windowbutton::close_w);
pmenu->additem(item5);
}

void windowbutton::mouseReleaseEvent(QMouseEvent *event){
panelbutton::mouseReleaseEvent(event);

if (event->button() == Qt::LeftButton){
raise_w();
}
else if(event->button() == Qt::RightButton){
QSize sizeHint = pmenu->popupw->sizeHint();
if (width() > sizeHint.width())
pmenu->popupw->setFixedSize(width(), sizeHint.height());
else
pmenu->popupw->setFixedSize(sizeHint.width(), sizeHint.height());

pmenu->show();
}
}

void windowbutton::raise_w(){
Xcbutills::raiseWindow(window_id);
}

void windowbutton::maximize_w(){
Xcbutills::maximizeWindow(window_id);
}

void windowbutton::minimize_w(){
Xcbutills::minimizeWindow(window_id);
}

void windowbutton::close_w(){
Xcbutills::closeWindow(window_id);
}

void windowbutton::demaximize_w(){
Xcbutills::demaximizeWindow(window_id);
}
38 changes: 38 additions & 0 deletions forest-panel/plugins/windowlist/windowbutton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef WINDOWBUTTON_H
#define WINDOWBUTTON_H

#include "panelbutton.h"

#include "popupmenu.h"

class windowbutton : public panelbutton
{
Q_OBJECT

public:
explicit windowbutton(ulong window, int desktop, QIcon icon, QString text);

ulong windowId(){return window_id;}
void setWindowDesktop(int desktop){window_desktop = desktop;}
int windowDesktop(){return window_desktop;}

signals:

private slots:
void raise_w();
void maximize_w();
void minimize_w();
void close_w();
void demaximize_w();

protected:
void mouseReleaseEvent(QMouseEvent *event);

private:
ulong window_id;
int window_desktop;

popupmenu *pmenu = nullptr;
};

#endif // WINDOWBUTTON_H
159 changes: 141 additions & 18 deletions forest-panel/plugins/windowlist/windowlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@

#include "windowlist.h"


#include <KWindowInfo>

windowlist::windowlist(){}

windowlist::~windowlist(){}

void windowlist::setupPlug(QBoxLayout *layout, QList<pmenuitem *> itemlist){
layout->addWidget(this);

mainlayout->setDirection(layout->direction());
QHBoxLayout *baseLayout = new QHBoxLayout;
baseLayout->addLayout(mainlayout);
baseLayout->setMargin(0);
baseLayout->setSpacing(0);
mainlayout->setMargin(0);
mainlayout->setSpacing(0);
this->setLayout(mainlayout);
QWidget *swidget = new QWidget;
baseLayout->addWidget(swidget);
this->setLayout(baseLayout);

pmenu = new popupmenu(this, CenteredOnMouse);
foreach (pmenuitem *item, itemlist)
Expand All @@ -48,13 +56,19 @@ void windowlist::setupPlug(QBoxLayout *layout, QList<pmenuitem *> itemlist){
loadsettings();

currentdesk = Xcbutills::getCurrentDesktop();
updatelist();
//updatelist();

//this updates the text on the button (for like when you change directories in a file manager & the window title changes too.)
//there should be a better way to do this instead of running a timer all the time
QTimer *t = new QTimer;
connect(t, SIGNAL(timeout()), this, SIGNAL(updatebuttondata()));
t->start(800);
//QTimer *t = new QTimer;
//connect(t, SIGNAL(timeout()), this, SIGNAL(updatebuttondata()));
//t->start(800);

connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &windowlist::onWindowAdded);
connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &windowlist::onWindowRemoved);
connect(KWindowSystem::self(), static_cast<void (KWindowSystem::*)(WId, NET::Properties, NET::Properties2)>(&KWindowSystem::windowChanged),
this, &windowlist::onWindowChanged);
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &windowlist::onDesktopChanged);
}

QHash<QString, QString> windowlist::getpluginfo(){
Expand All @@ -65,8 +79,8 @@ QHash<QString, QString> windowlist::getpluginfo(){
return info;
}

void windowlist::updatelist(){
QList<xcb_window_t> x_client_list = Xcbutills::getClientList();
//void windowlist::updatelist(){
/* QList<xcb_window_t> x_client_list = Xcbutills::getClientList();
if (x_client_list != oldwindows || currentdesk != olddesk){
mainlayout->removeWidget(stretchwidget);
Expand All @@ -77,7 +91,11 @@ void windowlist::updatelist(){
desk_windows.append(window);
if (!oldwindows.contains(window)){
button *bt = new button(window, Xcbutills::getWindowIcon(window), bttype, Xcbutills::getWindowTitle(window));
KWindowInfo info(window, NET::WMVisibleName | NET::WMName);
QString title = info.visibleName().isEmpty() ? info.name() : info.visibleName();
button *bt = new button(window, Xcbutills::getWindowIcon(window), bttype, title);
connect(this, &windowlist::changehighlight, bt, &button::sethighlight);
connect(this, &windowlist::updatebuttondata, bt, &button::updatedata);
//connect(bt, &button::mouseEnter, ipopup, &imagepopup::btmouseEnter);
Expand All @@ -102,13 +120,13 @@ void windowlist::updatelist(){
mainlayout->addWidget(stretchwidget, 0);
oldwindows = desk_windows;
olddesk = currentdesk;
}
}
}*/
//}

//process events from X11 i.e. active window change, active desktop change
//called from the plugin host
void windowlist::XcbEventFilter(xcb_generic_event_t* event){
if (event->response_type == XCB_PROPERTY_NOTIFY){
/* if (event->response_type == XCB_PROPERTY_NOTIFY){
xcb_client_message_event_t *message = reinterpret_cast<xcb_client_message_event_t *>(event);
if (message->type == Xcbutills::atom("_NET_CLIENT_LIST")){
Expand All @@ -124,18 +142,18 @@ void windowlist::XcbEventFilter(xcb_generic_event_t* event){
updatelist();
}
}
}
}*/
}

void windowlist::reloadsettings(){
loadsettings();
foreach (unsigned long key, button_list.keys()) {
/*foreach (unsigned long key, button_list.keys()) {
button *bt = button_list[key];
if (bt){ bt->close(); bt->deleteLater(); }
}
button_list.clear();
oldwindows.clear();
updatelist();
}*/
//button_list.clear();
//oldwindows.clear();
//updatelist();
}

void windowlist::mouseReleaseEvent(QMouseEvent *event){
Expand All @@ -154,3 +172,108 @@ void windowlist::showsettingswidget(){
connect(swidget, SIGNAL(settingschanged()), this, SLOT(reloadsettings()));
swidget->show();
}


bool windowlist::acceptWindow(WId window) const
{
QFlags<NET::WindowTypeMask> ignoreList;
ignoreList |= NET::DesktopMask;
ignoreList |= NET::DockMask;
ignoreList |= NET::SplashMask;
ignoreList |= NET::ToolbarMask;
ignoreList |= NET::MenuMask;
ignoreList |= NET::PopupMenuMask;
ignoreList |= NET::NotificationMask;

KWindowInfo info(window, NET::WMWindowType | NET::WMState, NET::WM2TransientFor);
if (!info.valid())
return false;

if (NET::typeMatchesMask(info.windowType(NET::AllTypesMask), ignoreList))
return false;

if (info.state() & NET::SkipTaskbar)
return false;

// WM_TRANSIENT_FOR hint not set - normal window
WId transFor = info.transientFor();
if (transFor == 0 || transFor == window || transFor == (WId) QX11Info::appRootWindow())
return true;

info = KWindowInfo(transFor, NET::WMWindowType);

QFlags<NET::WindowTypeMask> normalFlag;
normalFlag |= NET::NormalMask;
normalFlag |= NET::DialogMask;
normalFlag |= NET::UtilityMask;

return !NET::typeMatchesMask(info.windowType(NET::AllTypesMask), normalFlag);
}

void windowlist::onWindowAdded(WId window){
if (!acceptWindow(window)) return;

KWindowInfo info(window, NET::WMDesktop);
int desktop = info.desktop();

if(!button_list.contains(window)){
windowbutton *wbt = new windowbutton(window, desktop, Xcbutills::getWindowIcon(window), Xcbutills::getWindowTitle(window));
wbt->setMaximumWidth(maxbtsize);
mainlayout->addWidget(wbt, 1);
button_list[window] = wbt;

if(desktop != currentdesk){
wbt->setHidden(true);
}
}
}

void windowlist::onWindowRemoved(WId window){
if(!button_list.contains(window))
return;

windowbutton *wbt = button_list[window];
button_list.remove(window);
mainlayout->removeWidget(wbt);
wbt->close();
wbt->deleteLater();
}

void windowlist::onWindowChanged(WId window, NET::Properties prop, NET::Properties2 prop2){
if(button_list.contains(window)){
windowbutton *wbt = button_list[window];
if (prop.testFlag(NET::WMVisibleName) || prop.testFlag(NET::WMName))
wbt->setText(Xcbutills::getWindowTitle(window));

if (prop.testFlag(NET::WMIcon) || prop2.testFlag(NET::WM2WindowClass))
wbt->setIcon(Xcbutills::getWindowIcon(window));

if (prop.testFlag(NET::WMDesktop) || prop.testFlag(NET::WMGeometry)) {
wbt->setWindowDesktop(Xcbutills::getWindowDesktop(window));
wbt->setHidden(wbt->windowDesktop() != currentdesk);
}

if (prop.testFlag(NET::WMState)) {
WId new_active_w = Xcbutills::getActiveWindow();
if(new_active_w != active_window){
if(button_list.contains(active_window))
button_list[active_window]->setDown(false);
if(button_list.contains(new_active_w))
button_list[new_active_w]->setDown(true);
active_window = new_active_w;
}

KWindowInfo info(window, NET::WMState);
if (info.hasState(NET::SkipTaskbar)) {
onWindowRemoved(window);
}
}
}
}

void windowlist::onDesktopChanged(int desktop){
currentdesk = desktop;
foreach(windowbutton *wbt, button_list){
wbt->setHidden(wbt->windowDesktop() != currentdesk);
}
}
Loading

0 comments on commit 4bef603

Please sign in to comment.