add mvcp unit control
[melted_gui] / src / instance.c
1 /*
2 * instance.c -- GTK+ 2 melted gui
3 * Copyright (C) 2012 Maksym Veremeyenko <verem@m1stereo.tv>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE
22 #endif
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <pthread.h>
34
35 #include "instance.h"
36 #include "ui.h"
37 #include "opts.h"
38 #include "timecode.h"
39 #include "player.h"
40 #include "library.h"
41 #include "playlist.h"
42 #include "control.h"
43
44 GtkTargetEntry drag_targets[] = { { (char*) "application/playlist_item_t", 0, 0 } };
45
46 static gboolean library_tree_key(GtkWidget *widget, GdkEventKey *event, gpointer data)
47 {
48 instance_t* app = (instance_t*)data;
49
50 switch(event->keyval)
51 {
52 case GDK_C:
53 case GDK_c:
54 if(event->state & GDK_CONTROL_MASK)
55 {
56 int count;
57 playlist_item_t* items;
58
59 items = library_get_selected_items(app, &count);
60
61 if(items)
62 {
63 int i;
64
65 for(i = 0; i < count; i++)
66 app->clipboard.item[i] = items[i];
67
68 app->clipboard.count = count;
69 };
70
71 return TRUE;
72 };
73 break;
74 case GDK_V:
75 case GDK_v:
76 if(event->state & GDK_CONTROL_MASK)
77 {
78 g_warning("CTRL+v\n");
79 return TRUE;
80 };
81 break;
82 case GDK_X:
83 case GDK_x:
84 if(event->state & GDK_CONTROL_MASK)
85 {
86 g_warning("CTRL+x\n");
87 return TRUE;
88 };
89 break;
90 case GDK_KEY_BackSpace:
91 // omnplay_library_add(app, 0);
92 return TRUE;
93 case GDK_KEY_F5:
94 // omnplay_library_refresh(app);
95 return TRUE;
96 };
97
98 return FALSE;
99 };
100
101 static gboolean playlist_grid_key(GtkWidget *widget, GdkEventKey *event, gpointer data)
102 {
103 instance_t* app = (instance_t*)data;
104
105 switch(event->keyval)
106 {
107 case GDK_C:
108 case GDK_c:
109 if(event->state & GDK_CONTROL_MASK)
110 {
111 playlist_item_copy(app);
112 return TRUE;
113 };
114 break;
115 case GDK_V:
116 case GDK_v:
117 if(event->state & GDK_CONTROL_MASK)
118 {
119 playlist_item_paste(app, 0);
120 return TRUE;
121 };
122 break;
123 case GDK_X:
124 case GDK_x:
125 if(event->state & GDK_CONTROL_MASK)
126 {
127 playlist_item_copy(app);
128 playlist_delete_selected_items(app);
129 return TRUE;
130 };
131 break;
132 case GDK_S:
133 case GDK_s:
134 if(event->state & GDK_CONTROL_MASK)
135 {
136 playlist_save(app);
137 return TRUE;
138 };
139 break;
140 case GDK_O:
141 case GDK_o:
142 if(event->state & GDK_CONTROL_MASK)
143 {
144 playlist_load(app);
145 return TRUE;
146 };
147 break;
148 case GDK_KEY_uparrow:
149 if(event->state & GDK_CONTROL_MASK)
150 {
151 playlist_item_swap(app, -1);
152 return TRUE;
153 };
154 break;
155 case GDK_KEY_downarrow:
156 if(event->state & GDK_CONTROL_MASK)
157 {
158 playlist_item_swap(app, -1);
159 return TRUE;
160 };
161 break;
162 case GDK_KEY_space:
163 control_route(app, BUTTON_PLAYER_PLAY);
164 return TRUE;
165 case GDK_KEY_Return:
166 control_route(app, BUTTON_PLAYER_CUE);
167 return TRUE;
168 case GDK_KEY_Insert:
169 // omnplay_playlist_item_add(app, 0);
170 return TRUE;
171 case GDK_KEY_Delete:
172 playlist_delete_selected_items(app);
173 return TRUE;
174 case GDK_E:
175 case GDK_e:
176 playlist_item_edit(app);
177 return TRUE;
178 };
179
180 return FALSE;
181 };
182
183 static gboolean library_tree_button(GtkWidget *widget, GdkEventButton *event, gpointer data)
184 {
185 // g_warning("on_library_grid_button: event->button=%d, event->type=%d", event->button, event->type);
186
187 if(event->button==1 && event->type==GDK_2BUTTON_PRESS)
188 {
189 playlist_item_add_from_library((instance_t* )data, 0);
190 return TRUE;
191 };
192
193 return FALSE;
194 };
195
196 static gboolean playlist_grid_button(GtkWidget *widget, GdkEventButton *event, gpointer data)
197 {
198 instance_t* app = (instance_t*)data;
199
200 // g_warning("on_playlist_grid_button");
201
202 if(event->button==1 && event->type==GDK_2BUTTON_PRESS)
203 {
204 playlist_item_edit(app);
205 return TRUE;
206 };
207
208 return FALSE;
209 };
210
211 static gboolean instance_button_click(instance_t* app, control_buttons_t button)
212 {
213 switch(button)
214 {
215 case BUTTON_PLAYLIST_ITEM_ADD:
216 playlist_item_add(app, 0);
217 break;
218 case BUTTON_PLAYLIST_ITEM_DEL:
219 playlist_delete_selected_items(app);
220 break;
221 case BUTTON_PLAYLIST_ITEM_EDIT:
222 playlist_item_edit(app);
223 break;
224 case BUTTON_PLAYLIST_LOAD:
225 playlist_load(app);
226 break;
227 case BUTTON_PLAYLIST_SAVE:
228 playlist_save(app);
229 break;
230 case BUTTON_PLAYLIST_BLOCK_SINGLE:
231 case BUTTON_PLAYLIST_BLOCK_LOOP:
232 playlist_block(app, (BUTTON_PLAYLIST_BLOCK_LOOP == button)?1:0);
233 break;
234 case BUTTON_PLAYLIST_ITEM_UP:
235 playlist_item_swap(app, -1);
236 break;
237 case BUTTON_PLAYLIST_ITEM_DOWN:
238 playlist_item_swap(app, +1);
239 break;
240 case BUTTON_PLAYER_CUE:
241 case BUTTON_PLAYER_PLAY:
242 case BUTTON_PLAYER_PAUSE:
243 case BUTTON_PLAYER_STOP:
244 control_route(app, button);
245 break;
246 case BUTTON_LIBRARY_ADD:
247 playlist_item_add_from_library(app, 0);
248 break;
249 case BUTTON_LIBRARY_REFRESH:
250 // omnplay_library_refresh(app);
251 break;
252 case BUTTON_LIBRARY_FIND:
253 // omnplay_library_search(app, 0);
254 break;
255 case BUTTON_LIBRARY_FIND_NEXT:
256 // omnplay_library_search(app, 1);
257 break;
258 case BUTTON_PLAYLIST_RELINK:
259 // omnplay_playlist_relink(app);
260 break;
261 default:
262 g_warning("instance_button_click: unknow button clicked");
263 };
264 return TRUE;
265 };
266
267 static gboolean on_button_click(GtkWidget *button, gpointer user_data)
268 {
269 int i;
270 instance_t* app = (instance_t*)user_data;
271
272 for(i = 1; i < BUTTON_LAST; i++)
273 if(app->buttons[i] == button)
274 return instance_button_click(app, (control_buttons_t)i);
275
276 return FALSE;
277 };
278
279 static gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data )
280 {
281 g_print ("delete event occurred [start]\n");
282 gdk_threads_leave();
283 instance_release((instance_t*)user_data);
284 gdk_threads_enter();
285 g_print ("delete event occurred [finish]\n");
286
287 return FALSE;
288 }
289
290 static void on_main_window_destroy( GtkWidget *widget, gpointer user_data )
291 {
292 g_print ("destroy occurred\n");
293 gtk_main_quit();
294 }
295
296 instance_t* instance_create(int argc, char** argv)
297 {
298 int i, c;
299 instance_t* app;
300
301 /* prepare application instance */
302 app = (instance_t*)malloc(sizeof(instance_t));
303 memset(app, 0, sizeof(instance_t));
304
305 /* load parameters from command line */
306 if(!instance_opt(argc, argv, app) && app->players.count)
307 app->window = ui_create(app);
308 else
309 instance_usage();
310
311 return app;
312 };
313
314 void instance_destroy(instance_t* app)
315 {
316 free(app);
317 };
318
319 void instance_init(instance_t* app)
320 {
321 int i;
322 pthread_mutexattr_t attr;
323
324 gtk_signal_connect( GTK_OBJECT( app->window ), "delete-event",
325 GTK_SIGNAL_FUNC(on_main_window_delete_event), app);
326
327 gtk_signal_connect( GTK_OBJECT( app->window ), "destroy",
328 GTK_SIGNAL_FUNC(on_main_window_destroy), app);
329
330 gtk_widget_add_events(app->playlist_grid, GDK_BUTTON_PRESS_MASK);
331 gtk_widget_add_events(app->playlist_grid, GDK_KEY_PRESS_MASK);
332 gtk_signal_connect(GTK_OBJECT(app->playlist_grid), "key-press-event",
333 GTK_SIGNAL_FUNC(playlist_grid_key), app);
334
335 gtk_widget_add_events(app->library_tree, GDK_BUTTON_PRESS_MASK);
336 gtk_widget_add_events(app->library_tree, GDK_KEY_PRESS_MASK);
337 gtk_signal_connect(GTK_OBJECT(app->library_tree), "key-press-event",
338 GTK_SIGNAL_FUNC(library_tree_key), app);
339
340 gtk_signal_connect(GTK_OBJECT(app->playlist_grid), "button-press-event",
341 GTK_SIGNAL_FUNC(playlist_grid_button), app);
342
343 gtk_signal_connect(GTK_OBJECT(app->library_tree), "button-press-event",
344 GTK_SIGNAL_FUNC(library_tree_button), app);
345
346 /* create lock */
347 pthread_mutexattr_init(&attr);
348 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
349 pthread_mutex_init(&app->players.lock, &attr);
350 pthread_mutex_init(&app->playlist.lock, &attr);
351 pthread_mutex_init(&app->library.lock, &attr);
352 pthread_mutexattr_destroy(&attr);
353
354 /* run unit monitoring threads */
355 for(i = 0; i < app->players.count; i++)
356 player_run(app, i);
357
358 /* attach buttons click */
359 for(i = 1; i < BUTTON_LAST; i++)
360 gtk_signal_connect(GTK_OBJECT(app->buttons[i]), "clicked",
361 GTK_SIGNAL_FUNC( on_button_click), app );
362
363 /* init library */
364 library_init(app);
365
366 /* init playlist */
367 playlist_init(app);
368 };
369
370 void instance_release(instance_t* app)
371 {
372 int i;
373
374 app->f_exit = 1;
375
376 /* stop unit monitoring threads */
377 for(i = 0; i < app->players.count; i++)
378 player_stop(app, i);
379
380 /* release laylist */
381 playlist_release(app);
382
383 /* release library */
384 library_release(app);
385
386 /* destroy lock */
387 pthread_mutex_destroy(&app->players.lock);
388
389 /* destroy lock */
390 pthread_mutex_destroy(&app->playlist.lock);
391
392 /* destroy library lock */
393 pthread_mutex_destroy(&app->library.lock);
394 };