qt: playlist: use item title if available
[vlc.git] / modules / control / gestures.c
blob4497a445218025ffd20a61786c24283c84dd9934
1 /*****************************************************************************
2 * gestures.c: control vlc with mouse gestures
3 *****************************************************************************
4 * Copyright (C) 2004-2009 the VideoLAN team
6 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_interface.h>
35 #include <vlc_vout.h>
36 #include <vlc_player.h>
37 #include <vlc_playlist.h>
38 #include <vlc_vector.h>
39 #include <assert.h>
41 /*****************************************************************************
42 * intf_sys_t: description and status of interface
43 *****************************************************************************/
45 typedef struct VLC_VECTOR(vout_thread_t *) vout_vector;
46 struct intf_sys_t
48 vlc_playlist_t *playlist;
49 vlc_player_listener_id *player_listener;
50 vlc_mutex_t lock;
51 vout_vector vout_vector;
52 bool b_button_pressed;
53 int i_last_x, i_last_y;
54 unsigned int i_pattern;
55 unsigned int i_num_gestures;
56 int i_threshold;
57 int i_button_mask;
60 /*****************************************************************************
61 * Local prototypes.
62 *****************************************************************************/
63 #define UP 1
64 #define DOWN 2
65 #define LEFT 3
66 #define RIGHT 4
67 #define NONE 0
68 #define GESTURE( a, b, c, d ) (a | ( b << 4 ) | ( c << 8 ) | ( d << 12 ))
70 static int Open ( vlc_object_t * );
71 static void Close ( vlc_object_t * );
73 /*****************************************************************************
74 * Module descriptor
75 *****************************************************************************/
76 #define THRESHOLD_TEXT N_( "Motion threshold (10-100)" )
77 #define THRESHOLD_LONGTEXT N_( \
78 "Amount of movement required for a mouse gesture to be recorded." )
80 #define BUTTON_TEXT N_( "Trigger button" )
81 #define BUTTON_LONGTEXT N_( \
82 "Trigger button for mouse gestures." )
84 #define BUTTON_DEFAULT "left"
86 static const char *const button_list[] = { "left", "middle", "right" };
87 static const char *const button_list_text[] =
88 { N_("Left"), N_("Middle"), N_("Right") };
90 vlc_module_begin ()
91 set_shortname( N_("Gestures"))
92 set_category( CAT_INTERFACE )
93 set_subcategory( SUBCAT_INTERFACE_CONTROL )
94 add_integer( "gestures-threshold", 30,
95 THRESHOLD_TEXT, THRESHOLD_LONGTEXT, true )
96 add_string( "gestures-button", BUTTON_DEFAULT,
97 BUTTON_TEXT, BUTTON_LONGTEXT, false )
98 change_string_list( button_list, button_list_text )
99 set_description( N_("Mouse gestures control interface") )
101 set_capability( "interface", 0 )
102 set_callbacks( Open, Close )
103 vlc_module_end ()
105 static void player_on_vout_changed(vlc_player_t *player,
106 enum vlc_player_vout_action action,
107 vout_thread_t *vout,
108 enum vlc_vout_order order,
109 vlc_es_id_t *es_id,
110 void *data);
111 static int MovedEvent( vlc_object_t *, char const *,
112 vlc_value_t, vlc_value_t, void * );
113 static int ButtonEvent( vlc_object_t *, char const *,
114 vlc_value_t, vlc_value_t, void * );
116 /*****************************************************************************
117 * OpenIntf: initialize interface
118 *****************************************************************************/
119 static int Open ( vlc_object_t *p_this )
121 intf_thread_t *p_intf = (intf_thread_t *)p_this;
123 /* Allocate instance and initialize some members */
124 intf_sys_t *p_sys = p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
125 if( unlikely(p_sys == NULL) )
126 return VLC_ENOMEM;
128 // Configure the module
129 p_sys->playlist = vlc_intf_GetMainPlaylist(p_intf);
130 vlc_mutex_init( &p_sys->lock );
131 vlc_vector_init(&p_sys->vout_vector);
133 static const struct vlc_player_cbs cbs =
135 .on_vout_changed = player_on_vout_changed,
137 vlc_player_t *player = vlc_playlist_GetPlayer(p_sys->playlist);
138 vlc_player_Lock(player);
139 p_sys->player_listener = vlc_player_AddListener(player, &cbs, p_intf);
140 vlc_player_Unlock(player);
141 if (!p_sys->player_listener)
142 goto error;
144 p_sys->b_button_pressed = false;
145 p_sys->i_threshold = var_InheritInteger( p_intf, "gestures-threshold" );
147 // Choose the tight button to use
148 char *psz_button = var_InheritString( p_intf, "gestures-button" );
149 if( psz_button && !strcmp( psz_button, "left" ) )
150 p_sys->i_button_mask = 1;
151 else if( psz_button && !strcmp( psz_button, "middle" ) )
152 p_sys->i_button_mask = 2;
153 else // psz_button == "right"
154 p_sys->i_button_mask = 4;
155 free( psz_button );
157 p_sys->i_pattern = 0;
158 p_sys->i_num_gestures = 0;
160 return VLC_SUCCESS;
162 error:
163 vlc_vector_clear(&p_sys->vout_vector);
164 free(p_sys);
165 return VLC_EGENERIC;
168 /*****************************************************************************
169 * gesture: return a subpattern within a pattern
170 *****************************************************************************/
171 static inline unsigned gesture( unsigned i_pattern, unsigned i_num )
173 return ( i_pattern >> ( i_num * 4 ) ) & 0xF;
176 /*****************************************************************************
177 * CloseIntf: destroy dummy interface
178 *****************************************************************************/
179 static void Close ( vlc_object_t *p_this )
181 intf_thread_t *p_intf = (intf_thread_t *)p_this;
182 intf_sys_t *p_sys = p_intf->p_sys;
184 vlc_player_t *player = vlc_playlist_GetPlayer(p_sys->playlist);
185 vlc_player_Lock(player);
186 vlc_player_RemoveListener(player, p_sys->player_listener);
187 vlc_player_Unlock(player);
189 /* Destroy the callbacks (the order matters!) */
190 vout_thread_t *vout;
191 vlc_vector_foreach(vout, &p_sys->vout_vector)
193 var_DelCallback(vout, "mouse-moved", MovedEvent, p_intf);
194 var_DelCallback(vout, "mouse-button-down", ButtonEvent, p_intf);
195 vout_Release(vout);
197 vlc_vector_clear(&p_sys->vout_vector);
199 /* Destroy structure */
200 free( p_sys );
203 static void ProcessGesture( intf_thread_t *p_intf )
205 intf_sys_t *p_sys = p_intf->p_sys;
206 vlc_playlist_t *playlist = p_sys->playlist;
207 vlc_player_t *player = vlc_playlist_GetPlayer(playlist);
209 /* Do something */
210 /* If you modify this, please try to follow this convention:
211 Start with LEFT, RIGHT for playback related commands
212 and UP, DOWN, for other commands */
213 vlc_playlist_Lock(playlist);
214 switch( p_sys->i_pattern )
216 case LEFT:
217 case RIGHT:
219 msg_Dbg( p_intf, "Go %s in the movie!",
220 p_sys->i_pattern == LEFT ? "backward" : "forward" );
221 int it = var_InheritInteger( p_intf , "short-jump-size" );
222 if( it > 0 )
224 vlc_tick_t jump = p_sys->i_pattern == LEFT ? -it : it;
225 vlc_player_JumpTime(player, vlc_tick_from_sec(jump));
227 break;
230 case GESTURE(LEFT,UP,NONE,NONE):
231 msg_Dbg( p_intf, "Going slower." );
232 vlc_player_DecrementRate(player);
233 break;
235 case GESTURE(RIGHT,UP,NONE,NONE):
236 msg_Dbg( p_intf, "Going faster." );
237 vlc_player_IncrementRate(player);
238 break;
240 case GESTURE(LEFT,RIGHT,NONE,NONE):
241 case GESTURE(RIGHT,LEFT,NONE,NONE):
243 msg_Dbg( p_intf, "Play/Pause" );
244 vlc_player_TogglePause(player);
245 break;
248 case GESTURE(LEFT,DOWN,NONE,NONE):
249 vlc_playlist_Prev(playlist);
250 break;
252 case GESTURE(RIGHT,DOWN,NONE,NONE):
253 vlc_playlist_Next(playlist);
254 break;
256 case UP:
257 msg_Dbg(p_intf, "Louder");
258 vlc_player_aout_IncrementVolume(player, 1, NULL);
259 break;
261 case DOWN:
262 msg_Dbg(p_intf, "Quieter");
263 vlc_player_aout_DecrementVolume(player, 1, NULL);
264 break;
266 case GESTURE(UP,DOWN,NONE,NONE):
267 case GESTURE(DOWN,UP,NONE,NONE):
268 msg_Dbg( p_intf, "Mute sound" );
269 vlc_player_aout_ToggleMute(player);
270 break;
272 case GESTURE(UP,RIGHT,NONE,NONE):
273 case GESTURE(DOWN,RIGHT,NONE,NONE):
275 enum es_format_category_e cat =
276 p_sys->i_pattern == GESTURE(UP,RIGHT,NONE,NONE) ?
277 AUDIO_ES : SPU_ES;
278 vlc_player_SelectNextTrack(player, cat);
279 break;
282 case GESTURE(UP,LEFT,NONE,NONE):
284 vlc_player_vout_ToggleFullscreen(player);
285 break;
288 case GESTURE(DOWN,LEFT,NONE,NONE):
289 vlc_playlist_Unlock(playlist);
290 /* FIXME: Should close the vout!"*/
291 libvlc_Quit( vlc_object_instance(p_intf) );
292 break;
294 case GESTURE(DOWN,LEFT,UP,RIGHT):
295 case GESTURE(UP,RIGHT,DOWN,LEFT):
296 msg_Dbg( p_intf, "a square was drawn!" );
297 break;
299 vlc_playlist_Unlock(playlist);
301 p_sys->i_num_gestures = 0;
302 p_sys->i_pattern = 0;
305 static int MovedEvent(vlc_object_t *this, char const *psz_var,
306 vlc_value_t oldval, vlc_value_t newval, void *data)
308 VLC_UNUSED(this); VLC_UNUSED(psz_var); VLC_UNUSED(oldval);
310 intf_thread_t *intf = data;
311 intf_sys_t *sys = intf->p_sys;
313 vlc_mutex_lock(&sys->lock);
314 if (sys->b_button_pressed)
316 unsigned int pattern = 0;
317 int xdelta = newval.coords.x - sys->i_last_x;
318 xdelta /= sys->i_threshold;
319 int ydelta = newval.coords.y - sys->i_last_y;
320 ydelta /= sys->i_threshold;
322 char const *dir;
323 unsigned int delta;
324 if (abs(xdelta) > abs(ydelta))
326 pattern = xdelta < 0 ? LEFT : RIGHT;
327 dir = xdelta < 0 ? "left" : "right";
328 delta = abs(xdelta);
330 else if (abs(ydelta) > 0)
332 pattern = ydelta < 0 ? UP : DOWN;
333 dir = ydelta < 0 ? "up" : "down";
334 delta = abs(ydelta);
337 if (pattern)
339 sys->i_last_x = newval.coords.x;
340 sys->i_last_y = newval.coords.y;
341 if (sys->i_num_gestures > 0 &&
342 gesture(sys->i_pattern, sys->i_num_gestures - 1) != pattern)
344 sys->i_pattern |= pattern << (sys->i_num_gestures * 4);
345 sys->i_num_gestures++;
347 else if (sys->i_num_gestures == 0)
349 sys->i_pattern = pattern;
350 sys->i_num_gestures = 1;
352 msg_Dbg(intf, "%s gesture (%u)", dir, delta);
355 vlc_mutex_unlock(&sys->lock);
356 return VLC_SUCCESS;
359 static int ButtonEvent( vlc_object_t *p_this, char const *psz_var,
360 vlc_value_t oldval, vlc_value_t val, void *p_data )
362 intf_thread_t *p_intf = p_data;
363 intf_sys_t *p_sys = p_intf->p_sys;
365 (void) psz_var; (void) oldval;
367 vlc_mutex_lock( &p_sys->lock );
368 if( val.i_int & p_sys->i_button_mask )
370 if( !p_sys->b_button_pressed )
372 p_sys->b_button_pressed = true;
373 var_GetCoords( p_this, "mouse-moved",
374 &p_sys->i_last_x, &p_sys->i_last_y );
377 else
379 if( p_sys->b_button_pressed )
381 p_sys->b_button_pressed = false;
382 ProcessGesture( p_intf );
385 vlc_mutex_unlock( &p_sys->lock );
387 return VLC_SUCCESS;
390 static void
391 player_on_vout_changed(vlc_player_t *player,
392 enum vlc_player_vout_action action,
393 vout_thread_t *vout,
394 enum vlc_vout_order order,
395 vlc_es_id_t *es_id, void *data)
397 VLC_UNUSED(player); VLC_UNUSED(order);
398 intf_thread_t *intf = data;
399 intf_sys_t *sys = intf->p_sys;
401 if (vlc_es_id_GetCat(es_id) != VIDEO_ES)
402 return;
404 switch (action)
406 case VLC_PLAYER_VOUT_STARTED:
407 if (vlc_vector_push(&sys->vout_vector, vout))
409 vout_Hold(vout);
410 var_AddCallback(vout, "mouse-moved", MovedEvent, intf);
411 var_AddCallback(vout, "mouse-button-down", ButtonEvent, intf);
413 break;
414 case VLC_PLAYER_VOUT_STOPPED:
415 for (size_t i = 0; i < sys->vout_vector.size; ++i)
417 vout_thread_t *it = sys->vout_vector.data[i];
418 if (it == vout)
420 vlc_vector_remove(&sys->vout_vector, i);
421 var_DelCallback(vout, "mouse-moved", MovedEvent, intf);
422 var_DelCallback(vout, "mouse-button-down", ButtonEvent, intf);
423 vout_Release(vout);
424 break;
427 break;
428 default:
429 vlc_assert_unreachable();