diff options
Diffstat (limited to 'kstart')
-rw-r--r-- | kstart/LICENSE.readme | 124 | ||||
-rw-r--r-- | kstart/Makefile.am | 21 | ||||
-rw-r--r-- | kstart/kstart.cpp | 404 | ||||
-rw-r--r-- | kstart/kstart.h | 36 | ||||
-rw-r--r-- | kstart/version.h | 1 |
5 files changed, 586 insertions, 0 deletions
diff --git a/kstart/LICENSE.readme b/kstart/LICENSE.readme new file mode 100644 index 000000000..1cc95fd53 --- /dev/null +++ b/kstart/LICENSE.readme @@ -0,0 +1,124 @@ +kstart --- the KDE legacy application starter + +Copyright (C) 1997, 1998 by Matthias Ettrich <ettrich@kde.org> + + The "Artistic License" + + Preamble + + The intent of this document is to state the conditions under which a + Package may be copied, such that the Copyright Holder maintains some + semblance of artistic control over the development of the package, + while giving the users of the package the right to use and + distribute the Package in a more-or-less customary fashion, plus the + right to make reasonable modifications. + + Definitions: + + * "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + * "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of + the Copyright Holder. + + * "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + * "You" is you, if you're thinking about copying or distributing + this Package. + + * "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people + involved, and so on. (You will not be required to justify it to + the Copyright Holder, but only to the computing community at + large as a market that must bear the fee.) + + * "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + + 1. You may make and give away verbatim copies of the source form of + the Standard Version of this Package without restriction, provided + that you duplicate all of the original copyright notices and + associated disclaimers. + + 2. You may apply bug fixes, portability fixes and other + modifications derived from the Public Domain or from the Copyright + Holder. A Package modified in such a way shall still be considered + the Standard Version. + + 3. You may otherwise modify your copy of this Package in any way, + provided that you insert a prominent notice in each changed file + stating how and when you changed that file, and provided that you do + at least ONE of the following: + + a) place your modifications in the Public Domain or + otherwise make them Freely Available, such as by posting + said modifications to Usenet or an equivalent medium, or + placing the modifications on a major archive site such as + ftp.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation + or organization. + + c) rename any non-standard executables so the names do not + conflict with standard executables, which must also be + provided, and provide a separate manual page for each + non-standard executable that clearly documents how it + differs from the Standard Version. + + d) make other distribution arrangements with the Copyright + Holder. + + 4. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and + library files, together with instructions (in the manual + page or equivalent) on where to get the Standard Version. + + b) accompany the distribution with the machine-readable + source of the Package with your modifications. + + c) accompany any non-standard executables with their + corresponding Standard Version executables, giving the + non-standard executables non-standard names, and clearly + documenting the differences in manual pages (or + equivalent), together with instructions on where to get + the Standard Version. + + d) make other distribution arrangements with the Copyright + Holder. + + 5. You may charge a reasonable copying fee for any distribution of + this Package. You may charge any fee you choose for support of this + Package. You may not charge a fee for this Package itself. However, + you may distribute this Package in aggregate with other (possibly + commercial) programs as part of a larger (possibly commercial) + software distribution provided that you do not advertise this + Package as a product of your own. + + 6. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever + generated them, and may be sold commercially, and may be aggregated + with this Package. + + 7. C or perl subroutines supplied by you and linked into this + Package shall not be considered part of this Package. + + 8. The name of the Copyright Holder may not be used to endorse or + promote products derived from this software without specific prior + written permission. + + 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End + + diff --git a/kstart/Makefile.am b/kstart/Makefile.am new file mode 100644 index 000000000..01aeca492 --- /dev/null +++ b/kstart/Makefile.am @@ -0,0 +1,21 @@ +####### Fiddle here + +AM_CPPFLAGS = -DQT_NO_CAST_ASCII -DQT_CLEAN_NAMESPACE -DQT_NO_COMPAT + +INCLUDES = $(all_includes) + +####### Files + +bin_PROGRAMS = kstart +kstart_SOURCES = kstart.cpp +kstart_LDFLAGS = $(all_libraries) $(KDE_RPATH) +kstart_LDADD = $(LIB_KDECORE) +METASOURCES = kstart.moc + +noinst_HEADERS = kstart.h version.h + +messages: + $(XGETTEXT) $(kstart_SOURCES) -o $(podir)/kstart.pot + +EXTRA_DIST = CHANGES LICENSE.readme + diff --git a/kstart/kstart.cpp b/kstart/kstart.cpp new file mode 100644 index 000000000..83105c86d --- /dev/null +++ b/kstart/kstart.cpp @@ -0,0 +1,404 @@ +/* + * kstart.C. Part of the KDE project. + * + * Copyright (C) 1997-2000 Matthias Ettrich <ettrich@kde.org> + * + * First port to NETWM by David Faure <faure@kde.org> + * Send to system tray by Richard Moore <rich@kde.org> + */ + +#include "kstart.moc" +#include "version.h" + +#include <fcntl.h> +#include <stdlib.h> + +#include <qregexp.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kprocess.h> +#include <klocale.h> +#include <kwin.h> +#include <kwinmodule.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kstartupinfo.h> +#include <kxmessages.h> + +#include <netwm.h> + + +// some globals + +static KProcess proc; +static QCString windowtitle = 0; +static QCString windowclass = 0; +static int desktop = 0; +static bool activate = false; +static bool iconify = false; +static bool toSysTray = false; +static bool fullscreen = false; +static unsigned long state = 0; +static unsigned long mask = 0; +static NET::WindowType windowtype = NET::Unknown; +static KWinModule* kwinmodule; + +KStart::KStart() + :QObject() +{ + NETRootInfo i( qt_xdisplay(), NET::Supported ); + bool useRule = !toSysTray && i.isSupported( NET::WM2KDETemporaryRules ); + + if( useRule ) + sendRule(); + else { + // connect to window add to get the NEW windows + connect(kwinmodule, SIGNAL(windowAdded(WId)), SLOT(windowAdded(WId))); + if (windowtitle) + kwinmodule->doNotManage( windowtitle ); + } + // propagate the app startup notification info to the started app + KStartupInfoId id; + id.initId( kapp->startupId()); + id.setupStartupEnv(); + + //finally execute the comand + if( proc.start(KProcess::DontCare) ) { + KStartupInfoData data; + data.addPid( proc.pid() ); + QCString bin = proc.args().first(); + data.setName( bin ); + data.setBin( bin.mid( bin.findRev( '/' ) + 1 )); + KStartupInfo::sendChange( id, data ); + } + else + KStartupInfo::sendFinish( id ); // failed to start + + QTimer::singleShot( useRule ? 0 : 120 * 1000, kapp, SLOT( quit())); +} + +void KStart::sendRule() { + KXMessages msg; + QCString message; + if( windowtitle ) + message += "title=" + windowtitle + "\ntitlematch=3\n"; // 3 = regexp match + if( windowclass ) + message += "wmclass=" + windowclass + "\nwmclassmatch=1\n" // 1 = exact match + + "wmclasscomplete=" + // if windowclass contains a space (i.e. 2 words, use whole WM_CLASS) + + ( windowclass.contains( ' ' ) ? "true" : "false" ) + "\n"; + if( windowtitle || windowclass ) { + // always ignore these window types + message += "types=" + QCString().setNum( -1U & + ~( NET::TopMenuMask | NET::ToolbarMask | NET::DesktopMask | NET::SplashMask | NET::MenuMask )) + "\n"; + } else { + // accept only "normal" windows + message += "types=" + QCString().setNum( NET::NormalMask | NET::DialogMask ) + "\n"; + } + if ( ( desktop > 0 && desktop <= kwinmodule->numberOfDesktops() ) + || desktop == NETWinInfo::OnAllDesktops ) { + message += "desktop=" + QCString().setNum( desktop ) + "\ndesktoprule=3\n"; + } + if (activate) + message += "fsplevel=0\nfsplevelrule=2\n"; + if (iconify) + message += "minimize=true\nminimizerule=3\n"; + if ( windowtype != NET::Unknown ) { + message += "type=" + QCString().setNum( windowtype ) + "\ntyperule=2"; + } + if ( state ) { + if( state & NET::KeepAbove ) + message += "above=true\naboverule=3\n"; + if( state & NET::KeepBelow ) + message += "below=true\nbelowrule=3\n"; + if( state & NET::SkipTaskbar ) + message += "skiptaskbar=true\nskiptaskbarrule=3\n"; + if( state & NET::SkipPager ) + message += "skippager=true\nskippagerrule=3\n"; + if( state & NET::MaxVert ) + message += "maximizevert=true\nmaximizevertrule=3\n"; + if( state & NET::MaxHoriz ) + message += "maximizehoriz=true\nmaximizehorizrule=3\n"; + if( state & NET::FullScreen ) + message += "fullscreen=true\nfullscreenrule=3\n"; + } + + msg.broadcastMessage( "_KDE_NET_WM_TEMPORARY_RULES", message, -1, false ); + kapp->flushX(); +} + +const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask + | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask + | NET::UtilityMask | NET::SplashMask; + +void KStart::windowAdded(WId w){ + + KWin::WindowInfo info = KWin::windowInfo( w ); + + // always ignore these window types + if( info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::TopMenu + || info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Toolbar + || info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Desktop ) + return; + + if ( windowtitle ) { + QString title = info.name().lower(); + QRegExp r( windowtitle.lower()); + if (r.match(title) == -1) + return; // no match + } + if ( windowclass ) { + XClassHint hint; + if( !XGetClassHint( qt_xdisplay(), w, &hint )) + return; + QCString cls = windowclass.contains( ' ' ) + ? QCString( hint.res_name ) + ' ' + hint.res_class : QCString( hint.res_class ); + cls = cls.lower(); + XFree( hint.res_name ); + XFree( hint.res_class ); + if( cls != windowclass ) + return; + } + if( !windowtitle && !windowclass ) { + // 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; + } + applyStyle( w ); + QApplication::exit(); +} + + +extern Atom qt_wm_state; // defined in qapplication_x11.cpp +static bool wstate_withdrawn( WId winid ) +{ + Atom type; + int format; + unsigned long length, after; + unsigned char *data; + int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2, + FALSE, AnyPropertyType, &type, &format, + &length, &after, &data ); + bool withdrawn = TRUE; + if ( r == Success && data && format == 32 ) { + Q_UINT32 *wstate = (Q_UINT32*)data; + withdrawn = (*wstate == WithdrawnState ); + XFree( (char *)data ); + } + return withdrawn; +} + + +void KStart::applyStyle(WId w ) { + + if ( toSysTray || state || iconify || windowtype != NET::Unknown || desktop >= 1 ) { + + XWithdrawWindow(qt_xdisplay(), w, qt_xscreen()); + QApplication::flushX(); + + while ( !wstate_withdrawn(w) ) + ; + } + + NETWinInfo info( qt_xdisplay(), w, qt_xrootwin(), NET::WMState ); + + if ( ( desktop > 0 && desktop <= kwinmodule->numberOfDesktops() ) + || desktop == NETWinInfo::OnAllDesktops ) + info.setDesktop( desktop ); + + if (iconify) { + XWMHints * hints = XGetWMHints(qt_xdisplay(), w ); + if (hints ) { + hints->flags |= StateHint; + hints->initial_state = IconicState; + XSetWMHints( qt_xdisplay(), w, hints ); + XFree(hints); + } + } + + if ( windowtype != NET::Unknown ) { + info.setWindowType( windowtype ); + } + + if ( state ) + info.setState( state, mask ); + + if ( toSysTray ) { + QApplication::beep(); + KWin::setSystemTrayWindowFor( w, qt_xrootwin() ); + } + + if ( fullscreen ) { + QRect r = QApplication::desktop()->geometry(); + XMoveResizeWindow( qt_xdisplay(), w, r.x(), r.y(), r.width(), r.height() ); + } + + + XSync(qt_xdisplay(), False); + + XMapWindow(qt_xdisplay(), w ); + XSync(qt_xdisplay(), False); + + if (activate) + KWin::forceActiveWindow( w ); + + QApplication::flushX(); +} + +// David, 05/03/2000 +static KCmdLineOptions options[] = +{ + { "!+command", I18N_NOOP("Command to execute"), 0 }, + // "!" means: all options after command are treated as arguments to the command + { "window <regexp>", I18N_NOOP("A regular expression matching the window title"), 0 }, + { "windowclass <class>", I18N_NOOP("A string matching the window class (WM_CLASS property)\n" + "The window class can be found out by running\n" + "'xprop | grep WM_CLASS' and clicking on a window\n" + "(use either both parts separated by a space or only the right part).\n" + "NOTE: If you specify neither window title nor window class,\n" + "then the very first window to appear will be taken;\n" + "omitting both options is NOT recommended."), 0 }, + { "desktop <number>", I18N_NOOP("Desktop on which to make the window appear"), 0 }, + { "currentdesktop", I18N_NOOP("Make the window appear on the desktop that was active\nwhen starting the application"), 0 }, + { "alldesktops", I18N_NOOP("Make the window appear on all desktops"), 0 }, + { "iconify", I18N_NOOP("Iconify the window"), 0 }, + { "maximize", I18N_NOOP("Maximize the window"), 0 }, + { "maximize-vertically", I18N_NOOP("Maximize the window vertically"), 0 }, + { "maximize-horizontally", I18N_NOOP("Maximize the window horizontally"), 0 }, + { "fullscreen", I18N_NOOP("Show window fullscreen"), 0 }, + { "type <type>", I18N_NOOP("The window type: Normal, Desktop, Dock, Tool, \nMenu, Dialog, TopMenu or Override"), 0 }, + { "activate", I18N_NOOP("Jump to the window even if it is started on a \n" + "different virtual desktop"), 0 }, + { "ontop", 0, 0 }, + { "keepabove", I18N_NOOP("Try to keep the window above other windows"), 0 }, + { "onbottom", 0, 0 }, + { "keepbelow", I18N_NOOP("Try to keep the window below other windows"), 0 }, + { "skiptaskbar", I18N_NOOP("The window does not get an entry in the taskbar"), 0 }, + { "skippager", I18N_NOOP("The window does not get an entry on the pager"), 0 }, + { "tosystray", I18N_NOOP("The window is sent to the system tray in Kicker"), 0 }, + KCmdLineLastOption +}; + +int main( int argc, char *argv[] ) +{ + // David, 05/03/2000 + KAboutData aboutData( "kstart", I18N_NOOP("KStart"), KSTART_VERSION, + I18N_NOOP("" + "Utility to launch applications with special window properties \n" + "such as iconified, maximized, a certain virtual desktop, a special decoration\n" + "and so on." ), + KAboutData::License_GPL, + "(C) 1997-2000 Matthias Ettrich (ettrich@kde.org)" ); + + aboutData.addAuthor( "Matthias Ettrich", 0, "ettrich@kde.org" ); + aboutData.addAuthor( "David Faure", 0, "faure@kde.org" ); + aboutData.addAuthor( "Richard J. Moore", 0, "rich@kde.org" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication app; + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if ( args->count() == 0 ) + KCmdLineArgs::usage(i18n("No command specified")); + + for(int i=0; i < args->count(); i++) + proc << args->arg(i); + + kwinmodule = new KWinModule; + + desktop = args->getOption( "desktop" ).toInt(); + if ( args->isSet ( "alldesktops") ) + desktop = NETWinInfo::OnAllDesktops; + if ( args->isSet ( "currentdesktop") ) + desktop = kwinmodule->currentDesktop(); + + windowtitle = args->getOption( "window" ); + windowclass = args->getOption( "windowclass" ); + if( windowclass ) + windowclass = windowclass.lower(); + + if( windowtitle.isEmpty() && windowclass.isEmpty()) + kdWarning() << "Omitting both --window and --windowclass arguments is not recommended" << endl; + + QCString s = args->getOption( "type" ); + if ( !s.isEmpty() ) { + s = s.lower(); + if ( s == "desktop" ) + windowtype = NET::Desktop; + else if ( s == "dock" ) + windowtype = NET::Dock; + else if ( s == "tool" ) + windowtype = NET::Tool; + else if ( s == "menu" ) + windowtype = NET::Menu; + else if ( s == "dialog" ) + windowtype = NET::Dialog; + else if ( s == "override" ) + windowtype = NET::Override; + else if ( s == "topmenu" ) + windowtype = NET::TopMenu; + else + windowtype = NET::Normal; + } + + if ( args->isSet( "keepabove" ) ) { + state |= NET::KeepAbove; + mask |= NET::KeepAbove; + } else if ( args->isSet( "keepbelow" ) ) { + state |= NET::KeepBelow; + mask |= NET::KeepBelow; + } + + if ( args->isSet( "skiptaskbar" ) ) { + state |= NET::SkipTaskbar; + mask |= NET::SkipTaskbar; + } + + if ( args->isSet( "skippager" ) ) { + state |= NET::SkipPager; + mask |= NET::SkipPager; + } + + activate = args->isSet("activate"); + + if ( args->isSet("maximize") ) { + state |= NET::Max; + mask |= NET::Max; + } + if ( args->isSet("maximize-vertically") ) { + state |= NET::MaxVert; + mask |= NET::MaxVert; + } + if ( args->isSet("maximize-horizontally") ) { + state |= NET::MaxHoriz; + mask |= NET::MaxHoriz; + } + + iconify = args->isSet("iconify"); + toSysTray = args->isSet("tosystray"); + if ( args->isSet("fullscreen") ) { + NETRootInfo i( qt_xdisplay(), NET::Supported ); + if( i.isSupported( NET::FullScreen )) { + state |= NET::FullScreen; + mask |= NET::FullScreen; + } else { + windowtype = NET::Override; + fullscreen = true; + } + } + + fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, 1); + args->clear(); + + KStart start; + + return app.exec(); +} diff --git a/kstart/kstart.h b/kstart/kstart.h new file mode 100644 index 000000000..0b5013387 --- /dev/null +++ b/kstart/kstart.h @@ -0,0 +1,36 @@ +/* + * kstart.h Part of the KDE project. + * + * Copyright (C) 1997-2000 Matthias Ettrich <ettrich@kde.org> + * + * Port to NETWM by David Faure <faure@kde.org> + * + */ + +#ifndef KSTART_H +#define KSTART_H + + +#include <qobject.h> + +class KWinModule; + +class KStart: public QObject { + Q_OBJECT + +public: + KStart(); + ~KStart(){}; + +public slots: + void windowAdded(WId); + +private: + + void applyStyle(WId ); + void sendRule(); + +}; + +#endif + diff --git a/kstart/version.h b/kstart/version.h new file mode 100644 index 000000000..3c866e946 --- /dev/null +++ b/kstart/version.h @@ -0,0 +1 @@ +#define KSTART_VERSION "kstart version 1.92" |