Logo Search packages:      
Sourcecode: kmess version File versions  Download package

systemtraywidget.cpp
/***************************************************************************
                          systemtraywidget.cpp  -  description
                             -------------------
    begin                : Sun Dec 29 2002
    copyright            : (C) 2002 by Mike K. Bennett
    email                : mkb137b@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "systemtraywidget.h"

#include "contact/msnstatus.h"
#include "config-kmess.h"
#include "currentaccount.h"
#include "kmessdebug.h"
#include "utils/kmessshared.h"

#include <QDesktopWidget>
#include <QDir>
#include <QPainter>
#include <QPixmap>
#include <QTemporaryFile>

#include <KApplication>
#include <KIconEffect>
#include <KLocale>
#include <KMessageBox>

#ifdef Q_WS_WIN
#include <windows.h>
#endif



// The constructor
SystemTrayWidget::SystemTrayWidget( QWidget *parent )
 : KSystemTrayIcon( parent )
{
  currentAccount_ = CurrentAccount::instance();

  // Connect the "changed status" and "changed friendly name" signals
  connect( currentAccount_, SIGNAL(       changedStatus() ),
           this,            SLOT  (       statusChanged() ) );
  connect( currentAccount_, SIGNAL( changedFriendlyName() ),
           this,            SLOT  (       statusChanged() ) );

  // Connect email related signals
  connect( currentAccount_, SIGNAL( changedNoEmails() ),
           this,            SLOT  (       statusChanged() ) );
  connect( currentAccount_, SIGNAL( changedEmailDisplaySettings() ),
           this,            SLOT  (       statusChanged() ) );

  // Force changing the icon
  statusChanged();
}



/**
 * Display an Hide On Close dialog window with a trayicon screenshot
 *
 * This method, taken from the Basket Note Pads project (see the related links below), is used when
 * the user closes the main KMess contact list window. Then a custom dialog window is shown to notify
 * that the app will still run in background. This useful method adds to it a screenshot of the system
 * tray area of the users' desktop, highlighting the application's icons.
 * The original code was KDE3, it's been ported to make better use of the new features of Qt4 and KDE4.
 *
 * @see http://basket.kde.org/ - Official site of the Basket Note Pads project
 * @see http://basket.kde.org/systemtray-on-close-info.php - Specific tray dialog page
 */
void SystemTrayWidget::displayCloseMessage( QString /*fileMenu*/ )
{
  // Don't do all the computations if they are unneeded:
  if ( ! KMessageBox::shouldBeShownContinue("hideOnCloseInfo") )
      return;

  const QString message( i18n( "Closing the main window will keep KMess running in the system tray. "
                               "Use 'Quit' from the 'Connect' menu to quit the application." ) );

  // If the system tray is not visible, just show the text message
  if( ! QSystemTrayIcon::isSystemTrayAvailable() || ! isVisible() )
  {
#ifdef KMESSDEBUG_SYSTEMTRAY
    kmDebug() << "Displaying simple dialog with no screenshot.";
#endif

    KMessageBox::information( kapp->activeWindow(), message,
                              i18n( "Docking in System Tray" ),
                              "hideOnCloseInfo" );
    return;
  }

#ifdef KMESSDEBUG_SYSTEMTRAY
  kmDebug() << "Displaying dialog with tray icon screenshot: generating image...";
#endif

  // Get initial position of the tray icon and the the screen size
  QRect pictureArea( geometry() );
  QRect pictureGeometry( geometry() );
  QRect desktopArea = kapp->desktop()->screenGeometry( geometry().topLeft() );

  // Compute the final size and position of the pixmap to grab
  const int xRadius = desktopArea.width() / 8;
  const int yRadius = desktopArea.height() / 16;
  pictureArea.adjust( -xRadius, -yRadius, xRadius, yRadius );


  // Crop the picture if it goes out of screen
  pictureArea = pictureArea.intersected( desktopArea );

  // This translates the geometry of the tray icon into the picture area
  pictureGeometry.translate( -pictureArea.x(), -pictureArea.y() );


#ifdef KMESSDEBUG_SYSTEMTRAY
  kmDebug() << "Creating screenshot from area" << pictureArea << "using a desktop size of" << desktopArea << "and geometry" << pictureGeometry;
#endif

  // Grab an image of the screen which contains the tray icon
  QPixmap shot;
  if( pictureArea.x() == 0 && pictureArea.y() == 0 )
  {
#ifdef Q_WS_X11
    shot = QPixmap::grabWindow( QX11Info::appRootWindow(), pictureArea.x(), pictureArea.y(), pictureArea.width(), pictureArea.height() );
#else
    #warning Screen capture code not implemented for this platform.
#endif
  }
#ifdef KMESSDEBUG_SYSTEMTRAY
  else
  {
    kmDebug() << "Looks like the systray is invisible, not displaying the screenshot in the dialog.";
  }
#endif

  if( ! shot.isNull() )
  {
    // Now we want to draw a circle around the icon
    // Some properties about the circle we'll draw
    const int CIRCLE_WIDTH   = 3;
    const int SHADOW_OFFSET  = 2;
    const int IMAGE_BORDER   = 1;
    const int CIRCLE_MARGINS = 6;

    QRect circleArea = pictureGeometry;
    circleArea.adjust( -CIRCLE_MARGINS, -CIRCLE_MARGINS, CIRCLE_MARGINS, CIRCLE_MARGINS );

#ifdef KMESSDEBUG_SYSTEMTRAY
    kmDebug() << "Picture geometry is" << pictureGeometry << "and circle area is" << circleArea;
#endif

    // Draw the circle with a dark shadow
    QPainter painter( &shot );
    painter.setPen( QPen(KApplication::palette().dark(), CIRCLE_WIDTH) );
    painter.drawArc( circleArea.adjusted( SHADOW_OFFSET, SHADOW_OFFSET, 0, 0 ), 0, 16*360 );
    painter.setPen( QPen(Qt::red, CIRCLE_WIDTH) );
    painter.drawArc( circleArea, 0, 16*360);

    // Draw the tray icon over the screenshot again, in case a window is hiding the icon
    icon().paint( &painter, geometry() );
    painter.end();

    // Then, we add a border around the image, to make it more visible
    QPixmap finalShot( pictureArea.size() );
    finalShot.fill( KApplication::palette().color( QPalette::Active, QPalette::Foreground ) );
    painter.begin( &finalShot );
    painter.drawPixmap( QRect( IMAGE_BORDER, IMAGE_BORDER, shot.width() - IMAGE_BORDER*2, shot.height() - IMAGE_BORDER*2 ), shot );
    painter.end();

    // Save the pixmap into a temporary file to allow using it in a dialog
    QTemporaryFile tempFile( QDir::tempPath() + "/kmess_temp_XXXXXX.png" );
    tempFile.open();
    finalShot.save( tempFile.fileName() );

#ifdef KMESSDEBUG_SYSTEMTRAY
    kmDebug() << "Temp file info"
             << "- Name:"       << tempFile.fileName()
             << "- Exists?"     << tempFile.exists();
#endif

    // Show the dialog
    KMessageBox::information(kapp->activeWindow(),
        "<qt><p>" + message + "</p><p><center><img src=\"" + tempFile.fileName() + "\" "
        "width=\""  + QString::number( pictureArea.width()  ) + "\" "
        "height=\"" + QString::number( pictureArea.height() ) + "\""
        "></center></p></qt>",
        i18n("Docking in System Tray"), "hideOnCloseInfo");

    // Close the temporary file, it will be deleted when the function returns
    tempFile.close();
  }
  else
  {
    // Dialog without the shot.
    KMessageBox::information(kapp->activeWindow(),
        "<qt><p>" + message + "</p></qt>",
        i18n("Docking in System Tray"), "hideOnCloseInfo");
  }

#ifdef KMESSDEBUG_SYSTEMTRAY
  kmDebug() << "Dialog closed.";
#endif
}



// The destructor
SystemTrayWidget::~SystemTrayWidget()
{
#ifdef KMESSDEBUG_SYSTEMTRAY
  kmDebug() << "DESTROYED.";
#endif
}



// Return the context menu
QMenu* SystemTrayWidget::menu() const
{
  return contextMenu();
}



// Change the icon when the user's status changes
void SystemTrayWidget::statusChanged()
{
  Status  status = currentAccount_->getStatus();
  QPixmap icon = KIconLoader::global()->loadIcon( "kmess", KIconLoader::Panel );

  if( status != STATUS_OFFLINE )
  {
    // overlay the status icon
    icon = KMessShared::drawIconOverlay( icon, MsnStatus::getIcon( status ) );
  }

  setIcon( icon );

  // Change the tooltip
  QString newTooltip( i18nc( "Tray icon tooltip showing the KMess version", "KMess %1", KMESS_VERSION ) );

  if( status != STATUS_OFFLINE )
  {
#if !defined(Q_WS_WIN)
    newTooltip += i18nc( "Tray icon tooltip, HTML version",
                         "<br><b>%1</b> (%2)%3",
                         currentAccount_->getFriendlyName( STRING_CLEANED_ESCAPED ),
                         MsnStatus::getName( status ),
                         currentAccount_->getShowEmail()?
                           i18nc("Tray icon email count, HTML version", "<br />%1 emails", currentAccount_->getNoEmails()):""
                         );
#else
    // Qt on Windows does not support html in the system tray widget.
    newTooltip += i18nc( "Tray icon tooltip, text version",
                         " - %1 (%2)%3",
                         currentAccount_->getFriendlyName( STRING_CLEANED ),
                         MsnStatus::getName( status ),
                         currentAccount_->getShowEmail()?
                           i18nc("Tray icon email count, text version", " - %1 emails", currentAccount_->getNoEmails()):""
                         );
#endif
  }

  setToolTip( newTooltip );
}



#include "systemtraywidget.moc"

Generated by  Doxygen 1.6.0   Back to index