Files

472 lines
12 KiB
C++
Raw Permalink Normal View History

2018-01-03 14:21:19 +08:00
/*
* Copyright (C) 2017 Tianjin KYLIN Information Technology Co., Ltd.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
2017-12-22 14:41:02 +08:00
#include <QDesktopWidget>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qxtglobalshortcut.h"
#include <QGraphicsDropShadowEffect>
#include <QGridLayout>
#include <QDebug>
#include <QTime>
#include <QPainter>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
2017-12-22 14:41:02 +08:00
#include "keyeventmonitor.h"
#undef signals
extern "C" {
#include <alt_tab_list.h>
#include <ukwm/compositor/plugins/ukui_plugin.h>
}
char tab_list_image_file[PATH_MAX_LEN] = {0};
char workspace_image_file[PATH_MAX_LEN] = {0};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDesktopWidget *desktop = QApplication::desktop();
move((desktop->width() - this->width()) / 2, (desktop->height() - this->height()) / 2);
2017-12-22 14:41:02 +08:00
this->ShowStatus = false;
this->CanBeRelease = true;
for (int i = 0; i < LINES; i++)
maxY[i] = 0;
this->WindowIndex = 0;
2017-12-22 14:41:02 +08:00
this->setAttribute(Qt::WA_TranslucentBackground, true);
2017-12-22 14:41:02 +08:00
m_sub = new QWidget(this);
m_sub->move((desktop->width() - this->width()) / 2, (desktop->height() - this->height()) / 2);
2017-12-22 14:41:02 +08:00
m_label = new QLabel(m_sub);
m_sub->setStyleSheet("background-color:rgba(0, 0, 0, 216);"
"border-radius: 8px;"
"border-color: rgb(200, 200, 200);"
"border-style:solid;"
"border-width:2px;");
2017-12-22 14:41:02 +08:00
//QFont font("Arial", 30, QFont::Bold);
QFont font("Microsoft YaHei", 10, 50);
m_label->setFont(font);
m_label->setAlignment(Qt::AlignCenter);
m_label->setStyleSheet("background-color: transparent;"
"border: 0px; color: white");
QFontMetrics fm(font);
fontWidth = fm.maxWidth();
fontHeight = fm.height();
2017-12-22 14:41:02 +08:00
QxtGlobalShortcut *sc = new QxtGlobalShortcut(QKeySequence("Alt+Tab"), this);
QxtGlobalShortcut *sc_u = new QxtGlobalShortcut(QKeySequence("Alt+Shift+Tab"), this);
if (sc == NULL or sc_u == NULL)
{
printf("Can not register shortcut, exit...\n");
QApplication::exit(1);
}
2017-12-22 14:41:02 +08:00
connect(sc, SIGNAL(activated()), this, SLOT(show_forward()));
connect(sc_u, SIGNAL(activated()), this, SLOT(show_backward()));
2017-12-22 14:41:02 +08:00
KeyEventMonitor *kem = new KeyEventMonitor;
connect(kem, SIGNAL(KeyAltRelease()), this, SLOT(doAltRelease()));
kem->start();
//QWidget::installEventFilter(this); //Install event filter for this window.
snprintf(tab_list_image_file, PATH_MAX_LEN, "/run/user/%d/%s",
2017-12-22 14:41:02 +08:00
getuid(), TAB_LIST_IMAGE_FILE);
}
MainWindow::~MainWindow()
{
for (int i = 0; i < theLabels.size(); i++)
delete theLabels[i];
theLabels.clear();
theTitles.clear();
2017-12-22 14:41:02 +08:00
delete m_label;
delete m_sub;
delete ui;
}
QPixmap qimageFromXImage(XImage* ximage)
{
QImage::Format format = QImage::Format_ARGB32_Premultiplied;
if (ximage->depth == 24)
format = QImage::Format_RGB32;
else if (ximage->depth == 16)
format = QImage::Format_RGB16;
QImage image = QImage(reinterpret_cast<uchar*>(ximage->data),
ximage->width, ximage->height,
ximage->bytes_per_line, format).copy();
// Little Endian or Big Endian?
if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && ximage->byte_order == MSBFirst)
|| (QSysInfo::ByteOrder == QSysInfo::BigEndian && ximage->byte_order == LSBFirst)) {
for (int i = 0; i < image.height(); i++) {
if (ximage->depth == 16) {
ushort* p = reinterpret_cast<ushort*>(image.scanLine(i));
ushort* end = p + image.width();
while (p < end) {
*p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
p++;
}
} else {
uint* p = reinterpret_cast<uint*>(image.scanLine(i));
uint* end = p + image.width();
while (p < end) {
*p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
| ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
p++;
}
}
}
}
// Fix alpha channel
if (format == QImage::Format_RGB32) {
QRgb* p = reinterpret_cast<QRgb*>(image.bits());
for (int y = 0; y < ximage->height; ++y) {
for (int x = 0; x < ximage->width; ++x)
p[x] |= 0xff000000;
p += ximage->bytes_per_line / 4;
}
}
return QPixmap::fromImage(image);
2017-12-22 14:41:02 +08:00
}
void MainWindow::show_forward()
{
show_tab_list(1);
2017-12-22 14:41:02 +08:00
}
void MainWindow::show_backward()
{
show_tab_list(-1);
2017-12-22 14:41:02 +08:00
}
void MainWindow::show_tab_list(int value)
{
static unsigned long tabPreviousTime = 0;
unsigned long tabCurrentTime = 0;
2017-12-22 14:41:02 +08:00
tabCurrentTime = QDateTime::currentMSecsSinceEpoch();
if (tabCurrentTime - tabPreviousTime < INTERVAL_TIME_MS)
2017-12-22 14:41:02 +08:00
{
return;
2017-12-22 14:41:02 +08:00
}
tabPreviousTime = tabCurrentTime;
2017-12-22 14:41:02 +08:00
this->CanBeRelease = false;
2017-12-22 14:41:02 +08:00
if (!this->ShowStatus)
2017-12-22 14:41:02 +08:00
{
for (int i = 0; i < LINES; i++)
maxY[i] = 0;
theLabels.clear();
2017-12-22 14:41:02 +08:00
InitUkwmPluginDBusComm();
while (!UkwmPluginDBusServiceIsReady())
2017-12-22 14:41:02 +08:00
{
usleep(1000);
2017-12-22 14:41:02 +08:00
}
this->global_tab_list = DBusGetAltTabList();
this->WindowCount = g_list_length(this->global_tab_list);
FinishUkwmPluginDBusComm();
if (this->WindowCount == 0)
2017-12-22 14:41:02 +08:00
{
this->CanBeRelease = true;
return;
2017-12-22 14:41:02 +08:00
}
this->ShowStatus = true;
2017-12-22 14:41:02 +08:00
//Generate min{20, this->WindowCount} labels
int total = LINES * COLS;
int n_labels = total; //How many labels will be showed?
if (total > this->WindowCount)
n_labels = this->WindowCount;
int lines;
lines = n_labels / COLS;
if (lines * COLS < n_labels)
lines++;
int i;
XImage *img = NULL;
Display *display = NULL;
XWindowAttributes attr;
GList *tab_list = this->global_tab_list;
display = XOpenDisplay(NULL);
for (i = 0; i < this->WindowCount; i++)
{
int myline = i / COLS; //line is from 0
//int mycol = i % COLS; //col is from 0
//Produce icon
alt_tab_item *ati = NULL;
ati = (alt_tab_item *)g_list_nth_data(tab_list, i);
theTitles.append(QString(ati->title_name));
if (myline < LINES)
{
if (maxY[myline] < PREVIEW_HEIGHT)
maxY[myline] = PREVIEW_HEIGHT;
//Compute myx
int j;
int myx = LEFT_SIZE;
for (j = myline * COLS; j < i; j++)
{
myx += theLabels[j]->width();
myx += INTERVAL_WIDTH_SIZE;
}
//Compute myy
int myy = TOP_SIZE;
for (j = 0; j < myline; j++)
{
myy += maxY[j];
myy += INTERVAL_HEIGHT_SIZE;
}
QPixmap pixmap;
pixmap.load(tab_list_image_file);
MyLabel *one = new MyLabel(i, ati->title_name, m_sub);
2017-12-22 14:41:02 +08:00
one->move(myx, myy);
one->resize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
XGetWindowAttributes(display, ati->xid, &attr);
img = XGetImage(display, ati->xid, 0, 0,
attr.width, attr.height, 0xffffffff,
ZPixmap);
QPixmap thumbnail = qimageFromXImage(img).scaled(THUMBNAIL_WIDTH,
THUMBNAIL_HEIGHT,
Qt::KeepAspectRatio,
Qt::FastTransformation);
XDestroyImage(img);
QPixmap icon = pixmap.copy(ati->x, ati->y, ati->width, ati->height).
scaled(ICON_WIDTH, ICON_HEIGHT,
Qt::KeepAspectRatio, Qt::FastTransformation);
QPixmap preview(PREVIEW_WIDTH, PREVIEW_HEIGHT);
preview.fill(Qt::transparent);
QPainter painter(&preview);
QRect source;
QRect target;
source = QRect(0, 0, thumbnail.width(), thumbnail.height());
target = QRect((THUMBNAIL_WIDTH - thumbnail.width()) / 2,
(THUMBNAIL_HEIGHT - thumbnail.height()) / 2,
thumbnail.width(), thumbnail.height());
painter.drawPixmap(target, thumbnail, source);
source = QRect(0, 0, icon.width(), icon.height());
target = QRect(PREVIEW_WIDTH -ICON_WIDTH,
PREVIEW_HEIGHT - ICON_HEIGHT,
icon.width(), icon.height());
painter.drawPixmap(target, icon, source);
painter.end();
one->setPixmap(preview);
2017-12-22 14:41:02 +08:00
theLabels.append(one);
connect(one, SIGNAL(myclicked(int)), this, SLOT(slotMylabel(int)));
}
}
XCloseDisplay(display);
//Compute the size (wx, wy) of the whole window.
int j;
int max_width = 0;
for (i = 0; i < lines; i++)
{
int wx = LEFT_SIZE;
for (j = 0; j < COLS; j++)
{
if ((i * COLS + j) >= n_labels)
break;
wx += theLabels[i * COLS + j]->width();
wx += INTERVAL_HEIGHT_SIZE;
}
wx = wx - INTERVAL_HEIGHT_SIZE + RIGHT_SIZE;
if (max_width < wx)
max_width = wx;
}
int max_height = TOP_SIZE;
for (i = 0; i < lines; i++)
{
max_height += maxY[i];
max_height += INTERVAL_HEIGHT_SIZE;
}
max_height = max_height - INTERVAL_HEIGHT_SIZE + BOTTOM_SIZE;
m_sub->resize(max_width, max_height);
QDesktopWidget *desktop = QApplication::desktop();
QRect screen_rect;
int s_num = desktop->screenCount();
int ps_idx = desktop->primaryScreen();
for (i = 0; i < screen_widget.length(); i++)
{
screen_widget[i]->hide();
}
//For multiple screens, use transparent QMainWindow to prevent clicking the mouse in other screens.
for (i = 0; i < s_num; i++)
{
if ((i + 1) > screen_widget.length())
{
screen_widget.append(new QMainWindow(this));
screen_widget[i]->setWindowFlags(Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint |
Qt::Tool);
screen_widget[i]->setWindowState(Qt::WindowActive);
screen_widget[i]->setAttribute(Qt::WA_TranslucentBackground);
screen_widget[i]->setWindowOpacity(0);
}
if (i != ps_idx)
{
screen_rect = desktop->screenGeometry(i);
screen_widget[i]->setGeometry(screen_rect);
screen_widget[i]->showFullScreen();
}
}
screen_rect = desktop->screenGeometry(ps_idx);
this->move(screen_rect.x(), screen_rect.y());
m_sub->move((screen_rect.width() - m_sub->width()) / 2,
(screen_rect.height() - m_sub->height()) / 2);
2017-12-22 14:41:02 +08:00
}
//this->setWindowState(Qt::WindowActive);
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool);
this->activateWindow();
this->showFullScreen();
m_sub->show();
fflush(stdout);
int count = this->WindowCount;
int index = this->WindowIndex;
for (int i = 0; i < theLabels.size(); i++)
theLabels[i]->setHideColor();
index = (index + count + value) % count;
this->WindowIndex = index;
m_label->setText("");
if (index < LINES * COLS)
2017-12-22 14:41:02 +08:00
{
theLabels[index]->setBrightColor();
2017-12-22 14:41:02 +08:00
}
m_label->setText(theTitles[index]); //All visible and invisible windows have their own titles.
2017-12-22 14:41:02 +08:00
m_label->resize(m_sub->width() - 10, 20);
m_label->move((m_sub->width() - m_label->width()) / 2, m_sub->height() - m_label->height() - 15);
this->CanBeRelease = true;
2017-12-22 14:41:02 +08:00
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
unsigned int modifiers = event->modifiers() & Qt::KeyboardModifierMask;
2017-12-22 14:41:02 +08:00
if ((event->key() == Qt::Key_Tab) || (event->key() == Qt::Key_Backtab))
{
if (modifiers == Qt::AltModifier)
show_tab_list(1);
2017-12-22 14:41:02 +08:00
if (modifiers == (Qt::ShiftModifier | Qt::AltModifier))
show_tab_list(-1);
}
2017-12-22 14:41:02 +08:00
}
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
QWidget::keyReleaseEvent(event);
2017-12-22 14:41:02 +08:00
}
void MainWindow::slotMylabel(int index)
{
for (int i = 0; i < theLabels.size(); i++)
theLabels[i]->setHideColor();
2017-12-22 14:41:02 +08:00
this->WindowIndex = index;
2017-12-22 14:41:02 +08:00
hideWindow();
2017-12-22 14:41:02 +08:00
}
void MainWindow::hideWindow()
{
if (this->ShowStatus)
{
int i = 0;
for (i = 0; i < theLabels.size(); i++)
delete theLabels[i];
theLabels.clear();
theTitles.clear();
2017-12-22 14:41:02 +08:00
for (i = 0; i < screen_widget.length(); i++)
screen_widget[i]->hide();
2017-12-22 14:41:02 +08:00
InitUkwmPluginDBusComm();
DBusActivateWindowByTabListIndex(this->WindowIndex);
FinishUkwmPluginDBusComm();
2017-12-22 14:41:02 +08:00
this->hide();
this->ShowStatus = false;
this->WindowIndex = 0;
}
2017-12-22 14:41:02 +08:00
}
void MainWindow::doAltRelease()
{
int times = 0;
while ((!this->CanBeRelease) && (times <= 10))
{
times++;
usleep(100 * 1000);
}
this->hideWindow();
2017-12-22 14:41:02 +08:00
}