/* 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. */ /* Provides an interface to a plain TQWidget, which is independent of KDE (bypassed to X11) begin: Fre Sep 26 2003 Copyright (C) 2003 Christian Muehlhaeuser Copyright (C) 2004 Michael Goettsche */ #include "osd.h" #include "konversationapplication.h" #include "common.h" #include #include #include #include #include #include #include #include //unsetColors() #include //reposition() OSDWidget::OSDWidget( const TQString &appName, TQWidget *parent, const char *name ) : TQWidget( parent, name, WNoAutoErase | WStyle_Customize | WX11BypassWM | WStyle_StaysOnTop | WStyle_Tool ) , m_appName( appName ) , m_duration( 5000 ) , m_shadow( true ) , m_alignment( Middle ) , m_screen( 0 ) , m_y( MARGIN ) , m_dirty( false ) { setFocusPolicy( TQ_NoFocus ); setBackgroundMode( NoBackground ); unsetColors(); connect( &timer, TQT_SIGNAL( timeout() ), TQT_SLOT( hide() ) ); connect( &timerMin, TQT_SIGNAL( timeout() ), TQT_SLOT( minReached() ) ); } void OSDWidget::renderOSDText( const TQString &txt ) { // Escaped text TQString text = Konversation::removeIrcMarkup(txt); static TQBitmap mask; //This is various spacings and margins, based on the font to look "just right" const uint METRIC = fontMetrics().width( 'x' ); // Set a sensible maximum size, don't cover the whole desktop or cross the screen TQSize max = TQApplication::desktop()->screen( m_screen )->size() - TQSize( MARGIN*2 + METRIC*2, 100 ); TQFont titleFont( "Arial", 12, TQFont::Bold ); TQFontMetrics titleFm( titleFont ); // The title cannnot be taller than one line // AlignAuto = align Arabic to the right, etc. TQRect titleRect = titleFm.boundingRect( 0, 0, max.width() - METRIC, titleFm.height(), AlignAuto, m_appName ); // The osd cannot be larger than the screen TQRect textRect = fontMetrics().boundingRect( 0, 0, max.width(), max.height(), AlignAuto | WordBreak, text ); if ( textRect.width() < titleRect.width() ) textRect.setWidth( titleRect.width() ); //this should still be within the screen bounds textRect.addCoords( 0, 0, METRIC*2, titleRect.height() + METRIC ); osdBuffer.resize( textRect.size() ); mask.resize( textRect.size() ); // Start painting! TQPainter bufferPainter( &osdBuffer ); TQPainter maskPainter( &mask ); // Draw backing rectangle const uint xround = (METRIC * 200) / textRect.width(); const uint yround = (METRIC * 200) / textRect.height(); bufferPainter.setPen( TQt::black ); bufferPainter.setBrush( backgroundColor() ); bufferPainter.drawRoundRect( textRect, xround, yround ); bufferPainter.setFont( font() ); const uint w = textRect.width() - 1; const uint h = textRect.height() - 1; // Draw the text shadow if ( m_shadow ) { bufferPainter.setPen( backgroundColor().dark( 175 ) ); bufferPainter.drawText( METRIC + 3, (METRIC/2) + titleFm.height() + 1, w, h, AlignLeft | WordBreak, text ); } // Draw the text bufferPainter.setPen( foregroundColor() ); bufferPainter.drawText( METRIC, (METRIC/2) + titleFm.height() - 1, w, h, AlignLeft | WordBreak, text ); // Draw the title text bufferPainter.setFont( titleFont ); bufferPainter.drawText( METRIC * 2, (METRIC/2), w, h, AlignLeft, m_appName ); // Masking for transparency mask.fill( TQt::black ); maskPainter.setBrush( TQt::white ); maskPainter.drawRoundRect( textRect, xround, yround ); setMask( mask ); //do last to reduce noticeable change when showing multiple OSDs in succession reposition( textRect.size() ); m_currentText = text; m_dirty = false; update(); } // slot void OSDWidget::showOSD( const TQString &text, bool preemptive ) { if ( isEnabled() && !text.isEmpty() ) { TQString plaintext = text.copy(); plaintext.replace(TQRegExp("]*>"), TQString("")); plaintext.replace(TQString("<"), TQString("<")); plaintext.replace(TQString(">"), TQString(">")); plaintext.replace(TQString("&"), TQString("&")); if ( preemptive || !timerMin.isActive() ) { m_currentText = plaintext; m_dirty = true; show(); } else textBuffer.append( plaintext ); //queue } } void OSDWidget::minReached() //SLOT { if ( !textBuffer.isEmpty() ) { renderOSDText( textBuffer.front() ); textBuffer.pop_front(); if( m_duration ) //timerMin is still running timer.start( m_duration, true ); } else timerMin.stop(); } void OSDWidget::setDuration( int ms ) { m_duration = ms; if( !m_duration ) timer.stop(); } void OSDWidget::setFont( TQFont newFont ) { TQWidget::setFont( newFont ); refresh(); } void OSDWidget::setShadow( bool shadow ) { m_shadow = shadow; refresh(); } void OSDWidget::setTextColor( const TQColor &newColor ) { setPaletteForegroundColor( newColor ); refresh(); } void OSDWidget::setBackgroundColor( const TQColor &newColor ) { setPaletteBackgroundColor( newColor ); refresh(); } void OSDWidget::unsetColors() { setPaletteForegroundColor( TDEGlobalSettings::activeTextColor() ); setPaletteBackgroundColor( TDEGlobalSettings::activeTitleColor() ); refresh(); } void OSDWidget::setOffset( int /*x*/, int y ) { //m_offset = TQPoint( x, y ); m_y = y; reposition(); } void OSDWidget::setAlignment( Alignment a ) { m_alignment = a; reposition(); } void OSDWidget::setScreen( uint screen ) { const uint n = TQApplication::desktop()->numScreens(); m_screen = (screen >= n) ? n-1 : (int)screen; reposition(); } bool OSDWidget::event( TQEvent *e ) { switch( e->type() ) { case TQEvent::Paint: bitBlt( this, 0, 0, &osdBuffer ); return true; default: return TQWidget::event( e ); } } void OSDWidget::mousePressEvent( TQMouseEvent* ) { hide(); emit hidden(); } void OSDWidget::show() { // Don't show the OSD widget when the desktop is locked if ( isKDesktopLockRunning() == Locked ) { minReached(); // don't queue the message return; } if ( m_dirty ) renderOSDText( m_currentText ); TQWidget::show(); if ( m_duration ) //duration 0 -> stay forever { timer.start( m_duration, true ); //calls hide() timerMin.start( 150 ); //calls minReached() } } void OSDWidget::refresh() { if ( isVisible() ) { //we need to update the buffer renderOSDText( m_currentText ); } else m_dirty = true; //ensure we are re-rendered before we are shown } void OSDWidget::reposition( TQSize newSize ) { if( !newSize.isValid() ) newSize = size(); TQPoint newPos( MARGIN, m_y ); const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen ); //TODO m_y is the middle of the OSD, and don't exceed screen margins switch ( m_alignment ) { case Left: break; case Right: newPos.rx() = screen.width() - MARGIN - newSize.width(); break; case Center: newPos.ry() = (screen.height() - newSize.height()) / 2; //FALL THROUGH case Middle: newPos.rx() = (screen.width() - newSize.width()) / 2; break; } //ensure we don't dip below the screen if( newPos.y()+newSize.height() > screen.height()-MARGIN ) newPos.ry() = screen.height()-MARGIN-newSize.height(); // correct for screen position newPos += screen.topLeft(); //ensure we are painted before we move if( isVisible() ) paintEvent( (TQPaintEvent*)0 ); //fancy X11 move+resize, reduces visual artifacts XMoveResizeWindow( x11Display(), winId(), newPos.x(), newPos.y(), newSize.width(), newSize.height() ); } ////// OSDPreviewWidget below ///////////////////// #include //previewWidget #include OSDPreviewWidget::OSDPreviewWidget( const TQString &appName, TQWidget *parent, const char *name ) : OSDWidget( appName, parent, name ) , m_dragging( false ) { m_currentText = i18n( "OSD Preview - drag to reposition" ); m_duration = 0; } void OSDPreviewWidget::mousePressEvent( TQMouseEvent *event ) { m_dragOffset = event->pos(); if ( event->button() == Qt::LeftButton && !m_dragging ) { grabMouse( KCursor::sizeAllCursor() ); m_dragging = true; } } void OSDPreviewWidget::mouseReleaseEvent( TQMouseEvent * /*event*/ ) { if ( m_dragging ) { m_dragging = false; releaseMouse(); // compute current Position && offset TQDesktopWidget *desktop = TQApplication::desktop(); int currentScreen = desktop->screenNumber( pos() ); if ( currentScreen != -1 ) { // set new data m_screen = currentScreen; m_y = TQWidget::y(); emit positionChanged(); } } } void OSDPreviewWidget::mouseMoveEvent( TQMouseEvent *e ) { if ( m_dragging && this == mouseGrabber() ) { const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen ); const uint hcenter = screen.width() / 2; const uint eGlobalPosX = e->globalPos().x() - screen.left(); const uint snapZone = screen.width() / 8; TQPoint destination = e->globalPos() - m_dragOffset - screen.topLeft(); int maxY = screen.height() - height() - MARGIN; if( destination.y() < MARGIN ) destination.ry() = MARGIN; if( destination.y() > maxY ) destination.ry() = maxY; if( eGlobalPosX < (hcenter-snapZone) ) { m_alignment = Left; destination.rx() = MARGIN; } else if( eGlobalPosX > (hcenter+snapZone) ) { m_alignment = Right; destination.rx() = screen.width() - MARGIN - width(); } else { const uint eGlobalPosY = e->globalPos().y() - screen.top(); const uint vcenter = screen.height()/2; destination.rx() = hcenter - width()/2; if( eGlobalPosY >= (vcenter-snapZone) && eGlobalPosY <= (vcenter+snapZone) ) { m_alignment = Center; destination.ry() = vcenter - height()/2; } else m_alignment = Middle; } destination += screen.topLeft(); move( destination ); } } // the code was taken from pilotDaemon.cpp in KPilot // static OSDWidget::KDesktopLockStatus OSDWidget::isKDesktopLockRunning() { if (!Preferences::oSDCheckDesktopLock()) return NotLocked; DCOPClient *dcopptr = TDEApplication::kApplication()->dcopClient(); // Can't tell, very weird if (!dcopptr || !dcopptr->isAttached()) { kdWarning() << k_funcinfo << ": Could not make DCOP connection." << endl; return DCOPError; } TQByteArray data,returnValue; TQCString returnType; if (!dcopptr->call("kdesktop","KScreensaverIface","isBlanked()", data,returnType,returnValue,true)) { // KDesktop is not running. Maybe we are in a KDE4 desktop... kdDebug() << k_funcinfo << ": Check for screensaver failed." << endl; return DCOPError; } if (returnType == "bool") { bool b; TQDataStream reply(returnValue,IO_ReadOnly); reply >> b; return (b ? Locked : NotLocked); } else { kdWarning() << k_funcinfo << ": Strange return value from screensaver. " << "Assuming screensaver is active." << endl; // Err on the side of safety. return Locked; } } #include "osd.moc"