tablet: ukui tablet mode basic support

This commit is contained in:
Hongfei Shang 2022-06-19 07:03:56 +08:00
parent df074a9056
commit c8e1470339
10 changed files with 226 additions and 0 deletions

View File

@ -96,6 +96,7 @@ AbstractClient::AbstractClient()
connect(ApplicationMenu::self(), &ApplicationMenu::applicationMenuEnabledChanged, this, [this] {
Q_EMIT hasApplicationMenuChanged(hasApplicationMenu());
});
m_bTabletToPcRestoreFlag = false;
}
AbstractClient::~AbstractClient()
@ -1129,6 +1130,9 @@ void AbstractClient::handleInteractiveMoveResize(int x, int y, int x_root, int y
if (isWaitingForInteractiveMoveResizeSync())
return; // we're still waiting for the client or the timeout
if (workspace()->isInTabletMode())
return;
const Gravity gravity = interactiveMoveResizeGravity();
if ((gravity == Gravity::None && !isMovableAcrossScreens())
|| (gravity != Gravity::None && (isShade() || !isResizable()))) {
@ -2387,6 +2391,11 @@ bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignor
if (!wantsInput()) // we cannot be active, use it anyway
active = true;
if(workspace()->isInTabletMode()) {
Workspace::self()->performWindowOperation(this, Options::NoOp);
return false;
}
// check whether it is a double click
if (event->button() == Qt::LeftButton && titlebarPositionUnderMouse()) {
if (m_decoration.doubleClickTimer.isValid()) {

View File

@ -371,6 +371,14 @@ public:
return m_icon;
}
void setTabletToPcRestoreFlag(bool bTabletToPcRestoreFlag){
m_bTabletToPcRestoreFlag = bTabletToPcRestoreFlag;
}
bool getTabletToPcRestoreFlag() const {
return m_bTabletToPcRestoreFlag;
}
bool isZombie() const;
bool isActive() const {
return m_active;
@ -1239,6 +1247,7 @@ private:
bool m_keepBelow = false;
bool m_demandsAttention = false;
bool m_minimized = false;
bool m_bTabletToPcRestoreFlag; //平板切换pc后如果此时窗口处于最小化则该标志置为true激活后用于将最大化窗口还原再次为false
QTimer *m_autoRaiseTimer = nullptr;
QTimer *m_shadeHoverTimer = nullptr;
ShadeMode m_shadeMode = ShadeNone;

View File

@ -171,6 +171,29 @@ void DecorationBridge::init()
QStringLiteral("org.kde.KGlobalSettings"),
QStringLiteral("slotFontChange"),
this, SLOT(fontUpdate(int, QString)));
m_bTabletMode = false;
//kwin启动时获取运行模式: 0:PC模式, 1:平板模式
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.statusmanager.interface",
"/",
"com.kylin.statusmanager.interface",
"get_current_tabletmode");
QDBusMessage response = QDBusConnection::sessionBus().call(message);
if (response.type() == QDBusMessage::ReplyMessage) {
m_bTabletMode = response.arguments().takeFirst().toBool();
//printf("TabletMode = %d\n", m_bTabletMode);
} else {
printf("TabletMode qdus invalid\n");
}
//通过dbus监听PC-平板模式切换
QDBusConnection::sessionBus().connect("com.kylin.statusmanager.interface",
"/",
"com.kylin.statusmanager.interface",
"mode_change_signal",
this,
SLOT(slotSetSurface(bool)));
}
void DecorationBridge::slotThemeUpdate(int themeId)
@ -189,6 +212,15 @@ void DecorationBridge::fontUpdate(int nfont, QString strFamily)
Q_EMIT sig_updateFont(font);
}
void DecorationBridge::slotSetSurface(bool bSurface)
{
if(m_bTabletMode == bSurface)
{
return;
}
m_bTabletMode = bSurface;
}
void DecorationBridge::initPlugin()
{
const KPluginMetaData metaData = KPluginMetaData::findPluginById(s_pluginName, m_plugin);
@ -326,6 +358,7 @@ KDecoration2::Decoration *DecorationBridge::createDecoration(AbstractClient *cli
args.insert(QStringLiteral("themeId"), m_themeId); //针对UKUI定制的主题id
args.insert(QStringLiteral("systemFontSize"), m_nFont); //标题栏字体大小
args.insert(QStringLiteral("systemFont"), m_strFontFamily); //标题栏字体类型
args.insert(QStringLiteral("tabletMode"), m_bTabletMode);
auto deco = m_factory->create<KDecoration2::Decoration>(client, QVariantList({args}));
deco->setSettings(m_settings);
deco->init();

View File

@ -71,6 +71,7 @@ Q_SIGNALS:
public Q_SLOTS:
void slotThemeUpdate(int);
void fontUpdate(int nfont, QString strFamily);
void slotSetSurface(bool bSurface);
private:
QString readPlugin();
@ -93,6 +94,7 @@ private:
int m_themeId; //主题id
int m_nFont;
QString m_strFontFamily;
bool m_bTabletMode;
KWIN_SINGLETON(DecorationBridge)
};

View File

@ -834,6 +834,10 @@ void Workspace::quickTileWindow(QuickTileMode mode)
return;
}
if(m_bTabletMode) {
return;
}
// If the user invokes two of these commands in a one second period, try to
// combine them together to enable easy and intuitive corner tiling
#define FLAG(name) QuickTileMode(QuickTileFlag::name)

View File

@ -1363,6 +1363,9 @@ void Workspace::slotWindowToPrevScreen()
*/
void Workspace::slotWindowMaximize()
{
if(m_bTabletMode)
return;
if (USABLE_ACTIVE_CLIENT)
performWindowOperation(active_client, Options::MaximizeOp);
}

View File

@ -127,6 +127,7 @@ Workspace::Workspace()
, set_active_client_recursion(0)
, block_stacking_updates(0)
, m_sessionManager(new SessionManager(this))
, m_bTabletMode(false)
{
// If KWin was already running it saved its configuration after loosing the selection -> Reread
QFuture<void> reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration);
@ -278,6 +279,28 @@ void Workspace::init()
connect(server, &WaylandServer::shellClientRemoved, this, &Workspace::removeShellClient);
}
//kwin启动时获取运行模式: 0:PC模式, 1:平板模式
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.statusmanager.interface",
"/",
"com.kylin.statusmanager.interface",
"get_current_tabletmode");
QDBusMessage response = QDBusConnection::sessionBus().call(message);
if (response.type() == QDBusMessage::ReplyMessage) {
m_bTabletMode = response.arguments().takeFirst().toBool();
slotSwitchTabletMode(m_bTabletMode);
} else {
printf("TabletMode qdus invalid\n");
}
//通过dbus监听PC-平板模式切换
QDBusConnection::sessionBus().connect("com.kylin.statusmanager.interface",
"/",
"com.kylin.statusmanager.interface",
"mode_change_signal",
this,
SLOT(slotSwitchTabletMode(bool)));
// SELI TODO: This won't work with unreasonable focus policies,
// and maybe in rare cases also if the selected client doesn't
// want focus
@ -289,6 +312,58 @@ void Workspace::init()
// TODO: ungrabXServer()
}
void Workspace::slotSwitchTabletMode(bool bSurfaceMode)
{
if (m_bTabletMode == bSurfaceMode)
return;
m_bTabletMode = bSurfaceMode;
switchTablet(m_bTabletMode);
}
void Workspace::switchTablet(bool bOn)
{
bool bTopClientMaximize = true; //顶层窗口最大化标志
for (int i = stacking_order.count() - 1; i > -1; --i) {
AbstractClient *c = qobject_cast<AbstractClient*>(stacking_order.at(i));
if (!c || c->isDock() || c->isDesktop())
continue;
//m_bTabletMode为true表示pc切平板
if (m_bTabletMode) {
if (c->maximizeMode() == MaximizeRestore) {
c->setTabletToPcRestoreFlag(true); //切平板前,如果是还原状态,则记录
}
//并且该窗口不是最小化时
if(!c->isMinimized()) {
if(bTopClientMaximize) {
bTopClientMaximize = false;
c->maximize(MaximizeFull); //序号越大,越在顶层,只需要将既不是任务栏又不是桌面的最顶层次未最小化的窗口最大化
if (false == c->isResizable()) {
if (!showingDesktop()) {
// 如果是固定大小的窗口,需要将窗口放到屏幕的正中间
Placement::self()->placeCentered(c, workspace()->activeOutput()->geometry());
}
}
} else {
printf("Workspace::switchTablet, minimize unminimized caption:%s\n", c->caption().toStdString().c_str());
c->minimize(true);
}
}
} else {
//m_bTabletMode为false表示平板切pc顶层最大化窗口如果之前是还原状态则需还原
if (MaximizeFull == c->maximizeMode() && true == bTopClientMaximize) {
bTopClientMaximize = false;
if (c->getTabletToPcRestoreFlag()) { //如果pc切平板前记录的之前是还原状态则当前激活窗口在切回pc后需还原否则不需要处理
c->maximize(MaximizeRestore);
c->setTabletToPcRestoreFlag(false); //切回pc后由于当前激活窗口已还原则以后该窗口无需再做还原处理
}
}
}
}
}
void Workspace::initializeX11()
{
if (!kwinApp()->x11Connection()) {
@ -656,6 +731,9 @@ X11Client *Workspace::createClient(xcb_window_t w, bool is_mapped)
return nullptr;
}
addClient(c);
if(m_bTabletMode) //当是平板模式时,窗口默认最大化,其他窗口最小化/*,并且设置平板标签*/
c->makeOthersMinimize();
return c;
}
@ -2238,6 +2316,17 @@ void Workspace::updateClientArea()
}
}
//当屏幕旋转时,那些固定大小的窗口需要再次进行一次居中设置(除了任务栏和桌面)
if (m_bTabletMode) {
for (auto it = m_x11Clients.constBegin(); it != m_x11Clients.constEnd(); ++it) {
if (true == (*it)->isResizable() || true == (*it)->isDock() || true == (*it)->isDesktop()) {
continue;
}
Placement::self()->placeCentered(*it, workspace()->activeOutput()->geometry());
}
}
if (m_workAreas != workAreas || m_restrictedAreas != restrictedAreas || m_screenAreas != screenAreas) {
m_workAreas = workAreas;
m_screenAreas = screenAreas;

View File

@ -416,6 +416,9 @@ public:
*/
void removeInternalClient(InternalClient *client);
bool isInTabletMode() {return m_bTabletMode;}
void switchTablet(bool bOn);
public Q_SLOTS:
void performWindowOperation(KWin::AbstractClient* c, Options::WindowOperation op);
// Keybindings
@ -431,6 +434,8 @@ public Q_SLOTS:
void slotWindowToPrevScreen();
void slotToggleShowDesktop();
void slotSwitchTabletMode(bool bSurfaceMode);
void slotWindowMaximize();
void slotWindowMaximizeVertical();
void slotWindowMaximizeHorizontal();
@ -662,6 +667,7 @@ private:
static Workspace* _self;
bool workspaceInit;
bool m_bTabletMode;
QScopedPointer<KStartupInfo> m_startup;
QScopedPointer<ColorMapper> m_colorMapper;

View File

@ -1946,6 +1946,50 @@ QStringList X11Client::activities() const
return AbstractClient::activities();
}
//使工作区其他X11窗口最小化
void X11Client::makeOthersMinimize()
{
printf("X11Client::makeOthersMinimize, takefocus windowType(0):%d, caption:%s, isModal:%d, isMaximizable:%d\n", windowType(), this->caption().toStdString().c_str(), isModal(), isMaximizable());
//平板模式下如果是isModal窗口(如xournal应用); 或者是瞬态的对话框(如归档管理器的新建窗口); 则没必要最小化其他所有未最小化的窗口,或者是新激活的桌面开始菜单和Dock窗口(比如onboard),也不要最小化其他窗口
if (true == this->isUtility()
|| true == this->isModal()
|| (true == this->isDialog() && true == this->isTransient())
|| true == this->isDesktop()
|| true == this->isDock()
|| caption() == "sogouImeService"
)
{
bUnMakeOthersMinimizeFlag = true;
return;
}
if (!(this->getSpecialFlags() == static_cast<unsigned int>(SpecialFlags::DoNotMaximize))) {
this->maximize(MaximizeFull);
}
printf("X11Client::makeOthersMinimize, takefocus windowType(1):%d, caption:%s, isdialog:%d, isMaximizable:%d\n", windowType(), this->caption().toStdString().c_str(), isDialog(), isMaximizable());
//锁屏时,如果当前是屏保窗口,对其他窗口不要最小化。解决在平板模式打开应用,锁屏后再进入桌面,应用窗口最小化问题
if (this->resourceClass() == "ukui-screensaver-default") {
return;
}
for (X11Client *c : workspace()->clientList()) {
bool isIgnoreWindow = (this == c || c->isDock() || skipTaskbar() || c->isDialog() || c->isDesktop());
bool isTabletBgWindow = (c->isUtility() && c->caption() == "ukui-kwin_tablet_background" && c->keepBelow());
//除了自己dock和对话框也没必要最小化
if (isIgnoreWindow || isTabletBgWindow) {
continue;
}
if (false == c->isMinimized()){
printf("X11Client::makeOthersMinimize, minimize unminimized caption:%s\n", c->caption().toStdString().c_str());
c->minimize(true);
}
}
}
/**
* Performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
*/
@ -1969,6 +2013,21 @@ bool X11Client::takeFocus()
}
workspace()->setShouldGetFocus(this);
//如果是平板模式,则其他所有窗口均最小化
if (Workspace::self()->isInTabletMode()){
// 平板模式下,当窗口获得焦点时,如果是固定大小的窗口(除了任务栏),需要将窗口放到屏幕的正中间
if (false == this->isResizable() && false == isDock() && false == isDesktop()) {
Placement::self()->placeCentered(this, workspace()->activeOutput()->geometry());
}
makeOthersMinimize();
} else {
//如果pc切平板前该窗口是还原状态平板切pc后的窗口激活时需将该窗口从最大化切换还原
if (getTabletToPcRestoreFlag()) {
setTabletToPcRestoreFlag(false);
this->maximize(MaximizeRestore);
}
}
bool breakShowingDesktop = !keepAbove();
if (breakShowingDesktop) {
const auto members = group()->members();

View File

@ -45,6 +45,10 @@ enum class Predicate {
InputIdMatch,
};
enum class SpecialFlags {
DoNotMaximize = 0x1 << 0
};
/**
* @todo Remove when the X11 platform support is dropped. This decoration renderer
* will be used if compositing is off.
@ -181,6 +185,7 @@ public:
bool isCloseable() const override; ///< May be closed by the user (May have a close button)
bool takeFocus() override;
void makeOthersMinimize(); //使工作区其他X11窗口最小化
void invalidateDecoration() override;
@ -302,6 +307,9 @@ public:
static void cleanupX11();
void setSpecialFlags(unsigned int specialFlags) {m_specialFlags = specialFlags;}
unsigned int getSpecialFlags() {return m_specialFlags;}
public Q_SLOTS:
void closeWindow() override;
void updateCaption() override;
@ -528,6 +536,10 @@ private:
QRect m_lastFrameGeometry;
QRect m_lastClientGeometry;
QScopedPointer<X11DecorationRenderer> m_decorationRenderer;
bool bUnMakeOthersMinimizeFlag; //不最小化其他窗体标志
unsigned int m_specialFlags = 0;
};
inline xcb_window_t X11Client::wrapperId() const