1 /*
2 * This file is part of MPlayer.
3 *
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 /* main window */
20
21 #include <math.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <string.h>
27
28 #include "ui.h"
29 #include "gui/app/app.h"
30 #include "gui/app/gui.h"
31 #include "gui/interface.h"
32 #include "gui/skin/font.h"
33 #include "gui/skin/skin.h"
34 #include "gui/util/list.h"
35 #include "gui/util/mem.h"
36 #include "gui/util/misc.h"
37 #include "gui/util/string.h"
38 #include "gui/wm/ws.h"
39 #include "gui/wm/wsxdnd.h"
40
41 #include "help_mp.h"
42 #include "mp_msg.h"
43 #include "libvo/x11_common.h"
44 #include "libvo/fastmemcpy.h"
45 #include "libvo/wskeys.h"
46
47 #include "stream/stream.h"
48 #include "stream/url.h"
49
50 #include "libmpdemux/demuxer.h"
51 #include "libmpdemux/stheader.h"
52 #include "codec-cfg.h"
53 #include "m_option.h"
54 #include "mp_core.h"
55 #include "libavutil/avstring.h"
56 #include "libavutil/common.h"
57
58 #include "actions.h"
59
60 static unsigned char * mainDrawBuffer;
61 int uiMainRender = True;
62
63 int mainVisible = True;
64
65 int boxMoved = False;
66 int sx = 0,sy = 0;
67 int i,pot = 0;
68
69 #include "render.h"
70
uiMainDraw(void)71 static void uiMainDraw( void )
72 {
73
74 if ( guiApp.mainWindow.State == wsWindowClosed ) mplayer( MPLAYER_EXIT_GUI, EXIT_QUIT, 0 );
75
76 if ( guiApp.mainWindow.Visible == wsWindowNotVisible ||
77 !mainVisible ) return;
78 // !guiApp.mainWindow.Mapped ) return;
79
80 if ( uiMainRender && guiApp.mainWindow.State == wsWindowExpose )
81 {
82 btnModify( evSetMoviePosition,guiInfo.Position );
83 btnModify( evSetVolume,guiInfo.Volume );
84 btnModify( evSetBalance,guiInfo.Balance );
85
86 fast_memcpy( mainDrawBuffer,guiApp.main.Bitmap.Image,guiApp.main.Bitmap.ImageSize );
87 RenderAll( &guiApp.mainWindow,guiApp.mainItems,guiApp.IndexOfMainItems,mainDrawBuffer );
88 uiMainRender=False;
89 }
90 // NOTE TO MYSELF: probably not, if uiMainRender is False
91 wsImageDraw( &guiApp.mainWindow );
92 // XFlush( wsDisplay );
93 }
94
uiMainMouse(int Button,int X,int Y,int RX,int RY)95 static void uiMainMouse( int Button,int X,int Y,int RX,int RY )
96 {
97 static int itemtype = 0;
98 int i;
99 guiItem * item = NULL;
100 static double prev_point;
101 double point;
102 float value = 0.0f;
103
104 static int SelectedItem = -1;
105 int currentselected = -1;
106 static int endstop;
107
108 for ( i=0;i <= guiApp.IndexOfMainItems;i++ )
109 if ( ( guiApp.mainItems[i].pressed != btnDisabled )&&
110 ( 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 ) ) )
111 { currentselected=i; break; }
112
113 switch ( Button )
114 {
115 case wsPMMouseButton:
116 gtkShow( ivHidePopUpMenu,NULL );
117 uiMenuShow( RX,RY );
118 itemtype=itPRMButton;
119 break;
120 case wsRMMouseButton:
121 uiMenuHide( RX,RY,0 );
122 break;
123
124 case wsPLMouseButton:
125 gtkShow( ivHidePopUpMenu,NULL );
126 sx=X; sy=Y; boxMoved=True; itemtype=itPLMButton;
127 SelectedItem=currentselected;
128 if ( SelectedItem == -1 ) break;
129 boxMoved=False;
130 item=&guiApp.mainItems[SelectedItem];
131 itemtype=item->type;
132 item->pressed=btnPressed;
133 // NOTE TO MYSELF: commented, because the expression can never be true
134 /*switch( item->type )
135 {
136 case itButton:
137 if ( ( SelectedItem > -1 ) &&
138 ( ( ( item->message == evPlaySwitchToPause && item->message == evPauseSwitchToPlay ) ) ||
139 ( ( item->message == evPauseSwitchToPlay && item->message == evPlaySwitchToPause ) ) ) )
140 { item->pressed=btnDisabled; }
141 break;
142 }*/
143 if ( itemtype == itRPotmeter )
144 {
145 prev_point=appRadian( item, X - item->x, Y - item->y ) - item->zeropoint;
146 if ( prev_point < 0.0 ) prev_point+=2*M_PI;
147 if ( prev_point <= item->arclength ) endstop=False;
148 else endstop=STOPPED_AT_0 + STOPPED_AT_100; // block movement
149 }
150 break;
151 case wsRLMouseButton:
152 boxMoved=False;
153 if ( SelectedItem != -1 ) // NOTE TO MYSELF: only if hasButton
154 {
155 item=&guiApp.mainItems[SelectedItem];
156 item->pressed=btnReleased;
157 }
158 if ( currentselected == - 1 || SelectedItem == -1 ) { itemtype=0; break; }
159 SelectedItem=-1;
160 value=0;
161 switch( itemtype )
162 {
163 case itHPotmeter:
164 value=100.0 * ( X - item->x ) / item->width;
165 break;
166 case itVPotmeter:
167 value=100.0 - 100.0 * ( Y - item->y ) / item->height;
168 break;
169 case itRPotmeter:
170 if ( endstop ) { itemtype=0; return; }
171 point=appRadian( item, X - item->x, Y - item->y ) - item->zeropoint;
172 if ( point < 0.0 ) point+=2*M_PI;
173 value=100.0 * point / item->arclength;
174 break;
175 }
176 uiEvent( item->message,value );
177 itemtype=0;
178 break;
179
180 case wsRRMouseButton:
181 gtkShow( ivShowPopUpMenu, (void *) wMain );
182 break;
183
184 /* rolled mouse ... de szar :))) */
185 case wsP5MouseButton: value=-2.5f; goto rollerhandled;
186 case wsP4MouseButton: value= 2.5f;
187 rollerhandled:
188 if (currentselected != - 1)
189 {
190 item=&guiApp.mainItems[currentselected];
191 if ( ( item->type == itHPotmeter )||( item->type == itVPotmeter )||( item->type == itRPotmeter ) )
192 {
193 item->value=constrain(item->value + value);
194 uiEvent( item->message,item->value );
195 }
196 }
197 break;
198
199 /* moving */
200 case wsMoveMouse:
201 item=&guiApp.mainItems[SelectedItem];
202 switch ( itemtype )
203 {
204 case itPLMButton:
205 wsWindowMove( &guiApp.mainWindow,True,RX - abs( sx ),RY - abs( sy ) );
206 break;
207 case itPRMButton:
208 if (guiApp.menuIsPresent) guiApp.menuWindow.MouseHandler( 0,RX,RY,0,0 );
209 break;
210 case itRPotmeter:
211 point=appRadian( item, X - item->x, Y - item->y ) - item->zeropoint;
212 if ( point < 0.0 ) point+=2*M_PI;
213 if ( item->arclength < 2 * M_PI )
214 /* a potmeter with separated 0% and 100% positions */
215 {
216 value=item->value;
217 if ( point - prev_point > M_PI )
218 /* turned beyond the 0% position */
219 {
220 if ( !endstop )
221 {
222 endstop=STOPPED_AT_0;
223 value=0.0f;
224 }
225 }
226 else if ( prev_point - point > M_PI )
227 /* turned back from beyond the 0% position */
228 {
229 if ( endstop == STOPPED_AT_0 ) endstop=False;
230 }
231 else if ( prev_point <= item->arclength && point > item->arclength )
232 /* turned beyond the 100% position */
233 {
234 if ( !endstop )
235 {
236 endstop=STOPPED_AT_100;
237 value=100.0f;
238 }
239 }
240 else if ( prev_point > item->arclength && point <= item->arclength )
241 /* turned back from beyond the 100% position */
242 {
243 if ( endstop == STOPPED_AT_100 ) endstop=False;
244 }
245 }
246 if ( !endstop ) value=100.0 * point / item->arclength;
247 prev_point=point;
248 goto potihandled;
249 case itVPotmeter:
250 value=100.0 - 100.0 * ( Y - item->y ) / item->height;
251 goto potihandled;
252 case itHPotmeter:
253 value=100.0 * ( X - item->x ) / item->width;
254 potihandled:
255 item->value=constrain(value);
256 uiEvent( item->message,item->value );
257 break;
258 }
259 break;
260 }
261 }
262
uiMainKey(int KeyCode,int Type,int Key)263 static void uiMainKey( int KeyCode,int Type,int Key )
264 {
265 int msg = evNone;
266
267 if ( Type != wsKeyPressed ) return;
268
269 if ( !Key )
270 {
271 switch ( KeyCode )
272 {
273 // NOTE TO MYSELF: This is only for the Acer AirKey V keyboard.
274 /*case wsXFMMPrev: msg=evPrev; break;
275 case wsXFMMStop: msg=evStop; break;
276 case wsXFMMPlay: msg=evPlaySwitchToPause; break;
277 case wsXFMMNext: msg=evNext; break;
278 case wsXFMMVolUp: msg=evIncVolume; break;
279 case wsXFMMVolDown: msg=evDecVolume; break;
280 case wsXFMMMute: msg=evMute; break;*/
281 }
282 }
283 else
284 {
285 switch ( Key )
286 {
287 case wsEnter: msg=evPlay; break;
288 case wsXF86LowerVolume: msg=evDecVolume; break;
289 case wsXF86RaiseVolume: msg=evIncVolume; break;
290 case wsXF86Mute: msg=evMute; break;
291 case wsXF86Pause:
292 case wsXF86Play: msg=evPlaySwitchToPause; break;
293 case wsXF86Stop: msg=evStop; break;
294 case wsXF86Prev: msg=evPrev; break;
295 case wsXF86Next: msg=evNext; break;
296 case wsXF86Media: msg=evLoad; break;
297 case wsEscape:
298 if ( guiInfo.VideoWindow && guiInfo.Playing && guiApp.videoWindow.isFullScreen )
299 {
300 uiEvent( evNormalSize,0 );
301 return;
302 }
303 default: vo_x11_putkey( Key ); return;
304 }
305 }
306 if ( msg != evNone ) uiEvent( msg,0 );
307 }
308
309 /* this will be used to handle drag & drop files */
uiMainDND(int num,char ** files)310 static void uiMainDND(int num,char** files)
311 {
312 struct stat buf;
313 int f = 0;
314
315 char* subtitles = NULL;
316 char* file = NULL;
317 char* s;
318
319 if (num <= 0)
320 return;
321
322
323 /* now fill it with new items */
324 for(f=0; f < num; f++){
325 char* str = strdup( files[f] );
326 plItem* item;
327
328 url_unescape_string(str, files[f]);
329
330 if(stat(str,&buf) == 0 && S_ISDIR(buf.st_mode) == 0) {
331 /* this is not a directory so try to play it */
332 mp_msg( MSGT_GPLAYER,MSGL_V,"Received D&D %s\n",str );
333
334 /* check if it is a subtitle file */
335 {
336 char* ext = strrchr(str,'.');
337 if (ext) {
338 static char supported[] = "utf/sub/srt/smi/rt//txt/ssa/aqt/";
339 char* type;
340 int len;
341 if((len=strlen(++ext)) && (type=strstr(supported,ext)) &&\
342 (type-supported)%4 == 0 && *(type+len) == '/'){
343 /* handle subtitle file */
344 nfree(subtitles);
345 subtitles = str;
346 continue;
347 }
348 }
349 }
350
351 /* clear playlist */
352 if (file == NULL) {
353 file = files[f];
354 listMgr(PLAYLIST_DELETE,0);
355 }
356
357 item = calloc(1,sizeof(*item));
358
359 s = strrchr( str,'/' );
360
361 /* FIXME: decompose file name ? */
362 /* yes -- Pontscho */
363 if ( s ) {
364 *s=0; s++;
365 item->name = gstrdup( s );
366 item->path = gstrdup( str );
367 } else {
368 // NOTE TO MYSELF: this shouldn't happen, make sure we have a full path
369 item->name = strdup(str);
370 item->path = strdup(".");
371 }
372 listMgr(PLAYLIST_ITEM_APPEND,item);
373 } else {
374 mp_msg( MSGT_GPLAYER,MSGL_WARN,_(MSGTR_GUI_MSG_NotAFile1),str );
375 }
376 free( str );
377 }
378
379 if (file) {
380 uiSetFile( NULL,file,STREAMTYPE_FILE );
381 if ( guiInfo.Playing == GUI_PLAY ) uiEvent( evStop,0 );
382 uiEvent( evPlay,0 );
383 }
384 if (subtitles) {
385 nfree(guiInfo.SubtitleFilename);
386 guiInfo.SubtitleFilename = subtitles;
387 mplayerLoadSubtitle(guiInfo.SubtitleFilename);
388 }
389 }
390
uiMainInit(void)391 void uiMainInit (void)
392 {
393 mainDrawBuffer = malloc(guiApp.main.Bitmap.ImageSize);
394
395 if (!mainDrawBuffer)
396 {
397 char msg[80] = "[main] ";
398
399 av_strlcat(msg, _(MSGTR_GUI_MSG_MemoryErrorWindow), sizeof(msg));
400 gmp_msg(MSGT_GPLAYER, MSGL_FATAL, msg);
401 mplayer(MPLAYER_EXIT_GUI, EXIT_ERROR, 0);
402 }
403
404 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);
405 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[main] mainWindow ID: 0x%x\n", (int) guiApp.mainWindow.WindowID);
406 wsWindowShape(&guiApp.mainWindow, guiApp.main.Mask.Image);
407 wsWindowIcon(wsDisplay, guiApp.mainWindow.WindowID, &guiIcon);
408 wsXDNDMakeAwareness(&guiApp.mainWindow);
409
410 guiApp.mainWindow.DrawHandler = uiMainDraw;
411 guiApp.mainWindow.MouseHandler = uiMainMouse;
412 guiApp.mainWindow.KeyHandler = uiMainKey;
413 guiApp.mainWindow.DNDHandler = uiMainDND;
414 }
415
uiMainDone(void)416 void uiMainDone (void)
417 {
418 nfree(mainDrawBuffer);
419 wsWindowDestroy(&guiApp.mainWindow);
420 wsEvents();
421 }
422