2 * omnplay.c -- GTK+ 2 omnplay
3 * Copyright (C) 2011 Maksym Veremeyenko <verem@m1stereo.tv>
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.
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.
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.
32 #include <gdk/gdkkeysyms.h>
40 #include "omplrclnt.h"
42 int omnplay_get_content(omnplay_instance_t
* app
, playlist_item_t
*items
, int limit
,
43 omnplay_get_content_cb_proc proc
, void* data
)
46 OmPlrClipInfo clip_info
;
47 char clip_name
[omPlrMaxClipDirLen
];
49 pthread_mutex_lock(&app
->players
.lock
);
51 r
= OmPlrClipGetFirst((OmPlrHandle
)app
->players
.item
[0].handle
, clip_name
, sizeof(clip_name
));
52 for(; c
< limit
&& !r
;)
55 clip_info
.maxMsTracks
= 0;
56 clip_info
.size
= sizeof(clip_info
);
58 r
= OmPlrClipGetInfo((OmPlrHandle
)app
->players
.item
[0].handle
, clip_name
, &clip_info
);
63 strncpy(items
[c
].id
, clip_name
, PATH_MAX
);
64 items
[c
].in
= clip_info
.firstFrame
;
65 items
[c
].dur
= clip_info
.lastFrame
- clip_info
.firstFrame
;
68 pthread_mutex_unlock(&app
->players
.lock
);
70 proc(app
, &items
[c
], data
);
71 pthread_mutex_lock(&app
->players
.lock
);
76 r
= OmPlrClipGetNext((OmPlrHandle
)app
->players
.item
[0].handle
, clip_name
, sizeof(clip_name
));
79 pthread_mutex_unlock(&app
->players
.lock
);
85 static gboolean
on_main_window_delete_event( GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
91 omnplay_instance_t
* omnplay_create(int argc
, char** argv
)
94 omnplay_instance_t
* app
;
96 /* prepare application instance */
97 app
= (omnplay_instance_t
*)malloc(sizeof(omnplay_instance_t
));
98 memset(app
, 0, sizeof(omnplay_instance_t
));
100 /* load parameters from command line */
101 if(!omnplay_opt(argc
, argv
, app
) && app
->players
.count
)
102 app
->window
= ui_omnplay(app
);
109 void omnplay_destroy(omnplay_instance_t
* app
)
114 static int find_index_of_playlist_item(omnplay_instance_t
* app
, int start
, int idx
)
118 if(app
->playlist
.item
[start
].omn_idx
== idx
)
121 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_END
)
130 static void omnplay_update_status(omnplay_player_t
* player
, OmPlrStatus
*prev
, OmPlrStatus
*curr
)
133 char tc_cur
[32], tc_rem
[32], state
[32], status
[32];
138 frames2tc(curr
->pos
- curr
->minPos
, 25.0, tc_cur
);
139 frames2tc(curr
->maxPos
- curr
->pos
, 25.0, tc_rem
);
140 strcpy(status
, "ONLINE");
141 clip
= curr
->currClipName
;
145 case omPlrStateStopped
: strcpy(state
, "STOPPED"); break;
146 case omPlrStateCuePlay
: strcpy(state
, "CUE_PLAY"); break;
147 case omPlrStatePlay
: strcpy(state
, "PLAY"); break;
148 case omPlrStateCueRecord
: strcpy(state
, "CUE_RECORD"); break;
149 case omPlrStateRecord
: strcpy(state
, "RECORD"); break;
158 strcpy(status
, "OFFLINE");
161 /* update status in status page */
163 gtk_label_set_text(GTK_LABEL (player
->label_tc_cur
), tc_cur
);
164 gtk_label_set_text(GTK_LABEL (player
->label_tc_rem
), tc_rem
);
165 gtk_label_set_text(GTK_LABEL (player
->label_state
), state
);
166 gtk_label_set_text(GTK_LABEL (player
->label_status
), status
);
167 gtk_label_set_text(GTK_LABEL (player
->label_clip
), clip
);
171 /* update remaining time */
173 pthread_mutex_lock(&player
->app
->playlist
.lock
);
174 pthread_mutex_lock(&player
->app
->players
.lock
);
175 if(curr
->state
== omPlrStatePlay
|| curr
->state
== omPlrStateCuePlay
)
177 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, curr
->currClipNum
);
180 frames2tc(curr
->currClipStartPos
+ curr
->currClipLen
- curr
->pos
, 25.0, tc_rem
);
181 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
183 if(curr
->currClipNum
!= prev
->currClipNum
&& 1 != prev
->numClips
)
186 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, prev
->currClipNum
);
188 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
194 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, curr
->currClipNum
);
196 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
197 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, prev
->currClipNum
);
199 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
201 pthread_mutex_unlock(&player
->app
->players
.lock
);
202 pthread_mutex_unlock(&player
->app
->playlist
.lock
);
207 memcpy(prev
, curr
, sizeof(OmPlrStatus
));
210 static void* omnplay_thread_proc(void* data
)
213 OmPlrStatus st_curr
, st_prev
;
214 omnplay_player_t
* player
= (omnplay_player_t
*)data
;
217 pthread_mutex_lock(&player
->app
->players
.lock
);
218 r
= OmPlrOpen(player
->host
, player
->name
, (OmPlrHandle
*)&player
->handle
);
219 pthread_mutex_unlock(&player
->app
->players
.lock
);
222 fprintf(stderr
, "ERROR: OmPlrOpen(%s, %s) failed with 0x%.8X\n",
223 player
->host
, player
->name
, r
);
228 /* setup to do not reconnect */
229 pthread_mutex_lock(&player
->app
->players
.lock
);
230 OmPlrSetRetryOpen((OmPlrHandle
)player
->handle
, 0);
231 pthread_mutex_unlock(&player
->app
->players
.lock
);
233 /* setup directory */
234 if(player
->app
->players
.path
[0])
236 pthread_mutex_lock(&player
->app
->players
.lock
);
237 r
= OmPlrClipSetDirectory((OmPlrHandle
)player
->handle
, player
->app
->players
.path
);
238 pthread_mutex_unlock(&player
->app
->players
.lock
);
242 fprintf(stderr
, "ERROR: OmPlrClipSetDirectory(%s) failed with 0x%.8X\n",
243 player
->app
->players
.path
, r
);
245 pthread_mutex_lock(&player
->app
->players
.lock
);
246 OmPlrClose((OmPlrHandle
)player
->handle
);
247 pthread_mutex_unlock(&player
->app
->players
.lock
);
254 for(r
= 0 ; !player
->app
->f_exit
&& !r
;)
260 pthread_mutex_lock(&player
->app
->players
.lock
);
261 st_curr
.size
= sizeof(OmPlrStatus
);
262 r
= OmPlrGetPlayerStatus((OmPlrHandle
)player
->handle
, &st_curr
);
263 pthread_mutex_unlock(&player
->app
->players
.lock
);
266 fprintf(stderr
, "ERROR: OmPlrGetPlayerStatus failed with 0x%.8X\n", r
);
268 if(memcmp(&st_curr
, &st_prev
, sizeof(OmPlrStatus
)))
269 omnplay_update_status(player
, &st_prev
, &st_curr
);
272 pthread_mutex_lock(&player
->app
->players
.lock
);
273 OmPlrClose((OmPlrHandle
)player
->handle
);
274 pthread_mutex_unlock(&player
->app
->players
.lock
);
279 void get_selected_items_playlist_proc(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer data
)
281 int idx
, *list
= (int*)data
;
282 gtk_tree_model_get(model
, iter
, 7, &idx
, -1);
283 list
[list
[0] + 1] = idx
;
284 list
[0] = list
[0] + 1;
287 static int* get_selected_items_playlist(omnplay_instance_t
* app
)
290 GtkTreeSelection
*selection
;
292 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
));
295 list
= (int*)malloc(sizeof(int) * (MAX_PLAYLIST_ITEMS
+ 1));
296 memset(list
, 0, sizeof(int) * (MAX_PLAYLIST_ITEMS
+ 1));
298 gtk_tree_selection_selected_foreach(
300 get_selected_items_playlist_proc
,
313 static int idx_in_players_range(omnplay_instance_t
* app
, int idx
)
317 for(i
= 0; i
< app
->players
.count
&& !r
; i
++)
321 a
= app
->players
.item
[i
].playlist_start
;
322 b
= app
->players
.item
[i
].playlist_length
;
329 if(idx
>= a
&& idx
<= b
) r
= 1;
335 static int idxs_in_players_range(omnplay_instance_t
* app
, int start
, int stop
)
339 for(i
= 0; i
< app
->players
.count
&& !r
; i
++)
343 a
= app
->players
.item
[i
].playlist_start
;
344 b
= app
->players
.item
[i
].playlist_length
;
351 #define IN_RANGE(A,B,C) (A <= C && C <= B)
352 if( IN_RANGE(a
,b
,start
) ||
353 IN_RANGE(a
,b
,stop
) ||
354 IN_RANGE(start
,stop
,a
) ||
355 IN_RANGE(start
,stop
,b
))
362 static void omnplay_playlist_block(omnplay_instance_t
* app
, control_buttons_t button
)
364 int start
, stop
, r
, i
;
365 int* list
= get_selected_items_playlist(app
);
370 pthread_mutex_lock(&app
->playlist
.lock
);
371 pthread_mutex_lock(&app
->players
.lock
);
374 stop
= list
[list
[0]];
376 if(!idxs_in_players_range(app
, start
, stop
))
378 int loop
= (button
== BUTTON_PLAYLIST_BLOCK_LOOP
)?OMNPLAY_PLAYLIST_BLOCK_LOOP
:0;
380 /* update selected item */
381 for(i
= start
; i
<= stop
; i
++)
383 int t
= OMNPLAY_PLAYLIST_BLOCK_BODY
| loop
;
385 if(i
== start
) t
|= OMNPLAY_PLAYLIST_BLOCK_BEGIN
;
386 if(i
== stop
) t
|= OMNPLAY_PLAYLIST_BLOCK_END
;
388 app
->playlist
.item
[i
].type
= (playlist_item_type_t
)t
;
390 omnplay_playlist_draw_item(app
, i
);
393 /* update border items */
394 if(!start
&& !(app
->playlist
.item
[start
- 1].type
& OMNPLAY_PLAYLIST_BLOCK_END
))
396 app
->playlist
.item
[start
- 1].type
= (playlist_item_type_t
)(OMNPLAY_PLAYLIST_BLOCK_END
397 | app
->playlist
.item
[start
- 1].type
);
398 omnplay_playlist_draw_item(app
, start
- 1);
400 if((stop
+ 1) < app
->playlist
.count
&& !(app
->playlist
.item
[stop
+ 1].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
))
402 app
->playlist
.item
[stop
+ 1].type
= (playlist_item_type_t
)(OMNPLAY_PLAYLIST_BLOCK_BEGIN
403 | app
->playlist
.item
[stop
+ 1].type
);
404 omnplay_playlist_draw_item(app
, stop
+ 1);
408 fprintf(stderr
, "omnplay_playlist_block: range [%d %d] do OVERLAP player\n",
411 pthread_mutex_unlock(&app
->players
.lock
);
412 pthread_mutex_unlock(&app
->playlist
.lock
);
417 static int get_first_selected_item_playlist(omnplay_instance_t
* app
)
420 int* list
= get_selected_items_playlist(app
);
427 static int get_playlist_block(omnplay_instance_t
* app
, int idx
, int* start_ptr
, int* stop_ptr
)
431 for(start
= idx
; start
>= 0; start
--)
432 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
)
435 for(stop
= idx
; stop
< app
->playlist
.count
; stop
++)
436 if(app
->playlist
.item
[stop
].type
& OMNPLAY_PLAYLIST_BLOCK_END
)
439 fprintf(stderr
, "get_playlist_block: range %d -> %d\n", start
, stop
);
441 /* check block range */
442 if(start
>= 0 && stop
< app
->playlist
.count
)
446 return (stop
- start
+ 1);
452 static omnplay_player_t
*get_player_at_pos(omnplay_instance_t
* app
, int pos
)
454 /* check player range */
455 if(app
->playlist
.item
[pos
].player
> -1 && app
->playlist
.item
[pos
].player
< app
->players
.count
)
456 return &app
->players
.item
[app
->playlist
.item
[pos
].player
];
461 static void omnplay_playlist_delete_items(omnplay_instance_t
* app
, int* idxs
, int count
)
466 pthread_mutex_lock(&app
->playlist
.lock
);
467 pthread_mutex_lock(&app
->players
.lock
);
469 for(j
= 0; j
< count
; j
++)
473 /* fix block types */
475 app
->playlist
.item
[idx
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
- 1].type
|
476 OMNPLAY_PLAYLIST_BLOCK_END
);
477 if(idx
+ 1 < app
->playlist
.count
)
478 app
->playlist
.item
[idx
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
+ 1].type
|
479 OMNPLAY_PLAYLIST_BLOCK_BEGIN
);
481 /* shift playlist items */
484 &app
->playlist
.item
[idx
],
485 &app
->playlist
.item
[idx
+ 1],
486 (app
->playlist
.count
- idx
- 1) * sizeof(playlist_item_t
)
489 /* decrement items count */
490 app
->playlist
.count
--;
492 /* increment servers indexes */
493 for(i
= 0; i
< app
->players
.count
; i
++)
494 if(app
->players
.item
[i
].playlist_start
>= idx
)
495 app
->players
.item
[i
].playlist_start
--;
500 /* redraw playlist */
501 omnplay_playlist_draw(app
);
504 path
= gtk_tree_path_new_from_indices(idxs
[0], -1);
505 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
506 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
507 gtk_tree_path_free(path
);
510 pthread_mutex_unlock(&app
->players
.lock
);
511 pthread_mutex_unlock(&app
->playlist
.lock
);
514 static void omnplay_playlist_item_del(omnplay_instance_t
* app
)
519 list
= get_selected_items_playlist(app
);
522 list2
= (int*)malloc(sizeof(int) * list
[0]);
524 for(i
= 0, c
= 0; i
< list
[0]; i
++)
526 /* check for playing block */
527 if(idx_in_players_range(app
, list
[i
+ 1]))
531 list2
[c
++] = list
[i
+ 1];
535 omnplay_playlist_delete_items(app
, list2
, c
);
541 static int omnplay_playlist_insert_check(omnplay_instance_t
* app
, int idx
, playlist_item_type_t
* t
)
543 *t
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
545 /* before or after playlist */
546 if(!idx
|| idx
== app
->playlist
.count
)
549 /* check for block borders */
550 if( app
->playlist
.item
[idx
- 1].type
& OMNPLAY_PLAYLIST_BLOCK_END
&&
551 app
->playlist
.item
[idx
+ 0].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
)
554 /* check for playing block */
555 if(idx_in_players_range(app
, idx
))
558 if(app
->playlist
.item
[idx
].type
& OMNPLAY_PLAYLIST_BLOCK_LOOP
)
559 *t
= OMNPLAY_PLAYLIST_ITEM_LOOP_BODY
;
561 *t
= OMNPLAY_PLAYLIST_ITEM_BLOCK_BODY
;
566 static void omnplay_playlist_insert_items(omnplay_instance_t
* app
, int idx
,
567 playlist_item_t
* items
, int count
)
572 pthread_mutex_lock(&app
->playlist
.lock
);
573 pthread_mutex_lock(&app
->players
.lock
);
575 /* shift playlist items */
578 &app
->playlist
.item
[idx
+ count
],
579 &app
->playlist
.item
[idx
],
580 (app
->playlist
.count
- idx
) * sizeof(playlist_item_t
)
586 &app
->playlist
.item
[idx
],
588 count
* sizeof(playlist_item_t
)
591 /* increment servers indexes */
592 for(i
= 0; i
< app
->players
.count
; i
++)
593 if(app
->players
.item
[i
].playlist_start
>= idx
)
594 app
->players
.item
[i
].playlist_start
+= idx
;
596 /* increment items count */
597 app
->playlist
.count
+= count
;
599 /* redraw playlist */
600 omnplay_playlist_draw(app
);
603 path
= gtk_tree_path_new_from_indices(idx
+ count
, -1);
604 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
605 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
606 gtk_tree_path_free(path
);
608 pthread_mutex_unlock(&app
->players
.lock
);
609 pthread_mutex_unlock(&app
->playlist
.lock
);
612 static void omnplay_playlist_item_add(omnplay_instance_t
* app
, int after
)
615 playlist_item_t item
;
616 playlist_item_type_t t
;
618 /* find insert position */
619 idx
= get_first_selected_item_playlist(app
);
625 if(!omnplay_playlist_insert_check(app
, idx
, &t
))
628 fprintf(stderr
, "allowed insert into idx=%d\n", idx
);
631 memset(&item
, 0, sizeof(playlist_item_t
));
632 if(ui_playlist_item_dialog(app
, &item
))
635 omnplay_playlist_insert_items(app
, idx
, &item
, 1);
639 static void omnplay_playlist_item_edit(omnplay_instance_t
* app
)
642 playlist_item_t item
;
644 /* find insert position */
645 idx
= get_first_selected_item_playlist(app
);
650 /* check for playing block */
651 if(idx_in_players_range(app
, idx
))
654 item
= app
->playlist
.item
[idx
];
656 if(ui_playlist_item_dialog(app
, &item
))
658 app
->playlist
.item
[idx
] = item
;
659 omnplay_playlist_draw_item(app
, idx
);
663 static void omnplay_ctl(omnplay_instance_t
* app
, control_buttons_t button
)
666 int idx
, start
, stop
;
667 omnplay_player_t
*player
;
669 pthread_mutex_lock(&app
->playlist
.lock
);
671 idx
= get_first_selected_item_playlist(app
);
675 pthread_mutex_unlock(&app
->playlist
.lock
);
679 fprintf(stderr
, "cue: selected item is %d\n", idx
);
681 if(get_playlist_block(app
, idx
, &start
, &stop
) < 0)
683 pthread_mutex_unlock(&app
->playlist
.lock
);
687 fprintf(stderr
, "cue: range %d -> %d\n", start
, stop
);
689 player
= get_player_at_pos(app
, start
);
693 pthread_mutex_unlock(&app
->playlist
.lock
);
697 pthread_mutex_lock(&app
->players
.lock
);
699 if(BUTTON_PLAYER_STOP
== button
|| BUTTON_PLAYER_CUE
== button
)
702 OmPlrStop((OmPlrHandle
)player
->handle
);
704 /* detach previous clips */
705 player
->playlist_length
= -1;
706 OmPlrDetachAllClips((OmPlrHandle
)player
->handle
);
709 if(BUTTON_PLAYER_CUE
== button
)
713 /* Attach clips to timeline */
714 for(i
= start
, c
= 0, o
= 0; i
<= stop
; i
++)
719 clip
.maxMsTracks
= 0;
720 clip
.size
= sizeof(clip
);
721 r
= OmPlrClipGetInfo((OmPlrHandle
)player
->handle
, app
->playlist
.item
[i
].id
, &clip
);
727 fprintf(stderr
, "OmPlrClipGetInfo(%s): firstFrame=%d, lastFrame=%d\n",
728 app
->playlist
.item
[i
].id
, clip
.firstFrame
, clip
.lastFrame
);
730 /* should we fix playlist clip timings */
732 app
->playlist
.item
[i
].in
>= clip
.firstFrame
&&
733 app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
<= clip
.lastFrame
) ||
734 !app
->playlist
.item
[i
].dur
)
736 fprintf(stderr
, "cue: item [%s] will be updated [%d;%d]->[%d;%d]\n",
737 app
->playlist
.item
[i
].id
,
738 app
->playlist
.item
[i
].in
, app
->playlist
.item
[i
].dur
,
739 clip
.firstFrame
, clip
.lastFrame
- clip
.firstFrame
);
741 app
->playlist
.item
[i
].in
= clip
.firstFrame
;
742 app
->playlist
.item
[i
].dur
= clip
.lastFrame
- clip
.firstFrame
;
743 omnplay_playlist_draw_item(app
, i
);
746 r
= OmPlrAttach((OmPlrHandle
)player
->handle
,
747 app
->playlist
.item
[i
].id
,
748 app
->playlist
.item
[i
].in
,
749 app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
,
750 0, omPlrShiftModeAfter
, &l
);
755 fprintf(stderr
, "cue: failed with %d, %s\n", r
, OmPlrGetErrorString((OmPlrError
)r
));
756 app
->playlist
.item
[i
].omn_idx
= -1;
757 app
->playlist
.item
[i
].omn_offset
= -1;
761 app
->playlist
.item
[i
].omn_idx
= c
;
762 app
->playlist
.item
[i
].omn_offset
= o
;
764 /* save selected item offset */
768 o
+= app
->playlist
.item
[i
].dur
;
776 /* Set timeline min/max */
777 OmPlrSetMinPosMin((OmPlrHandle
)player
->handle
);
778 OmPlrSetMaxPosMax((OmPlrHandle
)player
->handle
);
780 /* Set timeline position */
782 hs
.size
= sizeof(OmPlrStatus
);
783 OmPlrGetPlayerStatus((OmPlrHandle
)player
->handle
, &hs
);
784 OmPlrSetPos((OmPlrHandle
)player
->handle
, hs
.minPos
+ p
);
787 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_LOOP
)
788 OmPlrLoop((OmPlrHandle
)player
->handle
, hs
.minPos
, hs
.maxPos
);
790 OmPlrLoop((OmPlrHandle
)player
->handle
, hs
.minPos
, hs
.minPos
);
792 player
->playlist_start
= start
;
793 player
->playlist_length
= stop
- start
+ 1;
796 OmPlrCuePlay((OmPlrHandle
)player
->handle
, 0.0);
800 if(BUTTON_PLAYER_PLAY
== button
)
803 OmPlrPlay((OmPlrHandle
)player
->handle
, 1.0);
806 if(BUTTON_PLAYER_PAUSE
== button
)
808 OmPlrPlay((OmPlrHandle
)player
->handle
, 0.0);
810 pthread_mutex_unlock(&app
->players
.lock
);
812 pthread_mutex_unlock(&app
->playlist
.lock
);
815 static void omnplay_playlist_item_swap(omnplay_instance_t
* app
, int dir
)
819 playlist_item_t item
;
821 /* find insert position */
822 sel
= get_first_selected_item_playlist(app
);
839 /* check for playing block */
840 if(idx_in_players_range(app
, a
) || idx_in_players_range(app
, b
))
843 pthread_mutex_lock(&app
->playlist
.lock
);
844 pthread_mutex_lock(&app
->players
.lock
);
847 item
= app
->playlist
.item
[a
];
848 app
->playlist
.item
[a
] = app
->playlist
.item
[b
];
849 app
->playlist
.item
[b
] = item
;
852 app
->playlist
.item
[a
].type
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
853 app
->playlist
.item
[b
].type
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
855 /* redraw main items */
856 omnplay_playlist_draw_item(app
, a
);
857 omnplay_playlist_draw_item(app
, b
);
859 /* fix block types */
862 app
->playlist
.item
[a
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[a
- 1].type
|
863 OMNPLAY_PLAYLIST_BLOCK_END
);
864 omnplay_playlist_draw_item(app
, a
- 1);
866 if(b
+ 1 < app
->playlist
.count
)
868 app
->playlist
.item
[b
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[b
+ 1].type
|
869 OMNPLAY_PLAYLIST_BLOCK_BEGIN
);
870 omnplay_playlist_draw_item(app
, b
+ 1);
874 path
= gtk_tree_path_new_from_indices(sel
, -1);
875 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
876 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
877 gtk_tree_path_free(path
);
879 pthread_mutex_unlock(&app
->players
.lock
);
880 pthread_mutex_unlock(&app
->playlist
.lock
);
883 static gboolean
omnplay_button_click(omnplay_instance_t
* app
, control_buttons_t button
)
887 case BUTTON_PLAYLIST_ITEM_ADD
:
888 omnplay_playlist_item_add(app
, 0);
890 case BUTTON_PLAYLIST_ITEM_DEL
:
891 omnplay_playlist_item_del(app
);
893 case BUTTON_PLAYLIST_ITEM_EDIT
:
894 omnplay_playlist_item_edit(app
);
896 case BUTTON_PLAYLIST_LOAD
:
897 omnplay_playlist_load(app
);
899 case BUTTON_PLAYLIST_SAVE
:
900 omnplay_playlist_save(app
);
902 case BUTTON_PLAYLIST_BLOCK_SINGLE
:
903 case BUTTON_PLAYLIST_BLOCK_LOOP
:
904 omnplay_playlist_block(app
, button
);
906 case BUTTON_PLAYLIST_ITEM_UP
:
907 omnplay_playlist_item_swap(app
, -1);
909 case BUTTON_PLAYLIST_ITEM_DOWN
:
910 omnplay_playlist_item_swap(app
, +1);
912 case BUTTON_PLAYER_CUE
:
913 case BUTTON_PLAYER_PLAY
:
914 case BUTTON_PLAYER_PAUSE
:
915 case BUTTON_PLAYER_STOP
:
916 omnplay_ctl(app
, button
);
918 case BUTTON_LIBRARY_ADD
:
920 case BUTTON_LIBRARY_REFRESH
:
921 omnplay_library_refresh(app
);
928 static gboolean
on_button_click(GtkWidget
*button
, gpointer user_data
)
931 omnplay_instance_t
* app
= (omnplay_instance_t
*)user_data
;
933 for(i
= 1; i
< BUTTON_LAST
; i
++)
934 if(app
->buttons
[i
] == button
)
935 return omnplay_button_click(app
, (control_buttons_t
)i
);
940 static gboolean
on_playlist_grid_key(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
942 omnplay_instance_t
* app
= (omnplay_instance_t
*)data
;
944 switch(event
->keyval
)
948 if(event
->state
& GDK_CONTROL_MASK
)
950 fprintf(stderr
, "CTRL+c\n");
956 if(event
->state
& GDK_CONTROL_MASK
)
958 fprintf(stderr
, "CTRL+v\n");
964 if(event
->state
& GDK_CONTROL_MASK
)
966 fprintf(stderr
, "CTRL+x\n");
971 omnplay_ctl(app
, BUTTON_PLAYER_PLAY
);
974 omnplay_ctl(app
, BUTTON_PLAYER_CUE
);
977 omnplay_playlist_item_add(app
, 0);
980 omnplay_playlist_item_del(app
);
982 case GDK_KEY_BackSpace
:
983 omnplay_playlist_item_edit(app
);
990 void omnplay_init(omnplay_instance_t
* app
)
993 pthread_mutexattr_t attr
;
995 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
997 gtk_signal_connect( GTK_OBJECT( app
->window
), "destroy",
998 GTK_SIGNAL_FUNC(on_main_window_delete_event
), app
);
1000 gtk_widget_add_events(app
->playlist_grid
, GDK_BUTTON_PRESS_MASK
);
1001 gtk_signal_connect(GTK_OBJECT(app
->playlist_grid
), "key-press-event",
1002 GTK_SIGNAL_FUNC(on_playlist_grid_key
), app
);
1005 pthread_mutex_init(&app
->players
.lock
, &attr
);
1007 /* create a omneon status thread */
1008 for(i
= 0; i
< app
->players
.count
; i
++)
1009 pthread_create(&app
->players
.item
[i
].thread
, NULL
,
1010 omnplay_thread_proc
, &app
->players
.item
[i
]);
1013 pthread_mutex_init(&app
->playlist
.lock
, &attr
);
1015 /* attach buttons click */
1016 for(i
= 1; i
< BUTTON_LAST
; i
++)
1017 gtk_signal_connect(GTK_OBJECT(app
->buttons
[i
]), "clicked",
1018 GTK_SIGNAL_FUNC( on_button_click
), app
);
1021 pthread_mutex_init(&app
->library
.lock
, &attr
);
1024 omnplay_library_load(app
);
1027 void omnplay_release(omnplay_instance_t
* app
)
1034 for(i
= 0; i
< app
->players
.count
; i
++)
1035 /* create a omneon status thread */
1036 pthread_join(app
->players
.item
[i
].thread
, &r
);
1039 pthread_mutex_destroy(&app
->players
.lock
);
1042 pthread_mutex_destroy(&app
->playlist
.lock
);
1045 omnplay_library_save(app
);
1047 /* destroy library lock */
1048 pthread_mutex_destroy(&app
->library
.lock
);