ksystraycmd: drop it and use the new tray argument of KApplication

see the following commit in kdelibs repo:
4b632fcae67da3b95e69e954fa2e581a42f4c53c

currently enabled only for a few applications until more tests are done

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-08-24 01:44:44 +03:00
parent 69f7efcce1
commit 3f85de5864
11 changed files with 19 additions and 659 deletions

View file

@ -293,7 +293,6 @@ endif(Q_WS_X11 AND X11_Xinput_FOUND)
add_subdirectory(kcminit)
add_subdirectory(khotkeys)
add_subdirectory(ksystraycmd)
if (LightDM_FOUND)
add_subdirectory(kgreeter)

View file

@ -188,3 +188,4 @@ MimeType=inode/directory;
InitialPreference=10
StartupNotify=true
X-KDE-MediaPlayer=informationpanel
X-KDE-SysTray=true

View file

@ -121,6 +121,7 @@ MimeType=text/plain;
Exec=kate --icon '%i' --caption '%c' -b %U
StartupNotify=true
X-KDE-HasTempFileOption=true
X-KDE-SysTray=true
Icon=kate
X-DocPath=kate/index.html
Type=Application

View file

@ -97,3 +97,4 @@ Name[zh_TW]=尋找檔案/資料夾
StartupNotify=true
OnlyShowIn=KDE;
Categories=Qt;KDE;Core;
X-KDE-SysTray=true

View file

@ -35,6 +35,7 @@
#include <KDesktopFile>
#include <KUrlRequester>
#include <KShell>
#include <KDebug>
#include "khotkeys.h"
@ -269,9 +270,9 @@ void BasicTab::enableWidgets(bool isDF, bool isDeleted)
_iconButton->setEnabled(!isDeleted);
_execEdit->setEnabled(isDF && !isDeleted);
_launchCB->setEnabled(isDF && !isDeleted);
_systrayCB->setEnabled(isDF && !isDeleted);
_onlyShowInKdeCB->setEnabled( isDF && !isDeleted );
_hiddenEntryCB->setEnabled( isDF && !isDeleted );
// _systrayCB->setEnabled(isDF && !isDeleted);
_onlyShowInKdeCB->setEnabled(isDF && !isDeleted);
_hiddenEntryCB->setEnabled(isDF && !isDeleted);
_nameLabel->setEnabled(!isDeleted);
_descriptionLabel->setEnabled(!isDeleted);
_commentLabel->setEnabled(!isDeleted);
@ -280,7 +281,7 @@ void BasicTab::enableWidgets(bool isDF, bool isDeleted)
_path_group->setEnabled(isDF && !isDeleted);
_term_group->setEnabled(isDF && !isDeleted);
_uid_group->setEnabled(isDF && !isDeleted);
general_group_keybind->setEnabled( isDF && !isDeleted );
general_group_keybind->setEnabled(isDF && !isDeleted);
_termOptEdit->setEnabled(isDF && !isDeleted && _terminalCB->isChecked());
_termOptLabel->setEnabled(isDF && !isDeleted && _terminalCB->isChecked());
@ -369,10 +370,11 @@ void BasicTab::setEntryInfo(MenuEntryInfo *entryInfo)
else
_keyEdit->clearKeySequence();
}
QString temp = df->desktopGroup().readEntry("Exec");
if (temp.startsWith(QLatin1String("ksystraycmd ")))
if (temp.endsWith(QLatin1String(" -tray")))
{
_execEdit->lineEdit()->setText(temp.right(temp.length()-12));
_execEdit->lineEdit()->setText(temp.left(temp.length()-6));
_systrayCB->setChecked(true);
}
else
@ -380,6 +382,7 @@ void BasicTab::setEntryInfo(MenuEntryInfo *entryInfo)
_execEdit->lineEdit()->setText(temp);
_systrayCB->setChecked(false);
}
_systrayCB->setEnabled(df->desktopGroup().readEntry("X-KDE-SysTray", false));
_pathEdit->lineEdit()->setText(df->readPath());
_termOptEdit->setText(df->desktopGroup().readEntry("TerminalOptions"));
@ -387,12 +390,13 @@ void BasicTab::setEntryInfo(MenuEntryInfo *entryInfo)
_launchCB->setChecked(df->desktopGroup().readEntry("StartupNotify", false));
_onlyShowInKdeCB->setChecked( df->desktopGroup().readXdgListEntry("OnlyShowIn").contains( "KDE" ) ); // or maybe enable only if it contains nothing but KDE?
// or maybe enable only if it contains nothing but KDE?
_onlyShowInKdeCB->setChecked( df->desktopGroup().readXdgListEntry("OnlyShowIn").contains("KDE"));
if ( df->desktopGroup().hasKey( "NoDisplay" ) )
_hiddenEntryCB->setChecked( df->desktopGroup().readEntry( "NoDisplay", true ) );
if ( df->desktopGroup().hasKey("NoDisplay"))
_hiddenEntryCB->setChecked(df->desktopGroup().readEntry("NoDisplay", true));
else
_hiddenEntryCB->setChecked( false );
_hiddenEntryCB->setChecked(false);
if(df->desktopGroup().readEntry("Terminal", 0) == 1)
_terminalCB->setChecked(true);
@ -417,8 +421,8 @@ void BasicTab::apply()
KDesktopFile *df = _menuEntryInfo->desktopFile();
KConfigGroup dg = df->desktopGroup();
dg.writeEntry("Comment", _commentEdit->text());
if (_systrayCB->isChecked())
dg.writeEntry("Exec", _execEdit->lineEdit()->text().prepend("ksystraycmd "));
if (_systrayCB->isEnabled() && _systrayCB->isChecked())
dg.writeEntry("Exec", _execEdit->lineEdit()->text().append(" -tray"));
else
dg.writeEntry("Exec", _execEdit->lineEdit()->text());

View file

@ -1,12 +0,0 @@
set(ksystraycmd_SRCS ksystraycmd.cpp main.cpp )
add_executable(ksystraycmd ${ksystraycmd_SRCS})
target_link_libraries(ksystraycmd
KDE4::kdeui
${X11_X11_LIB}
)
install(
TARGETS ksystraycmd
DESTINATION ${KDE4_BIN_INSTALL_DIR}
)

View file

@ -1,2 +0,0 @@
#!/bin/bash
$XGETTEXT *.cpp -o $podir/ksystraycmd.pot

View file

@ -1,29 +0,0 @@
README for KSysTrayCmd
======================
Introduction
============
KSysTrayCmd is a utility that allows you to run any application you
like in the system tray, not just those designed to use it.
Examples
========
ksystraycmd --window 'kmail' kmail
ksystraycmd --startonshow --icon logfile --tooltip 'X Log' --hidden --window 'X Log' \
konsole --icon logfile --caption 'X Log' -e 'less -M ~/.xsession-errors'
More Information
================
I'm currently writing an article for the dot which will describe the
usage of both kstart and ksystraycmd in more detail, the text of the
article will be used to improve this document.
Richard Moore
rich@kde.org

View file

@ -1,379 +0,0 @@
#include <QTextStream>
#include <QImage>
#include <QRegExp>
#include <QtGui/qevent.h>
#include <kdebug.h>
#include <kapplication.h>
#include <kglobal.h>
#include <kicon.h>
#include <klocale.h>
#include <kmenu.h>
#include <kprocess.h>
#include <kwindowsystem.h>
#include <kconfig.h>
#include <ksystemtrayicon.h>
#include <kconfiggroup.h>
#include <kaboutdata.h>
#include <netwm.h>
#include "ksystraycmd.h"
#include "moc_ksystraycmd.cpp"
#include <QtGui/qx11info_x11.h>
KSysTrayCmd::KSysTrayCmd()
: KSystemTrayIcon( static_cast<QWidget*>(0) ),
isVisible(true), lazyStart( false ), noquit( false ),
quitOnHide( false ), onTop(false), ownIcon(false),
waitingForWindow( false ),
win(0), client(0), top(0), left(0)
{
connect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
menu = new KMenu();
setContextMenu(menu);
connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(mousePressEvent(QSystemTrayIcon::ActivationReason)));
refresh();
}
KSysTrayCmd::~KSysTrayCmd()
{
delete menu;
if( client )
{
if( client->state() == QProcess::Running )
{
client->terminate();
client->kill();
client->waitForFinished( 5000 );
}
delete client;
}
}
//
// Main entry point to the class
//
bool KSysTrayCmd::start()
{
// If we have no command we must catching an existing window
if ( command.isEmpty() ) {
if ( win ) {
setTargetWindow( win );
return true;
}
waitingForWindow = true;
checkExistingWindows();
if ( win ) {
// Window always on top
if (onTop) {
KWindowSystem::setState(win, NET::KeepAbove);
}
return true;
}
errStr = i18n( "No window matching pattern '%1' and no command specified.\n" ,
window );
return false;
}
// Run the command and watch for its window
if ( !startClient() ) {
errStr = i18n( "Cannot start client." );
clientExited();
return false;
}
return true;
}
//
// Window related functions.
//
void KSysTrayCmd::showWindow()
{
isVisible = true;
if ( !win )
return;
XMapWindow( QX11Info::display(), win );
// We move the window to the memorized position
XMoveWindow( QX11Info::display(), win, left, top);
// Window always on top
if (onTop)
{
KWindowSystem::setState(win, NET::KeepAbove);
}
KWindowSystem::activateWindow( win );
}
void KSysTrayCmd::hideWindow()
{
isVisible = false;
if ( !win )
return;
//We memorize the position of the window
left = KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().left();
top=KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().top();
XUnmapWindow( QX11Info::display(), win );
}
void KSysTrayCmd::setTargetWindow( WId w )
{
disconnect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
connect( KWindowSystem::self(), SIGNAL(windowChanged(WId)), SLOT(windowChanged(WId)) );
win = w;
// KWindowSystem::setSystemTrayWindowFor( winId(), win );
refresh();
show();
if ( isVisible )
KWindowSystem::activateWindow( win );
else
hideWindow();
// Always on top ?
if (onTop)
{
KWindowSystem::setState(win, NET::KeepAbove);
}
}
//
// Refresh the tray icon
//
void KSysTrayCmd::refresh()
{
// KWindowSystem::setSystemTrayWindowFor( winId(), win ? win : winId() );
if ( win ) {
if (ownIcon)
{
setIcon( KApplication::windowIcon() );
}
else
{
setIcon( KWindowSystem::icon( win, 22, 22, true ) );
}
if ( tooltip.isEmpty() )
this->setToolTip( KWindowSystem::windowInfo( win, NET::WMName ).name() );
}
else {
if ( !tooltip.isEmpty() )
this->setToolTip( tooltip );
else if ( !command.isEmpty() )
this->setToolTip( command );
else
this->setToolTip( window );
setIcon( KApplication::windowIcon() );
}
}
//
// Client related functions.
//
bool KSysTrayCmd::startClient()
{
kDebug() << "startClient()";
client = new KProcess();
client->setShellCommand( command );
//connect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
waitingForWindow = true;
connect( client, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(clientExited()) );
client->start();
return client->waitForStarted( -1 );
}
void KSysTrayCmd::clientExited()
{
delete client;
client = 0;
win = 0;
waitingForWindow = false;
if ( lazyStart && noquit )
refresh();
else
qApp->quit();
}
void KSysTrayCmd::quitClient()
{
if ( win ) {
// Before sending the close request we have to show the window
XMapWindow( QX11Info::display(), win );
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
ri.closeWindowRequest( win );
win=0;
noquit = false;
// We didn't give command, so we didn't open an application.
// That's why when the application is closed we aren't informed.
// So we quit now.
if ( command.isEmpty() ) {
qApp->quit();
}
}
else {
qApp->quit();
}
}
void KSysTrayCmd::quit()
{
if ( !isVisible ) {
showWindow();
}
qApp->quit();
}
void KSysTrayCmd::execContextMenu( const QPoint &pos )
{
menu->clear();
menu->addTitle( icon(), i18n( "KSysTrayCmd" ) );
QAction * hideShowId = menu->addAction( isVisible ? i18n( "&Hide" ) : i18n( "&Restore" ) );
QAction * undockId = menu->addAction( KIcon("dialog-close"), i18n( "&Undock" ) );
QAction * quitId = menu->addAction( KIcon("application-exit"), i18n( "&Quit" ) );
QAction * cmd = menu->exec( pos );
if ( cmd == quitId )
quitClient();
else if ( cmd == undockId )
quit();
else if ( cmd == hideShowId )
{
if ( lazyStart && ( !hasRunningClient() ) )
{
start();
isVisible=true;
}
else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
{
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
ri.closeWindowRequest( win );
isVisible=false;
}
else
toggleWindow();
}
}
void KSysTrayCmd::checkExistingWindows()
{
kDebug() << "checkExistingWindows()";
QList<WId>::ConstIterator it;
for ( it = KWindowSystem::windows().begin(); it != KWindowSystem::windows().end(); ++it ) {
windowAdded( *it );
if ( win )
break;
}
}
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::UtilityMask | NET::SplashMask;
void KSysTrayCmd::windowAdded(WId w)
{
if ( !waitingForWindow )
return;
KWindowInfo info = KWindowSystem::windowInfo( w, NET::WMWindowType | NET::WMName );
kDebug() << "windowAdded, id" << w << "pattern is " << window << " window is " << info.name();
// always ignore these window types
if( info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Toolbar
|| info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Desktop )
return;
// If we're grabbing the first window we see
if( window.isEmpty() ) {
// accept only "normal" windows
if( info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Unknown
&& info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Normal
&& info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Dialog )
return;
}
else if ( QRegExp( window ).indexIn( info.name() ) == -1 ) {
return;
}
kDebug() << "windowAdded, setting target " << (int) w;
setTargetWindow( w );
}
void KSysTrayCmd::windowChanged( WId w )
{
if ( w != win )
return;
refresh();
}
//
// Tray icon event handlers
//
void KSysTrayCmd::mousePressEvent( QSystemTrayIcon::ActivationReason reason )
{
if ( reason == QSystemTrayIcon::Context )
execContextMenu( QCursor::pos() );
else if ( lazyStart && ( !hasRunningClient() ) )
{
start();
isVisible=true;
}
else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
{
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
ri.closeWindowRequest( win );
isVisible=false;
}
else if ( reason == QSystemTrayIcon::Trigger )
toggleWindow();
}
WId KSysTrayCmd::findRealWindow( WId w, int depth )
{
if( depth > 5 )
return None;
static Atom wm_state = XInternAtom( QX11Info::display(), "WM_STATE", False );
Atom type;
int format;
unsigned long nitems, after;
unsigned char* prop;
if( XGetWindowProperty( QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType,
&type, &format, &nitems, &after, &prop ) == Success ) {
if( prop != NULL )
XFree( prop );
if( type != None )
return w;
}
Window root, parent;
Window* children;
unsigned int nchildren;
Window ret = None;
if( XQueryTree( QX11Info::display(), w, &root, &parent, &children, &nchildren ) != 0 ) {
for( unsigned int i = 0;
i < nchildren && ret == None;
++i )
ret = findRealWindow( children[ i ], depth + 1 );
if( children != NULL )
XFree( children );
}
return ret;
}

View file

@ -1,87 +0,0 @@
// -*- c++ -*-
#ifndef KSYSTRAYCMD_H
#define KSYSTRAYCMD_H
#include <KSystemTrayIcon>
class KProcess;
class KMenu;
/**
* Provides a system tray icon for a normal window.
*
* @author Richard Moore, rich@kde.org
*/
class KSysTrayCmd : public KSystemTrayIcon
{
Q_OBJECT
public:
KSysTrayCmd();
~KSysTrayCmd();
void setWindow( WId w ) { win = w; }
void setCommand( const QString &cmd ) { command = cmd; }
void setPattern( const QString &regexp ) { window = regexp; }
void setStartOnShow( bool enable ) { lazyStart = enable; isVisible = !enable; }
void setNoQuit( bool enable ) { noquit = enable; }
void setQuitOnHide( bool enable ) { quitOnHide = enable; }
void setOnTop( bool enable ) { onTop = enable; }
void setOwnIcon( bool enable ) { ownIcon = enable; }
void setDefaultTip( const QString &tip ) { tooltip = tip; }
bool hasTargetWindow() const { return (win != 0); }
bool hasRunningClient() const { return (client != 0); }
const QString &errorMsg() const { return errStr; }
bool start();
static WId findRealWindow( WId w, int depth = 0 );
public Q_SLOTS:
void refresh();
void showWindow();
void hideWindow();
void toggleWindow() { if ( isVisible ) hideWindow(); else showWindow(); }
void setTargetWindow( WId w );
void execContextMenu( const QPoint &pos );
void quit();
void quitClient();
protected Q_SLOTS:
void clientExited();
void windowAdded(WId w);
void windowChanged(WId w);
void mousePressEvent(QSystemTrayIcon::ActivationReason reason);
protected:
bool startClient();
void checkExistingWindows();
private:
QString command;
QString window;
QString tooltip;
bool isVisible;
bool lazyStart;
bool noquit;
bool quitOnHide;
bool onTop; ///< tells if window must stay on top or not
bool ownIcon; ///< tells if the ksystraycmd icon must be used in systray
bool waitingForWindow;
KMenu * menu;
WId win;
KProcess *client;
QString errStr;
/** Memorized 'top' position of the window*/
int top;
/** Memorized 'left' position of the window*/
int left;
};
#endif // KSYSTRAYCMD_H

View file

@ -1,137 +0,0 @@
#include <fcntl.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kdebug.h>
#include <klocale.h>
#include <kshell.h>
#include "ksystraycmd.h"
#include <X11/Xlib.h>
#include <QtGui/qx11info_x11.h>
#include <fixx11h.h>
int main( int argc, char *argv[] )
{
KAboutData aboutData( "ksystraycmd", 0, ki18n( "KSysTrayCmd" ),
"0.1",
ki18n( "Allows any application to be kept in the system tray" ),
KAboutData::License_GPL,
ki18n("(C) 2001-2002 Richard Moore (rich@kde.org)") );
aboutData.addAuthor( ki18n("Richard Moore"), KLocalizedString(), "rich@kde.org" );
KCmdLineArgs::init( argc, argv, &aboutData );
KCmdLineOptions options;
options.add("!+command", ki18n("Command to execute"));
// "!" means: all options after command are treated as arguments to the command
options.add("window <regexp>", ki18n("A regular expression matching the window title\n"
"If you do not specify one, then the very first window\n"
"to appear will be taken - not recommended."));
options.add("wid <int>", ki18n("The window id of the target window\n"
"Specifies the id of the window to use. If the id starts with 0x\n"
"it is assumed to be in hex."));
options.add("hidden", ki18n( "Hide the window to the tray on startup" ));
options.add("startonshow", ki18n( "Wait until we are told to show the window before\n"
"executing the command" ));
options.add("tooltip <text>", ki18n( "Sets the initial tooltip for the tray icon" ));
options.add("keeprunning", ki18n( "Keep the tray icon even if the client exits. This option\n"
"has no effect unless startonshow is specified." ));
options.add("ownicon", ki18n( "Use ksystraycmd's icon instead of the window's icon in the systray\n"
"(should be used with --icon to specify ksystraycmd icon)" ));
options.add("ontop", ki18n( "Try to keep the window above other windows"));
options.add("quitonhide", ki18n( "Quit the client when we are told to hide the window.\n"
"This has no effect unless startonshow is specified and implies keeprunning." ));
/*options.add("menuitem <item>", ki18n( "Adds a custom entry to the tray icon menu\n"
"The item should have the form text:command." ));*/
KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
KApplication app;
//
// Setup the tray icon from the arguments.
//
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
KSysTrayCmd cmd;
// Read the window id
QString wid = args->getOption( "wid" );
if ( !wid.isEmpty() ) {
int base = 10;
if ( wid.startsWith( "0x" ) ) {
base = 16;
wid = wid.right( wid.length() - 2 );
}
bool ok=true;
ulong w = wid.toULong( &ok, base );
if ( ok )
cmd.setTargetWindow( w );
else {
kWarning() << "KSysTrayCmd: Got bad win id" ;
}
}
// Read window title regexp
QString title = args->getOption( "window" );
if ( !title.isEmpty() )
cmd.setPattern( title );
if ( title.isEmpty() && wid.isEmpty() && (args->count() == 0) )
KCmdLineArgs::usageError(i18n("No command or window specified"));
// Read the command
QString command;
for ( int i = 0; i < args->count(); i++ )
command += KShell::quoteArg(args->arg(i)) + ' ';
if ( !command.isEmpty() )
cmd.setCommand( command );
// Tooltip
QString tip = args->getOption( "tooltip" );
if ( !tip.isEmpty() )
cmd.setDefaultTip( tip );
// Apply icon and tooltip
cmd.refresh();
// Keep running flag
if ( args->isSet( "keeprunning" ) )
cmd.setNoQuit( true );
if ( args->isSet( "quitonhide" ) ) {
cmd.setNoQuit( true );
cmd.setQuitOnHide( true );
}
// Start hidden
if ( args->isSet( "hidden" ) )
cmd.hideWindow();
// On top
if ( args->isSet( "ontop" ) )
cmd.setOnTop(true);
// Use ksystraycmd icon
if ( args->isSet( "ownicon" ) )
cmd.setOwnIcon(true);
// Lazy invocation flag
if ( args->isSet( "startonshow" ) ) {
cmd.setStartOnShow( true );
cmd.show();
}
else {
if ( !cmd.start() )
return 1;
}
fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, 1);
args->clear();
return app.exec();
}