view gui/ui/main.c @ 35883:804c3926503b

Fix a potential integer overflow.
author reimar
date Sat, 16 Mar 2013 10:32:42 +0000
parents b5f83ea354e7
children 7affacef2f88
line wrap: on
line source

/*
 * This file is part of MPlayer.
 *
 * MPlayer 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.
 *
 * MPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/* main window */

#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

#include "ui.h"
#include "gui/app/app.h"
#include "gui/app/gui.h"
#include "gui/interface.h"
#include "gui/skin/font.h"
#include "gui/skin/skin.h"
#include "gui/util/list.h"
#include "gui/util/mem.h"
#include "gui/util/string.h"
#include "gui/wm/ws.h"
#include "gui/wm/wsxdnd.h"

#include "help_mp.h"
#include "mp_msg.h"
#include "libvo/x11_common.h"
#include "libvo/fastmemcpy.h"
#include "libvo/wskeys.h"

#include "stream/stream.h"
#include "stream/url.h"

#include "libmpdemux/demuxer.h"
#include "libmpdemux/stheader.h"
#include "codec-cfg.h"
#include "m_option.h"
#include "mp_core.h"
#include "libavutil/common.h"

#include "actions.h"

static unsigned char * mainDrawBuffer;
int             uiMainRender = True;

int             mainVisible = True;

int             boxMoved = False;
int             sx = 0,sy = 0;
int             i,pot = 0;

#include "render.h"

static void uiMainDraw( void )
{

 if ( guiApp.mainWindow.State == wsWindowClosed ) mplayer( MPLAYER_EXIT_GUI, EXIT_QUIT, 0 );

 if ( guiApp.mainWindow.Visible == wsWindowNotVisible ||
      !mainVisible ) return;
//      !guiApp.mainWindow.Mapped ) return;

 if ( uiMainRender && guiApp.mainWindow.State == wsWindowExpose )
  {
   btnModify( evSetMoviePosition,guiInfo.Position );
   btnModify( evSetVolume,guiInfo.Volume );

   fast_memcpy( mainDrawBuffer,guiApp.main.Bitmap.Image,guiApp.main.Bitmap.ImageSize );
   RenderAll( &guiApp.mainWindow,guiApp.mainItems,guiApp.IndexOfMainItems,mainDrawBuffer );
   uiMainRender=False;
  }
 // NOTE TO MYSELF: probably not, if uiMainRender is False
 wsImageDraw( &guiApp.mainWindow );
// XFlush( wsDisplay );
}

static void uiMainMouse( int Button,int X,int Y,int RX,int RY )
{
 static int     itemtype = 0;
        int     i;
        guiItem * item = NULL;
        float   value = 0.0f;

 static int     SelectedItem = -1;
        int     currentselected = -1;

 for ( i=0;i <= guiApp.IndexOfMainItems;i++ )
  if ( ( guiApp.mainItems[i].pressed != btnDisabled )&&
       ( isInside( X,Y,guiApp.mainItems[i].x,guiApp.mainItems[i].y,guiApp.mainItems[i].x+guiApp.mainItems[i].width,guiApp.mainItems[i].y+guiApp.mainItems[i].height ) ) )
   { currentselected=i; break; }

 switch ( Button )
  {
   case wsPMMouseButton:
	  gtkShow( ivHidePopUpMenu,NULL );
          uiMenuShow( RX,RY );
          itemtype=itPRMButton;
          break;
   case wsRMMouseButton:
          uiMenuHide( RX,RY,0 );
          break;

   case wsPLMouseButton:
	  gtkShow( ivHidePopUpMenu,NULL );
          sx=X; sy=Y; boxMoved=True; itemtype=itPLMButton;
          SelectedItem=currentselected;
          if ( SelectedItem == -1 ) break;
          boxMoved=False;
          item=&guiApp.mainItems[SelectedItem];
          itemtype=item->type;
          item->pressed=btnPressed;
          // NOTE TO MYSELF: commented, because the expression can never be true
          /*switch( item->type )
           {
            case itButton:
                 if ( ( SelectedItem > -1 ) &&
                    ( ( ( item->message == evPlaySwitchToPause && item->message == evPauseSwitchToPlay ) ) ||
                      ( ( item->message == evPauseSwitchToPlay && item->message == evPlaySwitchToPause ) ) ) )
                  { item->pressed=btnDisabled; }
                 break;
           }*/
          break;
   case wsRLMouseButton:
          boxMoved=False;
          if ( SelectedItem != -1 )   // NOTE TO MYSELF: only if itButton, itHPotmeter or itVPotmeter
           {
            item=&guiApp.mainItems[SelectedItem];
            item->pressed=btnReleased;
           }
          if ( currentselected == - 1 || SelectedItem == -1 ) { itemtype=0; break; }
          SelectedItem=-1;
          value=0;
          switch( itemtype )
           {
            case itPotmeter:
            case itHPotmeter:
                 btnModify( item->message,(float)( X - item->x ) / item->width * 100.0f );
		 uiEvent( item->message,item->value );
                 value=item->value;
                 break;
	    case itVPotmeter:
                 btnModify( item->message, ( 1. - (float)( Y - item->y ) / item->height) * 100.0f );
		 uiEvent( item->message,item->value );
                 value=item->value;
                 break;
           }
          uiEvent( item->message,value );
          itemtype=0;
          break;

   case wsRRMouseButton:
        gtkShow( ivShowPopUpMenu,NULL );
        break;

/* rolled mouse ... de szar :))) */
   case wsP5MouseButton: value=-2.5f; goto rollerhandled;
   case wsP4MouseButton: value= 2.5f;
rollerhandled:
          if (currentselected != - 1)
           {
            item=&guiApp.mainItems[currentselected];
            if ( ( item->type == itHPotmeter )||( item->type == itVPotmeter )||( item->type == itPotmeter ) )
             {
              item->value+=value;
              btnModify( item->message,item->value );
              uiEvent( item->message,item->value );
             }
           }
          break;

/* moving */
   case wsMoveMouse:
          item=&guiApp.mainItems[SelectedItem];
          switch ( itemtype )
           {
            case itPLMButton:
                 wsWindowMove( &guiApp.mainWindow,True,RX - abs( sx ),RY - abs( sy ) );
                 break;
            case itPRMButton:
                 if (guiApp.menuIsPresent) guiApp.menuWindow.MouseHandler( 0,RX,RY,0,0 );
                 break;
            case itPotmeter:
                 item->value=(float)( X - item->x ) / item->width * 100.0f;
                 goto potihandled;
            case itVPotmeter:
                 item->value=(1. - (float)( Y - item->y ) / item->height) * 100.0f;
                 goto potihandled;
            case itHPotmeter:
                 item->value=(float)( X - item->x ) / item->width * 100.0f;
potihandled:
                 if ( item->value > 100.0f ) item->value=100.0f;
                 if ( item->value < 0.0f ) item->value=0.0f;
                 uiEvent( item->message,item->value );
                 break;
           }
          break;
  }
}

static void uiMainKey( int KeyCode,int Type,int Key )
{
 int msg = evNone;

 if ( Type != wsKeyPressed ) return;

 if ( !Key )
  {
   switch ( KeyCode )
    {
     // NOTE TO MYSELF: This is only for the Acer AirKey V keyboard.
   /*case wsXFMMPrev:     msg=evPrev;              break;
     case wsXFMMStop:	  msg=evStop;              break;
     case wsXFMMPlay:	  msg=evPlaySwitchToPause; break;
     case wsXFMMNext:	  msg=evNext;	           break;
     case wsXFMMVolUp:	  msg=evIncVolume;         break;
     case wsXFMMVolDown:  msg=evDecVolume;         break;
     case wsXFMMMute: 	  msg=evMute;	           break;*/
    }
  }
  else
   {
    switch ( Key )
     {
      case wsEnter:            msg=evPlay; break;
      case wsXF86LowerVolume:  msg=evDecVolume; break;
      case wsXF86RaiseVolume:  msg=evIncVolume; break;
      case wsXF86Mute:         msg=evMute; break;
      case wsXF86Pause:
      case wsXF86Play:         msg=evPlaySwitchToPause; break;
      case wsXF86Stop:         msg=evStop; break;
      case wsXF86Prev:         msg=evPrev; break;
      case wsXF86Next:         msg=evNext; break;
      case wsXF86Media:        msg=evLoad; break;
      case wsEscape:
    	    if ( guiInfo.VideoWindow && guiInfo.Playing && guiApp.videoWindow.isFullScreen )
	     {
	      uiEvent( evNormalSize,0 );
	      return;
	     }
      default:          vo_x11_putkey( Key ); return;
     }
   }
 if ( msg != evNone ) uiEvent( msg,0 );
}

/* this will be used to handle drag & drop files */
static void uiMainDND(int num,char** files)
{
  struct stat buf;
  int f = 0;

  char* subtitles = NULL;
  char* file = NULL;
  char* s;

  if (num <= 0)
    return;


  /* now fill it with new items */
  for(f=0; f < num; f++){
    char* str = strdup( files[f] );
    plItem* item;

    url_unescape_string(str, files[f]);

    if(stat(str,&buf) == 0 && S_ISDIR(buf.st_mode) == 0) {
      /* this is not a directory so try to play it */
      mp_msg( MSGT_GPLAYER,MSGL_V,"Received D&D %s\n",str );

      /* check if it is a subtitle file */
      {
	char* ext = strrchr(str,'.');
	if (ext) {
	  static char supported[] = "utf/sub/srt/smi/rt//txt/ssa/aqt/";
	  char* type;
	  int len;
	  if((len=strlen(++ext)) && (type=strstr(supported,ext)) &&\
	     (type-supported)%4 == 0 && *(type+len) == '/'){
	    /* handle subtitle file */
	    nfree(subtitles);
	    subtitles = str;
	    continue;
	  }
	}
      }

      /* clear playlist */
      if (file == NULL) {
	file = files[f];
	listMgr(PLAYLIST_DELETE,0);
      }

      item = calloc(1,sizeof(plItem));

      s = strrchr( str,'/' );

      /* FIXME: decompose file name ? */
      /* yes -- Pontscho */
      if ( s ) {
	*s=0; s++;
	item->name = gstrdup( s );
	item->path = gstrdup( str );
      } else {
	// NOTE TO MYSELF: this shouldn't happen, make sure we have a full path
	item->name = strdup(str);
	item->path = strdup(".");
      }
      listMgr(PLAYLIST_ITEM_APPEND,item);
    } else {
      mp_msg( MSGT_GPLAYER,MSGL_WARN,MSGTR_NotAFile,str );
    }
    free( str );
  }

  if (file) {
    uiSetFile( NULL,file,STREAMTYPE_FILE );
    if ( guiInfo.Playing == GUI_PLAY ) uiEvent( evStop,0 );
    uiEvent( evPlay,0 );
  }
  if (subtitles) {
    nfree(guiInfo.SubtitleFilename);
    guiInfo.SubtitleFilename = subtitles;
    mplayerLoadSubtitle(guiInfo.SubtitleFilename);
  }
}

void uiMainInit (void)
{
  mainDrawBuffer = malloc(guiApp.main.Bitmap.ImageSize);

  if (!mainDrawBuffer)
  {
    gmp_msg(MSGT_GPLAYER, MSGL_FATAL, MSGTR_NEMDB);
    mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
  }

  wsWindowCreate(&guiApp.mainWindow, guiApp.main.x, guiApp.main.y, guiApp.main.width, guiApp.main.height, (guiApp.mainDecoration ? wsShowFrame : 0 ) | wsMinSize | wsMaxSize | wsHideWindow, wsShowMouseCursor | wsHandleMouseButton | wsHandleMouseMove, "MPlayer");
  mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[main] mainWindow ID: 0x%x\n", (int) guiApp.mainWindow.WindowID);
  wsWindowShape(&guiApp.mainWindow, guiApp.main.Mask.Image);
  wsWindowIcon(wsDisplay, guiApp.mainWindow.WindowID, &guiIcon);
  wsXDNDMakeAwareness(&guiApp.mainWindow);

  guiApp.mainWindow.DrawHandler = uiMainDraw;
  guiApp.mainWindow.MouseHandler = uiMainMouse;
  guiApp.mainWindow.KeyHandler = uiMainKey;
  guiApp.mainWindow.DNDHandler = uiMainDND;
}

void uiMainDone (void)
{
  nfree(mainDrawBuffer);
  wsWindowDestroy(&guiApp.mainWindow);
}