// systray.h // // Copyright (C) 2000 Neil Stevens // Copyright (C) 1999 Charles Samuels // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name(s) of the author(s) shall not be // used in advertising or otherwise to promote the sale, use or other dealings // in this Software without prior written authorization from the author(s). #ifdef HAVE_CONFIG_H #include #endif #include "systray.h" #include "kitsystemtray.h" #include "cmodule.h" #include "yhconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO: Maybe make this value configurable? const int COVER_MAXW = 128; const int COVER_MAXH = 128; #define BASEICON "noatun" // From JuK class PassivePopup : public KPassivePopup { public: PassivePopup(TQWidget *parent = 0, const char *name = 0) : KPassivePopup(parent, name) {} protected: virtual void enterEvent(TQEvent *) { setTimeout(3000000); // Make timeout damn near infinite } virtual void leaveEvent(TQEvent *) { setTimeout(250); // Close quickly } }; //NoatunSystray *NoatunSystray::self = 0; NoatunSystray::NoatunSystray() : KMainWindow(0, "NoatunSystray"), Plugin(), mTray(0), traytqStatus(0), trayBase(0), mPassivePopup(0L) { //self = this; hide(); tmpCoverPath = locateLocal("tmp", "youngHickoryCover.png"); removeCover(); // make sure any old temp cover is gone KStdAction::quit(TQT_TQOBJECT(napp), TQT_SLOT(quit()), actionCollection()); KStdAction::open(TQT_TQOBJECT(napp), TQT_SLOT(fileOpen()), actionCollection()); KStdAction::preferences(TQT_TQOBJECT(napp), TQT_SLOT(preferences()), actionCollection()); NoatunStdAction::back(actionCollection(), "back"); NoatunStdAction::stop(actionCollection(), "stop"); NoatunStdAction::playpause(actionCollection(), "play"); NoatunStdAction::forward(actionCollection(), "forward"); NoatunStdAction::playlist(actionCollection(), "show_playlist"); NoatunStdAction::loop(actionCollection(), "loop_style"); NoatunStdAction::effects(actionCollection(), "effects"); NoatunStdAction::equalizer(actionCollection(), "equalizer"); createGUI("systrayui.rc"); mTray = new KitSystemTray("tray", this); mTray->show(); trayBase = renderIcon(BASEICON, TQString()); traytqStatus = renderIcon(BASEICON, "player_stop"); mTray->changeTitle(*trayBase, i18n("Noatun")); showingTraytqStatus = false; mBlinkTimer = new TQTimer(this); connect(mBlinkTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotBlinkTimer())); connect(napp->player(), TQT_SIGNAL(playing()), this, TQT_SLOT(slotPlayPause())); connect(napp->player(), TQT_SIGNAL(paused()), this, TQT_SLOT(slotPlayPause())); connect(napp->player(), TQT_SIGNAL(stopped()), this, TQT_SLOT(slotStopped())); //napp->player()->handleButtons(); } NoatunSystray::~NoatunSystray() { //kdDebug(66666) << k_funcinfo << "Called." << endl; removeCover(); delete trayBase; delete traytqStatus; napp->showInterfaces(); } void NoatunSystray::init() { YHModule *cmod = new YHModule(TQT_TQOBJECT(this)); connect(cmod, TQT_SIGNAL(saved()), this, TQT_SLOT(slotLoadSettings())); slotLoadSettings(); } void NoatunSystray::slotLoadSettings() { kdDebug(66666) << k_funcinfo << endl; YHConfig *c = YHConfig::self(); if(c->stateIconDisplay() == YHConfig::FlashingIcon) mBlinkTimer->start(1000); else mBlinkTimer->stop(); slotBlinkTimer(); if(c->tip()) TQToolTip::add(mTray, tipText); else TQToolTip::remove(mTray); if (!c->passivePopupCovers()) removeCover(); if(c->passivePopup()) { mPassivePopup = new PassivePopup(mTray, "NoatunPassivePopup"); } else { delete mPassivePopup; mPassivePopup = 0L; } } void NoatunSystray::closeEvent(TQCloseEvent*) { //kdDebug(66666) << k_funcinfo << "Called." << endl; disconnect(napp->player(), 0, 0, 0); unload(); } void NoatunSystray::slotPlayPause() { TQString status; if(napp->player()->isPaused()) { changeTray("player_pause"); status = i18n("Noatun - Paused"); } else { changeTray("player_play"); status = i18n("Noatun - Playing"); } const PlaylistItem item = napp->player()->current(); TQString s; if(!item.isProperty("title")) { // No metadata s = TQString("%1").tqarg(item.title()); } else { s = TQString("

%1

").tqarg(item.property("title")); if(item.isProperty("author")) s += TQString("%1
").tqarg(item.property("author")); if(item.isProperty("album")) { if(item.isProperty("date")) s += TQString("%1 (%2)
").tqarg(item.property("album")).tqarg(item.property("date")); else s += TQString("%1
").tqarg(item.property("album")); } } // prepare cover image for display if (YHConfig::self()->passivePopupCovers()) updateCover(); if(YHConfig::self()->passivePopupCovers() && TQFile::exists(tmpCoverPath)) { // QT always adds an empty line after the table so we add en empty line before the // table to get equal spacing on top and bottom setTipText(TQString("
" \ "" \ "" \ "

%1

%2
").tqarg(status).tqarg(s).tqarg(tmpCoverPath)); } else { setTipText(TQString("

%1

%2
").tqarg(status).tqarg(s)); } } void NoatunSystray::slotStopped() { if(!napp->player()->current()) return; changeTray("player_stop"); setTipText(TQString("

%1

").tqarg(i18n("Noatun - Stopped"))); } void NoatunSystray::changeTray(const TQString &pm) { delete traytqStatus; traytqStatus = renderIcon(BASEICON, pm); if(showingTraytqStatus) slotBlinkTimer(); } void NoatunSystray::slotBlinkTimer() { switch(YHConfig::self()->stateIconDisplay()) { case (YHConfig::FlashingIcon): showingTraytqStatus ^= true; break; case (YHConfig::StaticIcon): showingTraytqStatus = true; break; case (YHConfig::NoIcon): showingTraytqStatus = false; break; } if(showingTraytqStatus) mTray->setPixmap(*traytqStatus); else mTray->setPixmap(*trayBase); } // taken from patched karamba xmmssensor // modified heavily to work in this place void NoatunSystray::updateCover() { //kdDebug(66666) << k_funcinfo << endl; TQString dir = napp->player()->current().url().directory(); TQString cover; // TODO: Maybe make these filenames configurable? if(TQFile::exists(dir + "/folder.png")) cover = dir + "/folder.png"; else if(TQFile::exists(dir + "/.folder.png")) cover = dir + "/.folder.png"; else if(TQFile::exists(dir + "/cover.png")) cover = dir + "/cover.png"; else if(TQFile::exists(dir + "/cover.jpg")) cover = dir + "/cover.jpg"; else if(TQFile::exists(dir + "/cover.jpeg")) cover = dir + "/cover.jpeg"; else // no cover { //kdDebug(66666) << k_funcinfo << "NO COVER" << endl; removeCover(); return; } TQString title = napp->player()->current().title(); TQImage previmg; previmg.load(tmpCoverPath); if(previmg.text("Title") != title) { //Verify song change to limit CPU usage /*kdDebug(66666) << k_funcinfo << "Creating new temp cover for '" << cover << "'" << endl;*/ TQImage src; TQImage tmpimg; if(src.load(cover)) { if(src.width() >= COVER_MAXW || src.height() >= COVER_MAXH) tmpimg = src.scale(COVER_MAXW, COVER_MAXH, TQ_ScaleMin); else tmpimg = src; tmpimg.setText("Title", 0, title); //add Title in the image text for cache usage tmpimg.save(tmpCoverPath, "PNG", 0); } else { removeCover(); } } } void NoatunSystray::removeCover() { if(TQFile::exists(tmpCoverPath)) KIO::NetAccess::del(KURL(tmpCoverPath), this); } void NoatunSystray::setTipText(const TQString& text) { if(text == tipText) // save the planet, save cpu cycles ;) return; tipText = text; YHConfig *c = YHConfig::self(); if(c->passivePopup()) TQTimer::singleShot(0, this, TQT_SLOT(showPassivePopup())); if(c->tip()) TQToolTip::add(mTray, tipText); } void NoatunSystray::showPassivePopup() { if (!mPassivePopup) { kdDebug(66666) << k_funcinfo << "Called but no KPassivePopup created yet!" << endl; return; } mPassivePopup->reparent(0L, TQPoint(0,0)); if (YHConfig::self()->passivePopupButtons() && !napp->player()->isStopped()) { TQVBox *widget = mPassivePopup->standardView(TQString(), tipText, TQPixmap()); TQHBox *box = new TQHBox(mPassivePopup, "popupbox"); box->setSpacing(8); // Algorithm for determining popup location from kpassivepopup.cpp via JuK NETWinInfo ni(qt_xdisplay(), mTray->winId(), qt_xrootwin(), NET::WMIconGeometry | NET::WMKDESystemTrayWinFor); NETRect frame, win; ni.kdeGeometry(frame, win); TQRect bounds = KGlobalSettings::desktopGeometry(TQPoint(win.pos.x, win.pos.y)); if(win.pos.x < bounds.center().x()) { // Buttons to the left TQVBox *buttonBox = new TQVBox(box); buttonBox->setSpacing(3); TQPushButton *forwardButton = new TQPushButton(action("forward")->iconSet(), 0, buttonBox, "popup_forward"); forwardButton->setFlat(true); connect(forwardButton, TQT_SIGNAL(clicked()), action("forward"), TQT_SLOT(activate())); TQPushButton *backButton = new TQPushButton(action("back")->iconSet(), 0, buttonBox, "popup_back"); backButton->setFlat(true); connect(backButton, TQT_SIGNAL(clicked()), action("back"), TQT_SLOT(activate())); TQFrame *line = new TQFrame(box); line->setFrameShape(TQFrame::VLine); widget->reparent(box, TQPoint(0, 0)); } else { // Buttons to the right widget->reparent(box, TQPoint(0, 0)); TQFrame *line = new TQFrame(box); line->setFrameShape(TQFrame::VLine); TQVBox *buttonBox = new TQVBox(box); buttonBox->setSpacing(3); TQPushButton *forwardButton = new TQPushButton(action("forward")->iconSet(), 0, buttonBox, "popup_forward"); forwardButton->setFlat(true); connect(forwardButton, TQT_SIGNAL(clicked()), action("forward"), TQT_SLOT(activate())); TQPushButton *backButton = new TQPushButton(action("back")->iconSet(), 0, buttonBox, "popup_back"); backButton->setFlat(true); connect(backButton, TQT_SIGNAL(clicked()), action("back"), TQT_SLOT(activate())); } mPassivePopup->setView(box); } else { mPassivePopup->setView(TQString(), tipText); } mPassivePopup->setTimeout(YHConfig::self()->passivePopupTimeout()*1000); mPassivePopup->show(); } TQPixmap *NoatunSystray::renderIcon(const TQString& baseIcon, const TQString &overlayIcon) const { TQPixmap *base = new TQPixmap(KSystemTray::loadIcon(baseIcon)); if(!(overlayIcon.isNull())) // otherwise leave the base as-is { TQPixmap overlay = KSystemTray::loadIcon(overlayIcon); if(!overlay.isNull()) { // draw the overlay on top of it TQPainter p(base); p.drawPixmap(0, 0, overlay); } } return base; } #include "systray.moc"