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
)
87 g_print ("delete event occurred [start]\n");
89 omnplay_release((omnplay_instance_t
*)user_data
);
91 g_print ("delete event occurred [finish]\n");
96 static void on_main_window_destroy( GtkWidget
*widget
, gpointer user_data
)
98 g_print ("destroy occurred\n");
102 omnplay_instance_t
* omnplay_create(int argc
, char** argv
)
105 omnplay_instance_t
* app
;
107 /* prepare application instance */
108 app
= (omnplay_instance_t
*)malloc(sizeof(omnplay_instance_t
));
109 memset(app
, 0, sizeof(omnplay_instance_t
));
111 /* load parameters from command line */
112 if(!omnplay_opt(argc
, argv
, app
) && app
->players
.count
)
113 app
->window
= ui_omnplay(app
);
120 void omnplay_destroy(omnplay_instance_t
* app
)
125 static int find_index_of_playlist_item(omnplay_instance_t
* app
, int start
, int idx
)
129 if(app
->playlist
.item
[start
].omn_idx
== idx
)
132 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_END
)
141 static void omnplay_update_status(omnplay_player_t
* player
, OmPlrStatus
*prev
, OmPlrStatus
*curr
)
144 char tc_cur
[32], tc_rem
[32], state
[32], status
[32];
149 frames2tc(curr
->pos
- curr
->minPos
, 25.0, tc_cur
);
150 frames2tc(curr
->maxPos
- curr
->pos
, 25.0, tc_rem
);
151 strcpy(status
, "ONLINE");
152 clip
= curr
->currClipName
;
156 case omPlrStateStopped
: strcpy(state
, "STOPPED"); break;
157 case omPlrStateCuePlay
: strcpy(state
, "CUE_PLAY"); break;
158 case omPlrStatePlay
: strcpy(state
, "PLAY"); break;
159 case omPlrStateCueRecord
: strcpy(state
, "CUE_RECORD"); break;
160 case omPlrStateRecord
: strcpy(state
, "RECORD"); break;
169 strcpy(status
, "OFFLINE");
172 /* update status in status page */
174 gtk_label_set_text(GTK_LABEL (player
->label_tc_cur
), tc_cur
);
175 gtk_label_set_text(GTK_LABEL (player
->label_tc_rem
), tc_rem
);
176 gtk_label_set_text(GTK_LABEL (player
->label_state
), state
);
177 gtk_label_set_text(GTK_LABEL (player
->label_status
), status
);
178 gtk_label_set_text(GTK_LABEL (player
->label_clip
), clip
);
182 /* update remaining time */
184 pthread_mutex_lock(&player
->app
->playlist
.lock
);
185 pthread_mutex_lock(&player
->app
->players
.lock
);
186 if(curr
->state
== omPlrStatePlay
|| curr
->state
== omPlrStateCuePlay
)
188 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, curr
->currClipNum
);
191 frames2tc(curr
->currClipStartPos
+ curr
->currClipLen
- curr
->pos
, 25.0, tc_rem
);
192 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
194 if(curr
->currClipNum
!= prev
->currClipNum
&& 1 != prev
->numClips
)
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
);
205 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, curr
->currClipNum
);
207 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
208 idx
= find_index_of_playlist_item(player
->app
, player
->playlist_start
, prev
->currClipNum
);
210 omnplay_playlist_draw_item_rem(player
->app
, idx
, tc_rem
);
212 pthread_mutex_unlock(&player
->app
->players
.lock
);
213 pthread_mutex_unlock(&player
->app
->playlist
.lock
);
218 memcpy(prev
, curr
, sizeof(OmPlrStatus
));
221 static void* omnplay_thread_proc(void* data
)
224 OmPlrStatus st_curr
, st_prev
;
225 omnplay_player_t
* player
= (omnplay_player_t
*)data
;
227 g_warning("omnplay_thread_proc\n");
230 pthread_mutex_lock(&player
->app
->players
.lock
);
231 r
= OmPlrOpen(player
->host
, player
->name
, (OmPlrHandle
*)&player
->handle
);
232 pthread_mutex_unlock(&player
->app
->players
.lock
);
235 g_warning("ERROR: OmPlrOpen(%s, %s) failed with 0x%.8X\n",
236 player
->host
, player
->name
, r
);
241 /* setup to do not reconnect */
242 pthread_mutex_lock(&player
->app
->players
.lock
);
243 OmPlrSetRetryOpen((OmPlrHandle
)player
->handle
, 0);
244 pthread_mutex_unlock(&player
->app
->players
.lock
);
246 /* setup directory */
247 if(player
->app
->players
.path
[0])
249 pthread_mutex_lock(&player
->app
->players
.lock
);
250 r
= OmPlrClipSetDirectory((OmPlrHandle
)player
->handle
, player
->app
->players
.path
);
251 pthread_mutex_unlock(&player
->app
->players
.lock
);
255 g_warning("ERROR: OmPlrClipSetDirectory(%s) failed with 0x%.8X\n",
256 player
->app
->players
.path
, r
);
258 pthread_mutex_lock(&player
->app
->players
.lock
);
259 OmPlrClose((OmPlrHandle
)player
->handle
);
260 pthread_mutex_unlock(&player
->app
->players
.lock
);
267 for(r
= 0 ; !player
->app
->f_exit
&& !r
;)
277 pthread_mutex_lock(&player
->app
->players
.lock
);
278 st_curr
.size
= sizeof(OmPlrStatus
);
279 r
= OmPlrGetPlayerStatus((OmPlrHandle
)player
->handle
, &st_curr
);
280 pthread_mutex_unlock(&player
->app
->players
.lock
);
283 g_warning("ERROR: OmPlrGetPlayerStatus failed with 0x%.8X\n", r
);
285 if(memcmp(&st_curr
, &st_prev
, sizeof(OmPlrStatus
)))
286 omnplay_update_status(player
, &st_prev
, &st_curr
);
289 pthread_mutex_lock(&player
->app
->players
.lock
);
290 OmPlrClose((OmPlrHandle
)player
->handle
);
291 pthread_mutex_unlock(&player
->app
->players
.lock
);
296 void get_selected_items_playlist_proc(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer data
)
298 int idx
, *list
= (int*)data
;
299 gtk_tree_model_get(model
, iter
, 7, &idx
, -1);
300 list
[list
[0] + 1] = idx
;
301 list
[0] = list
[0] + 1;
304 static int* get_selected_items_playlist(omnplay_instance_t
* app
)
307 GtkTreeSelection
*selection
;
309 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
));
312 list
= (int*)malloc(sizeof(int) * (MAX_PLAYLIST_ITEMS
+ 1));
313 memset(list
, 0, sizeof(int) * (MAX_PLAYLIST_ITEMS
+ 1));
315 gtk_tree_selection_selected_foreach(
317 get_selected_items_playlist_proc
,
330 static int idx_in_players_range(omnplay_instance_t
* app
, int idx
)
334 for(i
= 0; i
< app
->players
.count
&& !r
; i
++)
338 a
= app
->players
.item
[i
].playlist_start
;
339 b
= app
->players
.item
[i
].playlist_length
;
346 if(idx
>= a
&& idx
<= b
) r
= 1;
352 static int idxs_in_players_range(omnplay_instance_t
* app
, int start
, int stop
)
356 for(i
= 0; i
< app
->players
.count
&& !r
; i
++)
360 a
= app
->players
.item
[i
].playlist_start
;
361 b
= app
->players
.item
[i
].playlist_length
;
368 #define IN_RANGE(A,B,C) (A <= C && C <= B)
369 if( IN_RANGE(a
,b
,start
) ||
370 IN_RANGE(a
,b
,stop
) ||
371 IN_RANGE(start
,stop
,a
) ||
372 IN_RANGE(start
,stop
,b
))
379 static void omnplay_playlist_block(omnplay_instance_t
* app
, control_buttons_t button
)
381 int start
, stop
, r
, i
;
382 int* list
= get_selected_items_playlist(app
);
387 pthread_mutex_lock(&app
->playlist
.lock
);
388 pthread_mutex_lock(&app
->players
.lock
);
391 stop
= list
[list
[0]];
393 if(!idxs_in_players_range(app
, start
, stop
))
395 int loop
= (button
== BUTTON_PLAYLIST_BLOCK_LOOP
)?OMNPLAY_PLAYLIST_BLOCK_LOOP
:0;
397 /* update selected item */
398 for(i
= start
; i
<= stop
; i
++)
400 int t
= OMNPLAY_PLAYLIST_BLOCK_BODY
| loop
;
402 if(i
== start
) t
|= OMNPLAY_PLAYLIST_BLOCK_BEGIN
;
403 if(i
== stop
) t
|= OMNPLAY_PLAYLIST_BLOCK_END
;
405 app
->playlist
.item
[i
].type
= (playlist_item_type_t
)t
;
407 omnplay_playlist_draw_item(app
, i
);
410 /* update border items */
411 if(start
&& !(app
->playlist
.item
[start
- 1].type
& OMNPLAY_PLAYLIST_BLOCK_END
))
413 app
->playlist
.item
[start
- 1].type
= (playlist_item_type_t
)(OMNPLAY_PLAYLIST_BLOCK_END
414 | app
->playlist
.item
[start
- 1].type
);
415 omnplay_playlist_draw_item(app
, start
- 1);
417 if((stop
+ 1) < app
->playlist
.count
&& !(app
->playlist
.item
[stop
+ 1].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
))
419 app
->playlist
.item
[stop
+ 1].type
= (playlist_item_type_t
)(OMNPLAY_PLAYLIST_BLOCK_BEGIN
420 | app
->playlist
.item
[stop
+ 1].type
);
421 omnplay_playlist_draw_item(app
, stop
+ 1);
425 g_warning("omnplay_playlist_block: range [%d %d] do OVERLAP player\n",
428 pthread_mutex_unlock(&app
->players
.lock
);
429 pthread_mutex_unlock(&app
->playlist
.lock
);
434 static int get_first_selected_item_playlist(omnplay_instance_t
* app
)
437 int* list
= get_selected_items_playlist(app
);
444 static int get_playlist_block(omnplay_instance_t
* app
, int idx
, int* start_ptr
, int* stop_ptr
)
448 for(start
= idx
; start
>= 0; start
--)
449 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
)
452 for(stop
= idx
; stop
< app
->playlist
.count
; stop
++)
453 if(app
->playlist
.item
[stop
].type
& OMNPLAY_PLAYLIST_BLOCK_END
)
456 g_warning("get_playlist_block: range %d -> %d\n", start
, stop
);
458 /* check block range */
459 if(start
>= 0 && stop
< app
->playlist
.count
)
463 return (stop
- start
+ 1);
469 static omnplay_player_t
*get_player_at_pos(omnplay_instance_t
* app
, int pos
)
471 /* check player range */
472 if(app
->playlist
.item
[pos
].player
> -1 && app
->playlist
.item
[pos
].player
< app
->players
.count
)
473 return &app
->players
.item
[app
->playlist
.item
[pos
].player
];
478 static void omnplay_playlist_delete_items(omnplay_instance_t
* app
, int* idxs
, int count
)
483 pthread_mutex_lock(&app
->playlist
.lock
);
484 pthread_mutex_lock(&app
->players
.lock
);
486 for(j
= 0; j
< count
; j
++)
490 /* fix block types */
491 if( app
->playlist
.item
[idx
].type
!= OMNPLAY_PLAYLIST_ITEM_BLOCK_BODY
&&
492 app
->playlist
.item
[idx
].type
!= OMNPLAY_PLAYLIST_ITEM_LOOP_BODY
)
495 app
->playlist
.item
[idx
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
- 1].type
|
496 OMNPLAY_PLAYLIST_BLOCK_END
);
497 if(idx
+ 1 < app
->playlist
.count
)
498 app
->playlist
.item
[idx
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
+ 1].type
|
499 OMNPLAY_PLAYLIST_BLOCK_BEGIN
);
502 /* shift playlist items */
505 &app
->playlist
.item
[idx
],
506 &app
->playlist
.item
[idx
+ 1],
507 (app
->playlist
.count
- idx
- 1) * sizeof(playlist_item_t
)
510 /* decrement items count */
511 app
->playlist
.count
--;
513 /* increment servers indexes */
514 for(i
= 0; i
< app
->players
.count
; i
++)
515 if(app
->players
.item
[i
].playlist_start
>= idx
)
516 app
->players
.item
[i
].playlist_start
--;
521 /* redraw playlist */
522 omnplay_playlist_draw(app
);
525 path
= gtk_tree_path_new_from_indices(idxs
[0], -1);
526 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
527 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
528 gtk_tree_path_free(path
);
531 pthread_mutex_unlock(&app
->players
.lock
);
532 pthread_mutex_unlock(&app
->playlist
.lock
);
535 static void omnplay_playlist_item_del(omnplay_instance_t
* app
)
540 list
= get_selected_items_playlist(app
);
543 list2
= (int*)malloc(sizeof(int) * list
[0]);
545 for(i
= 0, c
= 0; i
< list
[0]; i
++)
547 /* check for playing block */
548 if(idx_in_players_range(app
, list
[i
+ 1]))
552 list2
[c
++] = list
[i
+ 1];
556 omnplay_playlist_delete_items(app
, list2
, c
);
562 static int omnplay_playlist_insert_check(omnplay_instance_t
* app
, int idx
, playlist_item_type_t
* t
)
564 *t
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
566 /* before or after playlist */
567 if(!idx
|| idx
== app
->playlist
.count
)
570 /* check for block borders */
571 if( app
->playlist
.item
[idx
- 1].type
& OMNPLAY_PLAYLIST_BLOCK_END
&&
572 app
->playlist
.item
[idx
+ 0].type
& OMNPLAY_PLAYLIST_BLOCK_BEGIN
)
575 /* check for playing block */
576 if(idx_in_players_range(app
, idx
))
579 if(app
->playlist
.item
[idx
].type
& OMNPLAY_PLAYLIST_BLOCK_LOOP
)
580 *t
= OMNPLAY_PLAYLIST_ITEM_LOOP_BODY
;
582 *t
= OMNPLAY_PLAYLIST_ITEM_BLOCK_BODY
;
587 static void omnplay_playlist_insert_items(omnplay_instance_t
* app
, int idx
,
588 playlist_item_t
* items
, int count
)
593 pthread_mutex_lock(&app
->playlist
.lock
);
594 pthread_mutex_lock(&app
->players
.lock
);
596 /* shift playlist items */
599 &app
->playlist
.item
[idx
+ count
],
600 &app
->playlist
.item
[idx
],
601 (app
->playlist
.count
- idx
) * sizeof(playlist_item_t
)
607 &app
->playlist
.item
[idx
],
609 count
* sizeof(playlist_item_t
)
612 /* increment servers indexes */
613 for(i
= 0; i
< app
->players
.count
; i
++)
614 if(app
->players
.item
[i
].playlist_start
>= idx
)
615 app
->players
.item
[i
].playlist_start
+= idx
;
617 /* increment items count */
618 app
->playlist
.count
+= count
;
620 /* redraw playlist */
621 omnplay_playlist_draw(app
);
624 path
= gtk_tree_path_new_from_indices(idx
+ count
, -1);
625 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
626 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
627 gtk_tree_path_free(path
);
629 pthread_mutex_unlock(&app
->players
.lock
);
630 pthread_mutex_unlock(&app
->playlist
.lock
);
633 static void omnplay_playlist_item_add(omnplay_instance_t
* app
, int after
)
636 playlist_item_t item
;
637 playlist_item_type_t t
;
639 /* find insert position */
640 idx
= get_first_selected_item_playlist(app
);
646 if(!omnplay_playlist_insert_check(app
, idx
, &t
))
649 g_warning("allowed insert into idx=%d\n", idx
);
652 memset(&item
, 0, sizeof(playlist_item_t
));
653 if(ui_playlist_item_dialog(app
, &item
))
655 omnplay_library_normalize_item(app
, &item
);
657 omnplay_playlist_insert_items(app
, idx
, &item
, 1);
661 static void omnplay_playlist_item_edit(omnplay_instance_t
* app
)
664 playlist_item_t item
;
666 /* find insert position */
667 idx
= get_first_selected_item_playlist(app
);
672 /* check for playing block */
673 if(idx_in_players_range(app
, idx
))
676 item
= app
->playlist
.item
[idx
];
678 if(ui_playlist_item_dialog(app
, &item
))
680 omnplay_library_normalize_item(app
, &item
);
681 app
->playlist
.item
[idx
] = item
;
682 omnplay_playlist_draw_item(app
, idx
);
686 static void omnplay_ctl(omnplay_instance_t
* app
, control_buttons_t button
)
689 int idx
, start
, stop
;
690 omnplay_player_t
*player
;
692 pthread_mutex_lock(&app
->playlist
.lock
);
694 idx
= get_first_selected_item_playlist(app
);
698 pthread_mutex_unlock(&app
->playlist
.lock
);
702 g_warning("cue: selected item is %d\n", idx
);
704 if(get_playlist_block(app
, idx
, &start
, &stop
) < 0)
706 pthread_mutex_unlock(&app
->playlist
.lock
);
710 g_warning("cue: range %d -> %d\n", start
, stop
);
712 player
= get_player_at_pos(app
, start
);
716 pthread_mutex_unlock(&app
->playlist
.lock
);
720 pthread_mutex_lock(&app
->players
.lock
);
722 if(BUTTON_PLAYER_STOP
== button
|| BUTTON_PLAYER_CUE
== button
)
725 OmPlrStop((OmPlrHandle
)player
->handle
);
727 /* detach previous clips */
728 player
->playlist_length
= -1;
729 OmPlrDetachAllClips((OmPlrHandle
)player
->handle
);
732 if(BUTTON_PLAYER_CUE
== button
)
736 /* Attach clips to timeline */
737 for(i
= start
, c
= 0, o
= 0; i
<= stop
; i
++)
742 clip
.maxMsTracks
= 0;
743 clip
.size
= sizeof(clip
);
744 r
= OmPlrClipGetInfo((OmPlrHandle
)player
->handle
, app
->playlist
.item
[i
].id
, &clip
);
750 g_warning("OmPlrClipGetInfo(%s): firstFrame=%d, lastFrame=%d\n",
751 app
->playlist
.item
[i
].id
, clip
.firstFrame
, clip
.lastFrame
);
753 /* should we fix playlist clip timings */
755 app
->playlist
.item
[i
].in
>= clip
.firstFrame
&&
756 app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
<= clip
.lastFrame
) ||
757 !app
->playlist
.item
[i
].dur
)
759 g_warning("cue: item [%s] will be updated [%d;%d]->[%d;%d]\n",
760 app
->playlist
.item
[i
].id
,
761 app
->playlist
.item
[i
].in
, app
->playlist
.item
[i
].dur
,
762 clip
.firstFrame
, clip
.lastFrame
- clip
.firstFrame
);
764 app
->playlist
.item
[i
].in
= clip
.firstFrame
;
765 app
->playlist
.item
[i
].dur
= clip
.lastFrame
- clip
.firstFrame
;
766 omnplay_playlist_draw_item(app
, i
);
769 r
= OmPlrAttach((OmPlrHandle
)player
->handle
,
770 app
->playlist
.item
[i
].id
,
771 app
->playlist
.item
[i
].in
,
772 app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
,
773 0, omPlrShiftModeAfter
, &l
);
778 g_warning("cue: failed with %d, %s\n", r
, OmPlrGetErrorString((OmPlrError
)r
));
779 app
->playlist
.item
[i
].omn_idx
= -1;
780 app
->playlist
.item
[i
].omn_offset
= -1;
781 app
->playlist
.item
[i
].error
|= PLAYLIST_ITEM_ERROR_CUE
;
785 app
->playlist
.item
[i
].omn_idx
= c
;
786 app
->playlist
.item
[i
].omn_offset
= o
;
787 app
->playlist
.item
[i
].error
&= 0xF ^ PLAYLIST_ITEM_ERROR_CUE
;
789 /* save selected item offset */
793 o
+= app
->playlist
.item
[i
].dur
;
801 /* Set timeline min/max */
802 OmPlrSetMinPosMin((OmPlrHandle
)player
->handle
);
803 OmPlrSetMaxPosMax((OmPlrHandle
)player
->handle
);
805 /* Set timeline position */
807 hs
.size
= sizeof(OmPlrStatus
);
808 OmPlrGetPlayerStatus((OmPlrHandle
)player
->handle
, &hs
);
809 OmPlrSetPos((OmPlrHandle
)player
->handle
, hs
.minPos
+ p
);
812 if(app
->playlist
.item
[start
].type
& OMNPLAY_PLAYLIST_BLOCK_LOOP
)
813 OmPlrLoop((OmPlrHandle
)player
->handle
, hs
.minPos
, hs
.maxPos
);
815 OmPlrLoop((OmPlrHandle
)player
->handle
, hs
.minPos
, hs
.minPos
);
817 player
->playlist_start
= start
;
818 player
->playlist_length
= stop
- start
+ 1;
821 OmPlrCuePlay((OmPlrHandle
)player
->handle
, 0.0);
825 if(BUTTON_PLAYER_PLAY
== button
)
828 OmPlrPlay((OmPlrHandle
)player
->handle
, 1.0);
831 if(BUTTON_PLAYER_PAUSE
== button
)
833 OmPlrPlay((OmPlrHandle
)player
->handle
, 0.0);
835 pthread_mutex_unlock(&app
->players
.lock
);
837 pthread_mutex_unlock(&app
->playlist
.lock
);
840 static void omnplay_playlist_item_swap(omnplay_instance_t
* app
, int dir
)
842 int sel
, a
, b
, e
= 1;
844 playlist_item_t item
;
846 /* find insert position */
847 sel
= get_first_selected_item_playlist(app
);
864 /* check for playing block */
865 if(idx_in_players_range(app
, a
) || idx_in_players_range(app
, b
))
868 pthread_mutex_lock(&app
->playlist
.lock
);
869 pthread_mutex_lock(&app
->players
.lock
);
872 item
= app
->playlist
.item
[a
];
873 app
->playlist
.item
[a
] = app
->playlist
.item
[b
];
874 app
->playlist
.item
[b
] = item
;
877 if(app
->playlist
.item
[a
].type
!= app
->playlist
.item
[b
].type
)
880 app
->playlist
.item
[a
].type
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
881 app
->playlist
.item
[b
].type
= OMNPLAY_PLAYLIST_ITEM_BLOCK_SINGLE
;
884 /* redraw main items */
885 omnplay_playlist_draw_item(app
, a
);
886 omnplay_playlist_draw_item(app
, b
);
888 /* fix block types */
891 app
->playlist
.item
[a
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[a
- 1].type
|
892 OMNPLAY_PLAYLIST_BLOCK_END
);
893 omnplay_playlist_draw_item(app
, a
- 1);
895 if(b
+ 1 < app
->playlist
.count
&& !e
)
897 app
->playlist
.item
[b
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[b
+ 1].type
|
898 OMNPLAY_PLAYLIST_BLOCK_BEGIN
);
899 omnplay_playlist_draw_item(app
, b
+ 1);
903 path
= gtk_tree_path_new_from_indices(sel
, -1);
904 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
905 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
906 gtk_tree_path_free(path
);
908 pthread_mutex_unlock(&app
->players
.lock
);
909 pthread_mutex_unlock(&app
->playlist
.lock
);
912 static void omnplay_library_add(omnplay_instance_t
* app
, int after
)
915 playlist_item_t
* items
;
916 playlist_item_type_t t
;
918 /* find insert position */
919 idx
= get_first_selected_item_playlist(app
);
925 if(!omnplay_playlist_insert_check(app
, idx
, &t
))
928 items
= omnplay_library_get_selected(app
, &c
);
933 for(i
= 0; i
< c
; i
++)
938 omnplay_playlist_insert_items(app
, idx
, items
, c
);
943 static gboolean
omnplay_button_click(omnplay_instance_t
* app
, control_buttons_t button
)
947 case BUTTON_PLAYLIST_ITEM_ADD
:
948 omnplay_playlist_item_add(app
, 0);
950 case BUTTON_PLAYLIST_ITEM_DEL
:
951 omnplay_playlist_item_del(app
);
953 case BUTTON_PLAYLIST_ITEM_EDIT
:
954 omnplay_playlist_item_edit(app
);
956 case BUTTON_PLAYLIST_LOAD
:
957 omnplay_playlist_load(app
);
959 case BUTTON_PLAYLIST_SAVE
:
960 omnplay_playlist_save(app
);
962 case BUTTON_PLAYLIST_BLOCK_SINGLE
:
963 case BUTTON_PLAYLIST_BLOCK_LOOP
:
964 omnplay_playlist_block(app
, button
);
966 case BUTTON_PLAYLIST_ITEM_UP
:
967 omnplay_playlist_item_swap(app
, -1);
969 case BUTTON_PLAYLIST_ITEM_DOWN
:
970 omnplay_playlist_item_swap(app
, +1);
972 case BUTTON_PLAYER_CUE
:
973 case BUTTON_PLAYER_PLAY
:
974 case BUTTON_PLAYER_PAUSE
:
975 case BUTTON_PLAYER_STOP
:
976 omnplay_ctl(app
, button
);
978 case BUTTON_LIBRARY_ADD
:
979 omnplay_library_add(app
, 0);
981 case BUTTON_LIBRARY_REFRESH
:
982 omnplay_library_refresh(app
);
984 case BUTTON_LIBRARY_FIND
:
985 omnplay_library_search(app
, 0);
987 case BUTTON_LIBRARY_FIND_NEXT
:
988 omnplay_library_search(app
, 1);
995 static gboolean
on_button_click(GtkWidget
*button
, gpointer user_data
)
998 omnplay_instance_t
* app
= (omnplay_instance_t
*)user_data
;
1000 for(i
= 1; i
< BUTTON_LAST
; i
++)
1001 if(app
->buttons
[i
] == button
)
1002 return omnplay_button_click(app
, (control_buttons_t
)i
);
1007 static void omnplay_playlist_item_copy(omnplay_instance_t
* app
)
1011 list
= get_selected_items_playlist(app
);
1014 for(i
= 0; i
< list
[0]; i
++)
1015 app
->clipboard
.item
[i
] = app
->playlist
.item
[list
[i
+ 1]];
1016 app
->clipboard
.count
= list
[0];
1021 static void omnplay_playlist_item_paste(omnplay_instance_t
* app
, int after
)
1024 playlist_item_t
* items
;
1025 playlist_item_type_t t
;
1027 /* find insert position */
1028 idx
= get_first_selected_item_playlist(app
);
1034 if(!omnplay_playlist_insert_check(app
, idx
, &t
))
1038 if(app
->clipboard
.count
)
1040 for(i
= 0; i
< app
->clipboard
.count
; i
++)
1042 app
->clipboard
.item
[i
].type
= t
;
1043 app
->clipboard
.item
[i
].error
= 0;
1045 omnplay_playlist_insert_items(app
, idx
, app
->clipboard
.item
, app
->clipboard
.count
);
1049 static gboolean
on_playlist_grid_key(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
1051 omnplay_instance_t
* app
= (omnplay_instance_t
*)data
;
1053 switch(event
->keyval
)
1057 if(event
->state
& GDK_CONTROL_MASK
)
1059 omnplay_playlist_item_copy(app
);
1065 if(event
->state
& GDK_CONTROL_MASK
)
1067 omnplay_playlist_item_paste(app
, 0);
1073 if(event
->state
& GDK_CONTROL_MASK
)
1075 omnplay_playlist_item_copy(app
);
1076 omnplay_playlist_item_del(app
);
1082 if(event
->state
& GDK_CONTROL_MASK
)
1084 omnplay_playlist_save(app
);
1090 if(event
->state
& GDK_CONTROL_MASK
)
1092 omnplay_playlist_load(app
);
1097 omnplay_ctl(app
, BUTTON_PLAYER_PLAY
);
1099 case GDK_KEY_Return
:
1100 omnplay_ctl(app
, BUTTON_PLAYER_CUE
);
1102 case GDK_KEY_Insert
:
1103 omnplay_playlist_item_add(app
, 0);
1105 case GDK_KEY_Delete
:
1106 omnplay_playlist_item_del(app
);
1108 case GDK_KEY_BackSpace
:
1109 omnplay_playlist_item_edit(app
);
1116 static gboolean
on_library_grid_key(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
1118 omnplay_instance_t
* app
= (omnplay_instance_t
*)data
;
1120 switch(event
->keyval
)
1124 if(event
->state
& GDK_CONTROL_MASK
)
1127 playlist_item_t
* items
;
1129 items
= omnplay_library_get_selected(app
, &count
);
1135 for(i
= 0; i
< count
; i
++)
1136 app
->clipboard
.item
[i
] = items
[i
];
1138 app
->clipboard
.count
= count
;
1146 if(event
->state
& GDK_CONTROL_MASK
)
1148 g_warning("CTRL+v\n");
1154 if(event
->state
& GDK_CONTROL_MASK
)
1156 g_warning("CTRL+x\n");
1165 static gboolean
on_library_grid_button(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
1167 // g_warning("on_library_grid_button: event->button=%d, event->type=%d", event->button, event->type);
1169 if(event
->button
==1 && event
->type
==GDK_2BUTTON_PRESS
)
1171 omnplay_library_add((omnplay_instance_t
* )data
, 0);
1178 static gboolean
on_playlist_grid_button(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
1180 // g_warning("on_playlist_grid_button");
1182 if(event
->button
==1 && event
->type
==GDK_2BUTTON_PRESS
)
1184 omnplay_ctl((omnplay_instance_t
* )data
, BUTTON_PLAYER_CUE
);
1191 void omnplay_init(omnplay_instance_t
* app
)
1194 pthread_mutexattr_t attr
;
1196 pthread_mutexattr_init(&attr
);
1197 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
1199 gtk_signal_connect( GTK_OBJECT( app
->window
), "delete-event",
1200 GTK_SIGNAL_FUNC(on_main_window_delete_event
), app
);
1202 gtk_signal_connect( GTK_OBJECT( app
->window
), "destroy",
1203 GTK_SIGNAL_FUNC(on_main_window_destroy
), app
);
1205 gtk_widget_add_events(app
->playlist_grid
, GDK_BUTTON_PRESS_MASK
);
1206 gtk_widget_add_events(app
->playlist_grid
, GDK_KEY_PRESS_MASK
);
1207 gtk_signal_connect(GTK_OBJECT(app
->playlist_grid
), "key-press-event",
1208 GTK_SIGNAL_FUNC(on_playlist_grid_key
), app
);
1210 gtk_widget_add_events(app
->library_grid
, GDK_BUTTON_PRESS_MASK
);
1211 gtk_widget_add_events(app
->library_grid
, GDK_KEY_PRESS_MASK
);
1212 gtk_signal_connect(GTK_OBJECT(app
->library_grid
), "key-press-event",
1213 GTK_SIGNAL_FUNC(on_library_grid_key
), app
);
1215 gtk_signal_connect(GTK_OBJECT(app
->playlist_grid
), "button-press-event",
1216 GTK_SIGNAL_FUNC(on_playlist_grid_button
), app
);
1218 gtk_signal_connect(GTK_OBJECT(app
->library_grid
), "button-press-event",
1219 GTK_SIGNAL_FUNC(on_library_grid_button
), app
);
1222 pthread_mutex_init(&app
->players
.lock
, &attr
);
1224 /* create a omneon status thread */
1225 for(i
= 0; i
< app
->players
.count
; i
++)
1226 pthread_create(&app
->players
.item
[i
].thread
, NULL
,
1227 omnplay_thread_proc
, &app
->players
.item
[i
]);
1231 pthread_mutex_init(&app
->playlist
.lock
, &attr
);
1233 /* attach buttons click */
1234 for(i
= 1; i
< BUTTON_LAST
; i
++)
1235 gtk_signal_connect(GTK_OBJECT(app
->buttons
[i
]), "clicked",
1236 GTK_SIGNAL_FUNC( on_button_click
), app
);
1239 pthread_mutex_init(&app
->library
.lock
, &attr
);
1242 omnplay_library_load(app
);
1244 pthread_mutexattr_destroy(&attr
);
1247 void omnplay_release(omnplay_instance_t
* app
)
1254 for(i
= 0; i
< app
->players
.count
; i
++)
1255 /* create a omneon status thread */
1256 pthread_join(app
->players
.item
[i
].thread
, &r
);
1259 pthread_mutex_destroy(&app
->players
.lock
);
1262 pthread_mutex_destroy(&app
->playlist
.lock
);
1265 omnplay_library_save(app
);
1267 /* destroy library lock */
1268 pthread_mutex_destroy(&app
->library
.lock
);
1271 void omnplay_playlist_normalize(omnplay_instance_t
* app
)
1275 /* normalize playlist */
1276 for(i
= 0; i
< app
->playlist
.count
; i
++)
1277 if(omnplay_library_normalize_item(app
, &app
->playlist
.item
[i
]))
1278 omnplay_playlist_draw_item(app
, i
);