[prev in list] [next in list] [prev in thread] [next in thread]
List: xine-cvslog
Subject: [xine-cvs] CVS: xine-ui/src/xitk/oxine Makefile.am,NONE,1.1 event.h,NONE,1.1 list.c,NONE,1.1 list.h,
From: Miguel Freitas <miguelfreitas () users ! sourceforge ! net>
Date: 2005-01-31 2:49:51
Message-ID: E1CvRdP-000145-BF () sc8-pr-cvs1 ! sourceforge ! net
[Download RAW message or body]
Update of /cvsroot/xine/xine-ui/src/xitk/oxine
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2443/src/xitk/oxine
Added Files:
Makefile.am event.h list.c list.h mediamarks.c mediamarks.h
odk.c odk.h otk.c otk.h oxine.c oxine.h utils.c utils.h
Log Message:
xine-ui meets oxine ;-)
that is, my living room is now powered by xine!
minor xine-ui hooks are needed to get osd menus working, forwarding
navigation and mouse events as needed.
oxine code was greatly simplified since lots of features are already
provided by xine-ui itself with osd feedback (eg. navigation keys,
volume adjust, brightness/contrast...)
not all oxine menu code has been ported, this is still work in progress but
it is already usable (specially by providing a ~/.xine/oxine_mediamarks
file).
--- NEW FILE: Makefile.am ---
AM_CFLAGS = -I../
if HAVE_X11
oxine_lib = liboxine.la
endif
noinst_LTLIBRARIES = $(oxine_lib)
liboxine_la_SOURCES = \
list.c \
mediamarks.c \
odk.c \
otk.c \
oxine.c \
utils.c
noinst_HEADERS = \
list.h \
mediamarks.h \
odk.h \
otk.h \
oxine.h \
utils.h
debug:
@$(MAKE) CFLAGS="$(DEBUG_CFLAGS) -I../"
install-debug: debug
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
mostlyclean-generic:
-rm -f *~ \#* .*~ .\#*
maintainer-clean-generic:
-@echo "This command is intended for maintainers to use;"
-@echo "it deletes files that may require special tools to rebuild."
-rm -f Makefile.in
--- NEW FILE: event.h ---
/*
* Copyright (C) 2002 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: event.h,v 1.1 2005/01/31 02:49:47 miguelfreitas Exp $
*
* datatypes and defines for events
*/
#ifndef HAVE_EVENT_H
#define HAVE_EVENT_H
/*
* oxine global events and keycodes
*/
#define OXINE_EVENT_KEY 1
#define OXINE_EVENT_BUTTON 2
#define OXINE_EVENT_MOTION 3
#define OXINE_EVENT_FINISH 4
#define OXINE_EVENT_FORMAT_CHANGED 5
#define OXINE_EVENT_START 6
#define OXINE_KEY_NULL 0
#define OXINE_KEY_UP 1
#define OXINE_KEY_DOWN 2
#define OXINE_KEY_LEFT 3
#define OXINE_KEY_RIGHT 4
#define OXINE_KEY_PRIOR 5
#define OXINE_KEY_NEXT 6
#define OXINE_KEY_SELECT 7
#define OXINE_KEY_PLAY 8
#define OXINE_KEY_PAUSE 9
#define OXINE_KEY_STOP 10
#define OXINE_KEY_FORWARD 11
#define OXINE_KEY_REWIND 12
#define OXINE_KEY_0 13
#define OXINE_KEY_1 14
#define OXINE_KEY_2 15
#define OXINE_KEY_3 16
#define OXINE_KEY_4 17
#define OXINE_KEY_5 18
#define OXINE_KEY_6 19
#define OXINE_KEY_7 20
#define OXINE_KEY_8 21
#define OXINE_KEY_9 22
#define OXINE_KEY_MENU1 23
#define OXINE_KEY_MENU2 24
#define OXINE_KEY_MENU3 25
#define OXINE_KEY_MENU4 26
#define OXINE_KEY_MENU5 27
#define OXINE_KEY_MENU6 28
#define OXINE_KEY_MENU7 29
#define OXINE_KEY_ESCAPE 30
#define OXINE_KEY_FULLSCREEN 31
#define OXINE_KEY_VOLUP 32
#define OXINE_KEY_VOLDOWN 33
#define OXINE_KEY_VOLMUTE 34
#define OXINE_KEY_SEEK 35
#define OXINE_KEY_OSD 36
#define OXINE_KEY_EJECT 37
#define OXINE_KEY_PPLAY 38
#define OXINE_KEY_PL_NEXT 39
#define OXINE_KEY_PL_PREV 40
#define OXINE_KEY_SATURATION 41
#define OXINE_KEY_BRIGHTNESS 42
#define OXINE_KEY_CONTRAST 43
#define OXINE_KEY_HUE 44
#define OXINE_KEY_SPU_OFFSET 45
#define OXINE_KEY_SPU_CHANNEL 46
#define OXINE_KEY_AUDIO_CHANNEL_LOGICAL 47
#define OXINE_KEY_AV_OFFSET 48
#define OXINE_KEY_SPEED 49
#define OXINE_KEY_TOGGLE_ASPECT_RATIO 50
#define OXINE_KEY_VO_DEINTERLACE 51
#define OXINE_KEY_STREAM_POSITION 52
#define OXINE_BUTTON1 1
#define OXINE_BUTTON2 2
#define OXINE_BUTTON3 3
#define OXINE_BUTTON4 4
#define OXINE_BUTTON5 5
typedef struct {
int type;
int key, x, y;
int repeat;
char *data;
} oxine_event_t;
#endif
--- NEW FILE: list.c ---
/*
* Copyright (C) 2003 the oxine project
*
* xine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id: list.c,v 1.1 2005/01/31 02:49:47 miguelfreitas Exp $
*
* doubly linked lists with builtin iterator,
* based upon xine_list functions of the xine project
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
#ifdef DEBUG
#include <string.h>
#endif
#include "list.h"
#include "utils.h"
/*
* private data structures
*/
typedef struct node_s {
struct node_s *next, *prev;
void *content;
int priority;
} node_t;
struct list_s {
node_t *first, *last, *cur;
#ifdef DEBUG
char tag[256];
#endif
};
/*
* create a new, empty list
*/
#ifdef DEBUG
list_t *_list_new_tagged(char *file, int line) {
char tag[256];
list_t *list;
snprintf(tag, 255, "list @ %s:%i", file, line);
list = ho_new_tagged(list_t, tag);
strncpy(list->tag, tag, 255);
list->first=NULL;
list->last =NULL;
list->cur =NULL;
return list;
}
#else
list_t *list_new (void) {
list_t *list;
list = ho_new(list_t);
list->first=NULL;
list->last =NULL;
list->cur =NULL;
return list;
}
#endif
/*
* dispose a list (and only the list, contents have to be managed separately)
*/
void list_free(list_t *l) {
node_t *node;
if (!l) {
printf ("list: tried to free empty list\n");
abort();
}
if (!l->first) {
ho_free(l);
return;
}
node = l->first;
while(node) {
node_t *n = node;
node = n->next;
ho_free(n);
}
ho_free(l);
}
void *list_first_content (list_t *l) {
l->cur = l->first;
if (l->first)
return l->first->content;
else
return NULL;
}
void *list_next_content (list_t *l) {
if (l->cur) {
if (l->cur->next) {
l->cur = l->cur->next;
return l->cur->content;
}
else
return NULL;
} else {
printf ("list: next_content - passed end of list\n");
abort ();
}
}
void *list_current_content (list_t *l) {
if (l->cur) {
return l->cur->content;
} else {
printf ("list: next_content - passed end of list\n");
abort ();
}
}
int list_is_empty (list_t *l) {
if (l == NULL){
printf ("list: list_is_empty : list is NULL\n");
abort();
}
return (l->first != NULL);
}
void *list_last_content (list_t *l) {
if (l->last) {
l->cur = l->last;
return l->last->content;
} else
return NULL;
}
void *list_prev_content (list_t *l) {
if (l->cur) {
if (l->cur->prev) {
l->cur = l->cur->prev;
return l->cur->content;
}
else
return NULL;
} else {
printf ("list: passed begin of list\n");
abort ();
}
}
void list_append_priority_content (list_t *l, void *content, int priority) {
node_t *node;
#ifdef DEBUG
char tag[256];
snprintf(tag, 255, "pri node in %s", l->tag);
node = ho_new_tagged(node_t, tag);
#else
node = ho_new(node_t);
#endif
node->content = content;
node->priority = priority;
if (l->first) {
node_t *cur;
cur = l->first;
while(1) {
if( priority >= cur->priority ) {
node->next = cur;
node->prev = cur->prev;
if( node->prev )
node->prev->next = node;
else
l->first = node;
cur->prev = node;
l->cur = node;
break;
}
if( !cur->next ) {
node->next = NULL;
node->prev = cur;
cur->next = node;
l->cur = node;
l->last = node;
break;
}
cur = cur->next;
}
}
else {
l->first = l->last = l->cur = node;
node->prev = node->next = NULL;
}
}
#ifdef DEBUG
void _list_append_content(list_t *l, void *content, char *file, int line) {
node_t *node;
char tag[256];
snprintf(tag, 255, "app node @ %s:%i", file, line);
node = ho_new_tagged(node_t, tag);
#else
void list_append_content (list_t *l, void *content) {
node_t *node;
node = ho_new(node_t);
#endif
node->content = content;
if (l->last) {
node->next = NULL;
node->prev = l->last;
l->last->next = node;
l->last = node;
l->cur = node;
}
else {
l->first = l->last = l->cur = node;
node->prev = node->next = NULL;
}
}
void list_insert_content (list_t *l, void *content) {
node_t *nodecur, *nodenew, *nodeprev;
#ifdef DEBUG
char tag[256];
snprintf(tag, 255, "ins node in %s", l->tag);
nodenew = ho_new_tagged(node_t, tag);
#else
nodenew = ho_new(node_t);
#endif
nodenew->content = content;
nodecur = l->cur;
if(!nodecur) {
list_append_content(l, content);
return;
}
nodeprev = nodecur->prev;
nodecur->prev = nodenew;
nodenew->next = nodecur;
nodenew->prev = nodeprev;
if(nodecur != l->first) {
nodeprev->next = nodenew;
} else {
l->first = nodenew;
}
l->cur = nodenew;
}
void list_delete_current (list_t *l) {
node_t *node_cur;
node_cur = l->cur;
if(node_cur->prev) {
node_cur->prev->next = node_cur->next;
}
else { /* First entry */
l->first = node_cur->next;
}
if(node_cur->next) {
node_cur->next->prev = node_cur->prev;
l->cur = node_cur->next;
}
else { /* last entry in the list */
l->last = node_cur->prev;
l->cur = node_cur->prev;
}
ho_free(node_cur);
}
/*
* glib's implementation of lists
*/
#define _g_list_new g_list_new
g_list_t* g_list_new (void) {
g_list_t *list;
list = ho_new(g_list_t);
return list;
}
void g_list_free (g_list_t *list) {
g_list_t *last;
while (list)
{
last = list;
list = list->next;
ho_free (last);
}
}
#define _g_list_free_1 g_list_free_1
void g_list_free_1 (g_list_t *list) {
ho_free (list);
}
g_list_t* g_list_append (g_list_t *list, void* data) {
g_list_t *new_list;
g_list_t *last;
new_list = _g_list_new ();
new_list->data = data;
if (list)
{
last = g_list_last (list);
last->next = new_list;
new_list->prev = last;
return list;
}
else
return new_list;
}
g_list_t* g_list_prepend (g_list_t *list, void* data) {
g_list_t *new_list;
new_list = _g_list_new ();
new_list->data = data;
if (list)
{
if (list->prev)
{
list->prev->next = new_list;
new_list->prev = list->prev;
}
list->prev = new_list;
new_list->next = list;
}
return new_list;
}
g_list_t* g_list_insert (g_list_t *list, void* data, int position) {
g_list_t *new_list;
g_list_t *tmp_list;
if (position < 0)
return g_list_append (list, data);
else if (position == 0)
return g_list_prepend (list, data);
tmp_list = g_list_nth (list, position);
if (!tmp_list)
return g_list_append (list, data);
new_list = _g_list_new ();
new_list->data = data;
if (tmp_list->prev)
{
tmp_list->prev->next = new_list;
new_list->prev = tmp_list->prev;
}
new_list->next = tmp_list;
tmp_list->prev = new_list;
if (tmp_list == list)
return new_list;
else
return list;
}
g_list_t* g_list_insert_before (g_list_t *list, g_list_t *sibling, void* data) {
if (!list)
{
list = g_list_new ();
list->data = data;
return list;
}
else if (sibling)
{
g_list_t *node;
node = g_list_new ();
node->data = data;
if (sibling->prev)
{
node->prev = sibling->prev;
node->prev->next = node;
node->next = sibling;
sibling->prev = node;
return list;
}
else
{
node->next = sibling;
sibling->prev = node;
return node;
}
}
else
{
g_list_t *last;
last = list;
while (last->next)
last = last->next;
last->next = g_list_new ();
last->next->data = data;
last->next->prev = last;
return list;
}
}
g_list_t * g_list_concat (g_list_t *list1, g_list_t *list2) {
g_list_t *tmp_list;
if (list2)
{
tmp_list = g_list_last (list1);
if (tmp_list)
tmp_list->next = list2;
else
list1 = list2;
list2->prev = tmp_list;
}
return list1;
}
g_list_t* g_list_remove (g_list_t *list, const void *data) {
g_list_t *tmp;
tmp = list;
while (tmp)
{
if (tmp->data != data)
tmp = tmp->next;
else
{
if (tmp->prev)
tmp->prev->next = tmp->next;
if (tmp->next)
tmp->next->prev = tmp->prev;
if (list == tmp)
list = list->next;
_g_list_free_1 (tmp);
break;
}
}
return list;
}
g_list_t* g_list_remove_all (g_list_t *list, const void *data) {
g_list_t *tmp = list;
while (tmp)
{
if (tmp->data != data)
tmp = tmp->next;
else
{
g_list_t *next = tmp->next;
if (tmp->prev)
tmp->prev->next = next;
else
list = next;
if (next)
next->prev = tmp->prev;
_g_list_free_1 (tmp);
tmp = next;
}
}
return list;
}
static inline g_list_t* _g_list_remove_link (g_list_t *list, g_list_t *link) {
if (link)
{
if (link->prev)
link->prev->next = link->next;
if (link->next)
link->next->prev = link->prev;
if (link == list)
list = list->next;
link->next = NULL;
link->prev = NULL;
}
return list;
}
g_list_t* g_list_remove_link (g_list_t *list, g_list_t *link) {
return _g_list_remove_link (list, link);
}
g_list_t* g_list_delete_link (g_list_t *list, g_list_t *link) {
list = _g_list_remove_link (list, link);
_g_list_free_1 (link);
return list;
}
g_list_t* g_list_copy (g_list_t *list) {
g_list_t *new_list = NULL;
if (list)
{
g_list_t *last;
new_list = _g_list_new ();
new_list->data = list->data;
last = new_list;
list = list->next;
while (list)
{
last->next = _g_list_new ();
last->next->prev = last;
last = last->next;
last->data = list->data;
list = list->next;
}
}
return new_list;
}
g_list_t* g_list_reverse (g_list_t *list) {
g_list_t *last;
last = NULL;
while (list)
{
last = list;
list = last->next;
last->next = last->prev;
last->prev = list;
}
return last;
}
g_list_t* g_list_nth (g_list_t *list, unsigned int n) {
while ((n-- > 0) && list)
list = list->next;
return list;
}
g_list_t* g_list_nth_prev (g_list_t *list, unsigned int n) {
while ((n-- > 0) && list)
list = list->prev;
return list;
}
void* g_list_nth_data (g_list_t *list, unsigned int n) {
while ((n-- > 0) && list)
list = list->next;
return list ? list->data : NULL;
}
g_list_t* g_list_find (g_list_t *list, const void *data) {
while (list)
{
if (list->data == data)
break;
list = list->next;
}
return list;
}
g_list_t* g_list_find_custom (g_list_t *list, const void *data, list_compare func) {
while (list)
{
if (! func (list->data, data))
return list;
list = list->next;
}
return NULL;
}
int g_list_position (g_list_t *list, g_list_t *link) {
int i;
i = 0;
while (list)
{
if (list == link)
return i;
i++;
list = list->next;
}
return -1;
}
int g_list_index (g_list_t *list, const void *data) {
int i;
i = 0;
while (list)
{
if (list->data == data)
return i;
i++;
list = list->next;
}
return -1;
}
g_list_t* g_list_last (g_list_t *list) {
if (list)
{
while (list->next)
list = list->next;
}
return list;
}
g_list_t* g_list_first (g_list_t *list) {
if (list)
{
while (list->prev)
list = list->prev;
}
return list;
}
unsigned int g_list_length (g_list_t *list) {
unsigned int length;
length = 0;
while (list)
{
length++;
list = list->next;
}
return length;
}
void g_list_foreach (g_list_t *list, list_func func, void *user_data) {
while (list)
{
g_list_t *next = list->next;
(*func) (list->data, user_data);
list = next;
}
}
g_list_t* g_list_insert_sorted (g_list_t *list, void *data, list_compare func) {
g_list_t *tmp_list = list;
g_list_t *new_list;
int cmp;
if (!func) return list;
if (!list)
{
new_list = _g_list_new ();
new_list->data = data;
return new_list;
}
cmp = (*func) (data, tmp_list->data);
while ((tmp_list->next) && (cmp > 0))
{
tmp_list = tmp_list->next;
cmp = (*func) (data, tmp_list->data);
}
new_list = _g_list_new ();
new_list->data = data;
if ((!tmp_list->next) && (cmp > 0))
{
tmp_list->next = new_list;
new_list->prev = tmp_list;
return list;
}
if (tmp_list->prev)
{
tmp_list->prev->next = new_list;
new_list->prev = tmp_list->prev;
}
new_list->next = tmp_list;
tmp_list->prev = new_list;
if (tmp_list == list)
return new_list;
else
return list;
}
static g_list_t *g_list_sort_merge (g_list_t *l1, g_list_t *l2, list_func \
compare_func, int use_data, void *user_data) {
g_list_t list, *l, *lprev;
int cmp;
l = &list;
lprev = NULL;
while (l1 && l2)
{
if (use_data)
cmp = ((list_compare_data) compare_func) (l1->data, l2->data, user_data);
else
cmp = ((list_compare) compare_func) (l1->data, l2->data);
if (cmp <= 0)
{
l->next = l1;
l = l->next;
l->prev = lprev;
lprev = l;
l1 = l1->next;
}
else
{
l->next = l2;
l = l->next;
l->prev = lprev;
lprev = l;
l2 = l2->next;
}
}
l->next = l1 ? l1 : l2;
l->next->prev = l;
return list.next;
}
static g_list_t* g_list_sort_real (g_list_t *list, list_func compare_func,
int use_data, void *user_data) {
g_list_t *l1, *l2;
if (!list)
return NULL;
if (!list->next)
return list;
l1 = list;
l2 = list->next;
while ((l2 = l2->next) != NULL)
{
if ((l2 = l2->next) == NULL)
break;
l1 = l1->next;
}
l2 = l1->next;
l1->next = NULL;
return g_list_sort_merge (g_list_sort_real (list, compare_func, use_data, \
user_data), g_list_sort_real (l2, compare_func, use_data, user_data),
compare_func,
use_data,
user_data);
}
g_list_t *g_list_sort (g_list_t *list, list_compare compare_func) {
return g_list_sort_real (list, (list_func) compare_func, 0, NULL);
}
g_list_t * g_list_sort_with_data (g_list_t *list, list_compare compare_func, void \
*user_data) { return g_list_sort_real (list, (list_func) compare_func, 1, \
user_data); }
#if 0
static g_list_t* g_list_sort2 (g_list_t *list, list_compare compare_func) {
g_list_t *runs = NULL;
g_list_t *tmp;
/* Degenerate case. */
if (!list) return NULL;
/* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */
for (tmp = list; tmp; )
{
g_list_t *tmp2;
for (tmp2 = tmp;
tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0;
tmp2 = tmp2->next)
/* Nothing */;
runs = g_list_append (runs, tmp);
tmp = tmp2->next;
tmp2->next = NULL;
}
/* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */
while (runs->next)
{
/* We have more than one run. Merge pairwise. */
g_list_t *dst, *src, *dstprev = NULL;
dst = src = runs;
while (src && src->next)
{
dst->data = g_list_sort_merge (src->data,
src->next->data,
(list_func) compare_func,
0, NULL);
dstprev = dst;
dst = dst->next;
src = src->next->next;
}
/* If number of runs was odd, just keep the last. */
if (src)
{
dst->data = src->data;
dstprev = dst;
dst = dst->next;
}
dstprev->next = NULL;
g_list_free (dst);
}
/* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */
/* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */
list = runs->data;
g_list_free (runs);
return list;
}
#endif
--- NEW FILE: list.h ---
/*
* Copyright (C) 2003 the oxine project
*
* xine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* xine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id: list.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* doubly linked lists with builtin iterator,
* based upon xine_list functions of the xine project
*/
#ifndef HAVE_LIST_H
#define HAVE_LIST_H
#include <inttypes.h>
typedef struct list_s list_t;
/*
* create a new, empty list
*/
#ifdef DEBUG
list_t *_list_new_tagged(char*, int) ;
#define list_new() (_list_new_tagged(__FILE__, __LINE__))
#define xine_list_new() (_list_new_tagged(__FILE__, __LINE__))
#else
list_t *list_new (void) ;
#define xine_list_new list_new
#endif
/*
* dispose a list (and only the list, contents have to be managed separately)
*/
void list_free (list_t *l) ;
/*
* set cursor to the first element in list, return contents of first entry
*/
void *list_first_content (list_t *l) ;
/*
* set cursor to the next element, returns its contents
*/
void *list_next_content (list_t *l) ;
/*
* returns contents of the current element
*/
void *list_current_content (list_t *l) ;
/*
* returns 1, if list is empty
*/
int list_is_empty (list_t *l) ;
/*
* set cursor to the last element, returns its contents
*/
void *list_last_content (list_t *l) ;
/*
* set cursor to the previous element, return its contents
*/
void *list_prev_content (list_t *l) ;
/*
* sort element into list by priority. list_first_content returns then
* the element with the highest priority.
*/
void list_append_priority_content (list_t *l, void *content, int priority) ;
/*
* append element at the end of the list
*/
#ifdef DEBUG
void _list_append_content (list_t *l, void *content, char*, int) ;
#define list_append_content(list,cont) (_list_append_content(list, cont, __FILE__, \
__LINE__)) #define xine_list_append_content(list,cont) (_list_append_content(list, \
cont, __FILE__, __LINE__)) #else
void list_append_content (list_t *l, void *content) ;
#define xine_list_append_content list_append_content
#endif
/*
* insert content just before cursor position
*/
void list_insert_content (list_t *l, void *content) ;
/*
* delete current element (its contents have to be freen seperately!)
*/
void list_delete_current (list_t *l) ;
/*
* compatibility macros
*/
#define xine_list_t list_t
#define xine_list_free list_free
#define xine_list_first_content list_first_content
#define xine_list_next_content list_next_content
#define xine_list_current_content list_current_content
#define xine_list_is_empty list_is_empty
#define xine_list_last_content list_last_content
#define xine_list_prev_content list_prev_content
#define xine_list_append_priority_content list_append_priority_content
#define xine_list_insert_content list_insert_content
#define xine_list_delete_current list_delete_current
/*
* yet another list implementation
* thanks to glib project.
*/
typedef struct _g_list_t g_list_t;
struct _g_list_t
{
void* data;
g_list_t *next;
g_list_t *prev;
};
typedef int(*list_compare)(const void*, const void*);
typedef int(*list_compare_data)(const void*, const void*, void*);
typedef int(*list_func)(void*,void*);
/* Doubly linked lists
*/
//void g_list_push_allocator (GAllocator *allocator);
//void g_list_pop_allocator (void);
g_list_t* g_list_new (void);
void g_list_free (g_list_t *list);
void g_list_free_1 (g_list_t *list);
g_list_t* g_list_append (g_list_t *list, void *data);
g_list_t* g_list_prepend (g_list_t *list, void *data);
g_list_t* g_list_insert (g_list_t *list, void *data, int position);
g_list_t* g_list_insert_sorted (g_list_t *list, void* data, list_compare func);
g_list_t* g_list_insert_before (g_list_t *list, g_list_t *sibling, void* data);
g_list_t* g_list_concat (g_list_t *list1, g_list_t *list2);
g_list_t* g_list_remove (g_list_t *list, const void *data);
g_list_t* g_list_remove_all (g_list_t *list, const void *data);
g_list_t* g_list_remove_link (g_list_t *list, g_list_t *llink);
g_list_t* g_list_delete_link (g_list_t *list, g_list_t *link_);
g_list_t* g_list_reverse (g_list_t *list);
g_list_t* g_list_copy (g_list_t *list);
g_list_t* g_list_nth (g_list_t *list, unsigned int n);
g_list_t* g_list_nth_prev (g_list_t *list, unsigned int n);
g_list_t* g_list_find (g_list_t *list, const void *data);
g_list_t* g_list_find_custom (g_list_t *list, const void *data, list_compare func);
int g_list_position (g_list_t *list, g_list_t *llink);
int g_list_index (g_list_t *list, const void * data);
g_list_t* g_list_last (g_list_t *list);
g_list_t* g_list_first (g_list_t *list);
unsigned int g_list_length (g_list_t *list);
void g_list_foreach (g_list_t *list, list_func func, void* user_data);
g_list_t* g_list_sort (g_list_t *list, list_compare compare_func);
g_list_t* g_list_sort_with_data (g_list_t *list, list_compare compare_func, void* \
user_data); void* g_list_nth_data (g_list_t *list, unsigned int n);
#define g_list_previous(list) ((list) ? (((g_list_t *)(list))->prev) : NULL)
#define g_list_next(list) ((list) ? (((g_list_t *)(list))->next) : NULL)
#endif
--- NEW FILE: mediamarks.c ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: mediamarks.c,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* parsing mediamarks
*/
#define _GNU_SOURCE /* this is needed for getline(..) and strndup(..) */
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <libgen.h>
#include "common.h"
#include "oxine.h"
#include "otk.h"
#include "xine/xmlparser.h"
#include "utils.h"
extern gGui_t *gGui;
#define TYPE_NONE (0)
#define TYPE_DIR (1)
#define TYPE_REG (2)
#define TYPE_RDIR (3)
#define TYPE_RREG (4)
#define TYPE_UP (5)
#define TYPE_MULTIPLE (6)
#define TYPE_M3U (7)
/* sort methods 0 is default*/
#define PLAYITEM_SORT_FILES (1)
#define PLAYITEM_SORT_DIRFILES (0)
#define MM_ACTION_PLAY (1)
#define MM_ACTION_ADD (2)
const char *mm_action_strings[] = { "Play", "Add to PL" };
typedef struct playitem_s playitem_t;
struct playitem_s {
int type;
char *title;
char *mrl;
list_t *sub;
};
typedef struct mm_session_s mm_session_t;
struct mm_session_s {
oxine_t *oxine;
otk_widget_t *list;
int listpos;
list_t *backpath;
int action;
char ilabel[64];
};
/* private functions */
static int file_is_m3u(const char *mrl);
/* body of mediamarks functions */
void bpush (list_t *list, list_t *item) {
list_first_content(list);
list_insert_content(list, item);
}
list_t *bpop (list_t *list) {
list_t *item;
item = list_first_content(list);
list_delete_current(list);
return item;
}
/*
* implements case insensitive lengthlexicographic order
*
* returns 1 if a <= b
* 0 otherwise.
*/
static int in_cill_order(playitem_t *ita, playitem_t *itb, int type) {
char *a = ita->title;
char *b = itb->title;
char *ap, *bp; /* pointers to a, b */
char ac, bc;
int rtypea=0, rtypeb=0;
ap = a; bp = b;
/* printf("%s %s\n", a, b);
stat(ita->mrl, &filestat1);
stat(itb->mrl, &filestat2);*/
if(type == PLAYITEM_SORT_DIRFILES) {
if((ita->type == TYPE_DIR)||(ita->type == TYPE_RDIR)) rtypea = 1;
if((itb->type == TYPE_DIR)||(itb->type == TYPE_RDIR)) rtypeb = 1;
if((rtypea)&&(!rtypeb)) return 1;
if((!rtypea)&&(rtypeb)) return 0;
/*if((S_ISDIR(filestat1.st_mode))&&(!S_ISDIR(filestat2.st_mode))) return 1;
if((!S_ISDIR(filestat1.st_mode))&&(S_ISDIR(filestat2.st_mode))) return 0;*/
}
while (1) {
ac = *ap; bc = *bp;
if ((ac >= 'A') && (ac <= 'Z')) ac |= 0x20;
if ((bc >= 'A') && (bc <= 'Z')) bc |= 0x20;
if (ac < bc) return 1;
if (ac > bc) return 0;
if (!ac) return 1;
ap++; bp++;
}
return 1;
}
static void playitem_sort_into(playitem_t *item, list_t *list, int type) {
playitem_t *i;
i = list_first_content(list);
while(i) {
if (in_cill_order(item, i, type)) {
list_insert_content(list, item);
return;
}
i = list_next_content(list);
}
list_append_content(list, item);
}
static void playitem_append(playitem_t *item, list_t *list) {
list_append_content(list, item);
}
static playitem_t *playitem_new(int type, char *title, char *mrl, list_t *sub) {
playitem_t *item = ho_new(playitem_t);
item->type = type;
item->sub = sub;
if (title) item->title = ho_strdup(title);
if (mrl) item->mrl = ho_strdup(mrl);
return item;
}
static void free_subtree(list_t *list, int i) {
playitem_t *item;
if (!list) return;
item = list_first_content(list);
while (item) {
if (item->title) ho_free(item->title);
if (item->mrl) ho_free(item->mrl);
if(item->type != TYPE_UP) free_subtree(item->sub, 1);
list_delete_current(list);
ho_free(item);
item = list_first_content(list);
}
if(i) list_free(list);
}
/*static void playitem_free(playitem_t *item) {
playitem_t *child;
if(item->title) ho_free(item->title);
if(item->mrl) ho_free(item->mrl);
if(item->sub) {
child = list_first_content(item->sub);
while(child) {
playitem_free(child);
list_delete_current(item->sub);
child = list_first_content(item->sub);
}
list_free(item->sub);
}
ho_free(item);
}*/
static playitem_t *playitem_load (xml_node_t *node) {
playitem_t *play_item;
char *type;
struct stat filestat;
play_item = ho_new(playitem_t);
while (node) {
if (!strcasecmp (node->name, "title")) {
play_item->title = ho_strdup (node->data);
#ifdef LOG
printf ("mediamarks: title = %s\n", play_item->title);
#endif
} else if (!strcasecmp (node->name, "ref")) {
play_item->mrl = ho_strdup(xml_parser_get_property (node, "href"));
type = xml_parser_get_property(node, "type");
if(type) {
if(!strcasecmp(type, "multiple")) {
play_item->type = TYPE_MULTIPLE;
play_item->sub = list_new();
}
} else {
filestat.st_mode = 0;
stat(play_item->mrl, &filestat);
if(S_ISDIR(filestat.st_mode)) {
play_item->sub = list_new();
play_item->type = TYPE_RDIR;
} else {
play_item->type = TYPE_REG;
if(file_is_m3u(play_item->mrl)) play_item->type = TYPE_M3U;
}
}
#ifdef LOG
printf ("mediamarks: mrl = %s\n", play_item->mrl);
#endif
} else if (!strcasecmp (node->name, "time")) {
} else
printf ("mediamarks: error while loading mediamarks file, unknown node '%s'\n", \
node->name);
node = node->next;
}
return play_item;
}
static int parse_multiple(oxine_t *oxine, const char *mrl, list_t *list) {
int i=0, num=0;
playitem_t *item;
char **str;
str = xine_get_autoplay_mrls (oxine->xine, mrl, &num);
if (num<=0) return 0;
free_subtree(list, 0);
while(i < num) {
/* printf("%d %s\n", i, str[i]); */
item = playitem_new(TYPE_REG, str[i], str[i], list_new());
playitem_append(item, list);
i++;
}
return 1;
}
static void read_directory(oxine_t *oxine, const char *dir, list_t *list) {
DIR *dirp;
struct dirent *entp;
playitem_t *item;
free_subtree(list, 0);
#if 0
printf("Processing %s\n", dir);
#endif
dirp = opendir (dir);
if (dirp != NULL)
{
while ((entp = readdir(dirp))) {
struct stat filestat;
char mrl[1024];
char title[256];
int type = 0;
if((!strcmp(entp->d_name, "."))||(!strcmp(entp->d_name, ".."))) continue;
snprintf(mrl, 1023, "%s/%s", dir, entp->d_name);
stat(mrl, &filestat);
if(S_ISDIR(filestat.st_mode)) {
type = TYPE_RDIR;
snprintf(title, 255, "[%s]", entp->d_name);
}else if (S_ISREG(filestat.st_mode)) {
strncpy(title, entp->d_name, 255);
type = TYPE_RREG;
}
if(file_is_m3u(mrl)) {
type = TYPE_M3U;
snprintf(title, 255, "[%s]", entp->d_name);
}
item = playitem_new(type, title, mrl, list_new());
#if 0
printf("mrl : %s\n", item->mrl);
printf("title : %s\n", item->title);
printf("type : %d\n", item->type);
#endif
/* printf("ei %d\n", oxine->mm_sort_type); */
/* xine_config_lookup_entry (oxine->xine, "oxine.sort_type", &entry); */
playitem_sort_into(item, list, oxine->mm_sort_type);
}
closedir (dirp);
}
else
printf ("mediamarks: Couldn't open the directory.\n");
}
static char *read_entire_file (const char *mrl, int *file_size) {
char *buf;
struct stat statb;
int fd;
if (stat (mrl, &statb) < 0) {
printf ("mediamarks: cannot stat '%s'\n", mrl);
return NULL;
}
*file_size = statb.st_size;
fd = open (mrl, O_RDONLY);
if (fd<0)
return NULL;
/* buf = malloc (sizeof(char)*((*file_size)+1)); */
buf = ho_newstring((*file_size)+1);
if (!buf)
return NULL;
buf[*file_size]=0;
*file_size = read (fd, buf, *file_size);
close (fd);
return buf;
}
static int file_is_m3u(const char *mrl) {
#ifdef M3U_AS_SUBDIR
FILE *file;
char **line;
int *n;
int a;
file = fopen(mrl, "r");
if(!file) return 0;
n = ho_new(size_t);
line = ho_new(char *);
*line = NULL;
*n = 0;
a = getline(line, n, file);
if(a<=0) {
ho_free(n);
ho_free(line);
return 0;
}
if(!strncmp(*line, "#EXTM3U", 7)) {
ho_free(n);
ho_free(line);
return 1;
}
ho_free(n);
ho_free(line);
if( strstr(mrl,".m3u") != NULL || strstr(mrl,".M3U") )
return 1;
else
return 0;
#else
return 0; /* m3u is a normal file here, let xine-ui handle it as playlist */
#endif
}
static void parse_m3u(const char *mrl, list_t *items) {
FILE *file;
char **line;
int *n;
int a;
file = fopen(mrl, "r");
if(!file) return ;
n = ho_new(size_t);
line = ho_new(char *);
*line = NULL;
*n = 0;
a = getline(line, n, file);
if(a<=0) return;
while((a = getline(line, n, file))>0) {
char *str;
playitem_t *item;
if(*line[0] == '#') continue;
str = strndup(*line, a-1);
/* printf("%s\n", str); */
item = playitem_new (TYPE_REG, basename(str), str, list_new());
ho_free(str);
playitem_append(item, items);
}
ho_free(line);
ho_free(n);
fclose(file);
}
static void read_subs(xml_node_t *node, list_t *items) {
playitem_t *item = NULL;
while (node) {
if (!strcasecmp (node->name, "entry")) {
item = playitem_load (node->child);
} else if(!strcasecmp (node->name, "sub")) {
char title[256];
snprintf(title, 255, "[%s]", xml_parser_get_property (node, "name"));
item = playitem_new (TYPE_DIR, title, NULL, list_new());
read_subs(node->child, item->sub);
}
playitem_append(item, items);
node=node->next;
}
}
static int read_mediamarks(list_t *list, const char *mrl) {
int size;
char *file = read_entire_file(mrl, &size);
xml_node_t *node;
if (!file) return 0;
xml_parser_init (file, strlen (file), XML_PARSER_CASE_INSENSITIVE);
if (xml_parser_build_tree (&node)<0) {
printf("mediamarks: xml parsing of %s failed\n", mrl);
return 0;
}
if (strcasecmp (node->name, "oxinemm")) {
printf ("mediamarks: error, root node must be OXINEMM\n");
return 0;
}
read_subs(node->child, list);
xml_parser_free_tree(node);
ho_free(file);
return 1;
}
static void changelist (otk_widget_t *list, list_t *backpath) {
playitem_t *item, *back;
list_t *current = list_first_content(backpath);
list_t *parent = list_next_content(backpath);
otk_remove_listentries(list);
item = list_first_content(current);
if((item->type != TYPE_UP)&&(parent)) {
back = playitem_new(TYPE_UP, "[..]", NULL, parent);
list_insert_content(current, back);
//otk_add_listentry(list, back->title, back, -1);
}
item = list_first_content(current);
while (item) {
/*printf("item : %s\n" ,item->title);*/
otk_add_listentry(list, item->title, item, -1);
item = list_next_content(current);
}
otk_list_set_pos(list,0);
otk_set_focus(list);
}
static void action_changed (void *data, int pos) {
mm_session_t *session = (mm_session_t*) data;
session->action = pos;
}
static void set_ilabel(mm_session_t *session) {
int n;
n = gGui->playlist.num;
sprintf(session->ilabel, "Selected: %3d", n);
}
static void mediamarks_play_cb(void *data, void *entry) {
mm_session_t *session = (mm_session_t*) data;
oxine_t *oxine = session->oxine;
playitem_t *item = (playitem_t*) entry;
session->listpos = otk_list_get_pos(session->list);
#ifdef LOG
printf("mediamarks: mediamarks_play_cb %s\n", item->mrl);
fflush(NULL);
#endif
if (item->type == TYPE_DIR) {
bpush(session->backpath, item->sub);
changelist(session->list, session->backpath);
otk_draw_all(oxine->otk);
} else if (item->type == TYPE_RDIR) {
read_directory(oxine, item->mrl, item->sub);
bpush(session->backpath, item->sub);
changelist(session->list, session->backpath);
otk_draw_all(oxine->otk);
} else if (item->type == TYPE_UP) {
bpop(session->backpath);
changelist(session->list, session->backpath);
otk_draw_all(oxine->otk);
} else if (session->action == MM_ACTION_PLAY) {
if ((item->type == TYPE_REG)||(item->type == TYPE_RREG)) {
printf("mediamarks: playing %s\n", item->mrl);
/* if (is_movie(item->mrl)) {
oxine->main_window = NULL;
oxine->info_window = NULL;
otk_clear(oxine->otk);
if (oxine->filename)
ho_free(oxine->filename);
oxine->filename=ho_strdup(item->mrl);
select_subtitle_cb(get_dirname(oxine->filename), oxine, 0);
} else */ if(odk_open_and_play(oxine->odk, item->mrl)) {
set_ilabel(session);
oxine->main_window = NULL;
oxine->info_window = NULL;
oxine->mode = OXINE_MODE_NORMAL;
otk_clear(oxine->otk);
} /* else play_error(oxine); */
set_ilabel(session);
} else if (item->type == TYPE_M3U) {
parse_m3u(item->mrl, item->sub);
bpush(session->backpath, item->sub);
changelist(session->list, session->backpath);
otk_draw_all(oxine->otk);
} else if (item->type == TYPE_MULTIPLE) {
if (parse_multiple(oxine, item->mrl, item->sub)) {
bpush(session->backpath, item->sub);
changelist(session->list, session->backpath);
otk_draw_all(oxine->otk);
} else
printf("mediamarks: error getting autoplay mrls\n");
} else printf("mediamarks: %s is of unknown type\n", item->mrl);
} else if (session->action == MM_ACTION_ADD) {
if ((item->type == TYPE_REG)||(item->type == TYPE_RREG)) {
odk_enqueue(session->oxine->odk, item->mrl); /* FIXME: item->title unused */
set_ilabel(session);
otk_draw_all(session->oxine->otk);
}
}
}
static void mediamarks_leavetoplaylist_cb (void *data) {
/*
mm_session_t *session = (mm_session_t*) data;
session->oxine->reentry = NULL;
session->oxine->reentry_data = NULL;
playlist_cb(session->oxine);
*/
}
static void mediamarks_freeall(void *data) {
mm_session_t *session = (mm_session_t *) data;
list_t *current = list_first_content(session->backpath);
current = list_first_content(session->backpath);
while(current) {
free_subtree(current, 1);
list_delete_current(session->backpath);
current = list_first_content(session->backpath);
}
list_free(session->backpath);
}
static void mediamarks_leave_cb (void *data) {
mm_session_t *session = (mm_session_t*) data;
session->oxine->reentry = NULL;
session->oxine->reentry_data = NULL;
mediamarks_freeall(session);
session->oxine->main_menu_cb(session->oxine);
ho_free(session);
}
static void mediamarks_reentry_cb (void *data) {
mm_session_t *session = (mm_session_t*) data;
oxine_t *oxine = session->oxine;
otk_widget_t *b, *list_window;
lock_job_mutex();
if (oxine->info_window && oxine->media_info_close_cb) {
oxine->media_info_close_cb(oxine);
}
unlock_job_mutex();
otk_clear(oxine->otk);
oxine->main_window = otk_window_new (oxine->otk, NULL, 20, 130, 225, 420);
otk_label_new (oxine->main_window, 108, 60, OTK_ALIGN_CENTER|OTK_ALIGN_BOTTOM, \
"Action:"); b = otk_selector_new (oxine->main_window, 10, 80, 195, 60, \
mm_action_strings, 2, action_changed, session); otk_set_focus(b);
otk_selector_set(b, session->action);
otk_button_new (oxine->main_window, 10, 170, 195, 60, "Playlist", \
mediamarks_leavetoplaylist_cb, session); set_ilabel(session);
otk_label_new (oxine->main_window, 108, 280, OTK_ALIGN_CENTER|OTK_ALIGN_BOTTOM, \
session->ilabel); otk_button_new (oxine->main_window, 10, 340, 195, 60, "Back", \
mediamarks_leave_cb, session);
list_window = otk_window_new (oxine->otk, NULL, 245, 130, 535, 420);
session->list = otk_list_new(list_window, 10, 15, 523, 390, mediamarks_play_cb, \
session); changelist(session->list, session->backpath);
otk_list_set_pos(session->list, session->listpos);
otk_draw_all(oxine->otk);
}
void mediamarks_cb (void *data) {
oxine_t *oxine = (oxine_t*) data;
char mmpath[1025];
mm_session_t *session;
list_t *items = list_new();
session = ho_new(mm_session_t);
session->oxine = oxine;
session->backpath = list_new();
session->action = 1;
session->listpos = 0;
snprintf(mmpath,1024,"%s/.xine/oxine_mediamarks", getenv("HOME"));
if (!read_mediamarks(items, mmpath)) {
printf("mediamarks: trying to load system wide mediamarks\n");
snprintf(mmpath,1024,"%s/oxine_mediamarks", XINE_SCRIPTDIR);
if (read_mediamarks(items, mmpath)) {
bpush(session->backpath, items);
oxine->reentry_data = session;
oxine->reentry = mediamarks_reentry_cb;
mediamarks_reentry_cb(session);
} else {
list_free(items);
list_free(session->backpath);
ho_free(session);
}
} else {
bpush(session->backpath, items);
oxine->reentry_data = session;
oxine->reentry = mediamarks_reentry_cb;
mediamarks_reentry_cb(session);
}
}
--- NEW FILE: mediamarks.h ---
/*
* Copyright (C) 2002 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: mediamarks.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* parsing gxine's mediamarks
*/
#ifndef HAVE_MEDIAMARKS_H
#define HAVE_MEDIAMARKS_H
void mediamarks_cb (void *data);
#endif
--- NEW FILE: odk.c ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: odk.c,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* odk abstracts from xine and other software / hardware interfaces
*/
/*
#define LOG
*/
#include <stdio.h>
#include <string.h>
#include <xine.h>
#include "common.h"
#include "odk.h"
#include "utils.h"
extern gGui_t *gGui;
#define V_WIDTH 800
#define V_HEIGHT 600
/* determined by xine engine: */
#define NUM_COLORS 256
struct odk_s {
xine_t *xine;
xine_stream_t *stream;
xine_osd_t *osd;
int unscaled_osd;
double vscale, hscale;
int (*event_handler)(void *data, oxine_event_t *ev);
void *event_handler_data;
uint32_t color[NUM_COLORS];
uint8_t trans[NUM_COLORS];
int palette_fill;
char *menu_bg;
int is_freetype;
};
/* generates a gradient on palette out of given values */
static void palette_transition(odk_t *odk, int from_index, int to_index,
uint32_t from_color, uint8_t from_trans,
uint32_t to_color, uint8_t to_trans) {
double cr_step, cb_step, y_step;
uint8_t cr_from, cb_from, y_from;
uint8_t cr_to, cb_to, y_to;
double trans_step;
int num;
num = to_index - from_index;
trans_step = (double)(to_trans - from_trans) / num;
cb_from = from_color & 0xff;
cr_from = (from_color >> 8) & 0xff;
y_from = (from_color >> 16) & 0xff;
cb_to = to_color & 0xff;
cr_to = (to_color >> 8) & 0xff;
y_to = (to_color >> 16) & 0xff;
cb_step = (double)(cb_to - cb_from) / num;
cr_step = (double)(cr_to - cr_from) / num;
y_step = (double)(y_to - y_from) / num;
for (num = from_index; num < to_index; num++) {
uint8_t cb_cur = cb_from + (int8_t)(cb_step * (num-from_index));
uint8_t cr_cur = cr_from + (int8_t)(cr_step * (num-from_index));
uint8_t y_cur = y_from + (int8_t)( y_step * (num-from_index));
odk->color[num] = cb_cur + (cr_cur<<8) + (y_cur<<16);
odk->trans[num] = from_trans + trans_step * (num-from_index);
/* printf("writing: color %x trans %u to %u\n", odk->color[num], odk->trans[num], \
num); */ }
odk->color[to_index] = to_color;
odk->trans[to_index] = to_trans;
}
int odk_get_color(odk_t *odk, uint32_t color, uint8_t trans) {
int i;
for(i=0; i<odk->palette_fill; i++) {
if ((odk->color[i] == color) && (odk->trans[i] == trans))
return i;
}
if (odk->palette_fill == NUM_COLORS) {
printf("odk: too many colors: palette is full\n");
return 0;
}
odk->color[odk->palette_fill]=color;
odk->trans[odk->palette_fill]=trans;
xine_osd_set_palette(odk->osd, odk->color, odk->trans);
odk->palette_fill++;
return odk->palette_fill - 1;
}
int odk_alloc_text_palette(odk_t *odk, uint32_t fg_color, uint8_t fg_trans,
uint32_t bg_color, uint8_t bg_trans,
uint32_t bo_color, uint8_t bo_trans) {
odk->color[odk->palette_fill]=bg_color; /* not really used by fonts, set to bg */
odk->trans[odk->palette_fill]=bg_trans;
/* background (1) to border (6) transition */
palette_transition(odk, odk->palette_fill+1, odk->palette_fill+6,
bg_color, bg_trans, bo_color, bo_trans);
/* border (6) to foreground (10) transition */
palette_transition(odk, odk->palette_fill+6, odk->palette_fill+10,
bo_color, bo_trans, fg_color, fg_trans);
odk->palette_fill += 11;
xine_osd_set_palette(odk->osd, odk->color, odk->trans);
return odk->palette_fill-11;
}
/*
* adapt osd to new stream size.
* This only affects primitives drawn after
* this call.
*/
static void odk_adapt(odk_t *odk) {
int width, height;
if (odk->osd) xine_osd_free(odk->osd);
if( odk->unscaled_osd )
video_window_get_output_size(&width, &height);
else
video_window_get_frame_size(&width, &height);
lprintf("odk_adapt to: %i, %i\n", width, height);
odk->vscale = height / (double)V_HEIGHT;
odk->hscale = width / (double)V_WIDTH;
odk->osd = xine_osd_new(odk->stream, 0, 0, width, height);
xine_osd_set_palette(odk->osd, odk->color, odk->trans);
}
uint8_t *odk_get_pixmap(int type) {
int i;
uint8_t arrowup[] = {0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0};
uint8_t arrowdown[] = {0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 0, 0};
uint8_t *p = NULL;
p = ho_newstring(10*10 + 10);
switch(type) {
case PIXMAP_SIMPLE_ARROW_UP:
memcpy(p, arrowup, 100);
break;
case PIXMAP_SIMPLE_ARROW_DOWN:
memcpy(p, arrowdown, 100);
break;
}
/* FIXME: check this stuff "XINE_OSD_TEXT1 + 2" */
for(i=0;i<100;i++) p[i] = p[i] * XINE_OSD_TEXT1 + 2;
return p;
}
/*
* initializes drawable, xine stream and osd
*/
odk_t *odk_init(void) {
odk_t *odk = ho_new_tagged(odk_t, "odk object");
lprintf("initializing\n");
odk->palette_fill = 0;
odk->hscale = 0;
odk->vscale = 0;
odk->xine = gGui->xine;
odk->stream = gGui->stream;
/* test unscaled osd support */
odk->osd = xine_osd_new(odk->stream, 0, 0, 10, 10);
odk->unscaled_osd =
(xine_osd_get_capabilities(odk->osd) & XINE_OSD_CAP_UNSCALED );
xine_osd_free(odk->osd);
odk->osd = NULL;
odk_adapt(odk);
return odk;
}
/*
* primitive drawing functions
*/
void odk_draw_bitmap(odk_t *odk, uint8_t *bitmap, int x1, int y1, int width, int \
height, uint8_t *palette_map)
{
/* uint8_t a[] = {0, 0, 0, 255, 255, 255}; */
if (!(odk->hscale&&odk->vscale)) return;
/* FIXME: scaling? */
xine_osd_draw_bitmap(odk->osd, bitmap, x1, y1, width, height, NULL);
}
void odk_draw_line(odk_t *odk, int x1, int y1, int x2, int y2, int color) {
int px1, py1, px2, py2;
if (!(odk->hscale&&odk->vscale)) return;
px1 = (int) ((double)x1*odk->hscale);
py1 = (int) ((double)y1*odk->vscale);
px2 = (int) ((double)x2*odk->hscale);
py2 = (int) ((double)y2*odk->vscale);
lprintf("drawing line %u %u %u %u col: %u\n", px1, py1, px2, py2, color);
xine_osd_draw_line(odk->osd,
px1,
py1,
px2,
py2,
color);
}
void odk_draw_rect(odk_t *odk, int x1, int y1, int x2, int y2, int filled, int color) \
{
int px1, py1, px2, py2;
if (!(odk->hscale&&odk->vscale)) return;
px1 = (int) ((double)x1*odk->hscale);
py1 = (int) ((double)y1*odk->vscale);
px2 = (int) ((double)x2*odk->hscale);
py2 = (int) ((double)y2*odk->vscale);
lprintf("drawing rect %u %u %u %u col: %u\n", px1, py1, px2, py2, color);
xine_osd_draw_rect(odk->osd,
px1, py1, px2, py2, color, filled);
}
void odk_draw_text(odk_t *odk, int x, int y, const char *text, int alignment, int \
color) {
int px, py, w, h;
if (!(odk->hscale&&odk->vscale)) return;
odk_get_text_size(odk, text, &w, &h);
if (odk->is_freetype) {
if (alignment & ODK_ALIGN_VCENTER) y += h/2;
if (alignment & ODK_ALIGN_TOP) y += h;
} else {
if (alignment & ODK_ALIGN_VCENTER) y -= h/2;
if (alignment & ODK_ALIGN_BOTTOM) y -= h;
}
if (alignment & ODK_ALIGN_CENTER) x -= w/2;
if (alignment & ODK_ALIGN_RIGHT) x -= w;
px = (int) ((double)x*odk->hscale);
py = (int) ((double)y*odk->vscale);
lprintf("drawing text at %u %u (vs: %f hs: %f)\n", px, py, odk->vscale, \
odk->hscale);
xine_osd_draw_text(odk->osd, px, py, text, color);
}
/*
* overall osd control
*/
void odk_show(odk_t *odk) {
if( odk->unscaled_osd )
xine_osd_show_unscaled(odk->osd, 0);
else
xine_osd_show(odk->osd, 0);
}
void odk_hide(odk_t *odk) {
xine_osd_hide(odk->osd, 0);
}
void odk_clear(odk_t *odk) {
xine_osd_clear(odk->osd);
}
/*
* font stuff
*/
void odk_get_text_size(odk_t *odk, const char *text, int *width, int *height) {
int w, h;
if (!(odk->hscale&&odk->vscale)) {
*width = 0;
*height = 0;
return;
}
xine_osd_get_text_size(odk->osd, text, &w, &h);
*width = (int) ((double)w/odk->hscale);
*height = (int) ((double)h/odk->vscale);
}
void odk_set_font(odk_t *odk, const char *font, int size) {
int psize;
psize = (int)((double)size*(odk->hscale+odk->vscale)/2);
/* smallest text size possible */
if (psize<16) psize=16;
lprintf("setting font to %s %u %u\n", font, size, psize);
if (strchr(font, '.')||strchr(font, '/'))
odk->is_freetype = 1;
else
odk->is_freetype = 0;
xine_osd_set_font(odk->osd, font, psize);
}
/*
* event stuff
*/
void odk_set_event_handler(odk_t *odk, int (*cb)(void *data, oxine_event_t *ev), void \
*data) {
odk->event_handler = cb;
odk->event_handler_data = data;
}
int odk_send_event(odk_t *odk, oxine_event_t *event) {
switch (event->type) {
case OXINE_EVENT_FORMAT_CHANGED:
odk_adapt(odk);
break;
case OXINE_EVENT_BUTTON:
case OXINE_EVENT_MOTION:
if( !odk->unscaled_osd ) {
x11_rectangle_t rect;
rect.x = event->x;
rect.y = event->y;
rect.w = 0;
rect.h = 0;
if (xine_port_send_gui_data(gGui->vo_port,
XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect) == -1) {
return 0;
}
event->x = rect.x;
event->y = rect.y;
}
event->x = (int) ((double)event->x/odk->hscale);
event->y = (int) ((double)event->y/odk->vscale);
if ((event->x < 0) || (event->x > V_WIDTH)) return 0;
if ((event->y < 0) || (event->y > V_HEIGHT)) return 0;
}
if (odk->event_handler)
return odk->event_handler(odk->event_handler_data, event);
return 0;
}
/*
* destructor
*/
void odk_free(odk_t *odk) {
lprintf("finalizing\n");
xine_osd_free(odk->osd);
ho_free(odk);
}
/*
* xine control
*/
void odk_enqueue(odk_t *odk, const char *mrl)
{
int t = 0;
int playlist_num = gGui->playlist.num;
gui_dndcallback((char *)mrl);
/* wait a bit to get it enqueued */
while( t < 20 && playlist_num == gGui->playlist.num )
usleep(10000);
}
int odk_open_and_play(odk_t *odk, const char *mrl) {
odk_enqueue(odk, mrl);
if((xine_get_status(gGui->stream) != XINE_STATUS_STOP)) {
gGui->ignore_next = 1;
xine_stop(gGui->stream);
gGui->ignore_next = 0;
}
if( gGui->playlist.num ) {
gui_set_current_mmk(gGui->playlist.mmk[gGui->playlist.num - 1]);
return gui_xine_open_and_play(gGui->mmk.mrl, gGui->mmk.sub, 0,
gGui->mmk.start, gGui->mmk.av_offset, gGui->mmk.spu_offset, 0);
} else
return 0;
}
void odk_play(odk_t *odk) {
gui_xine_play(odk->stream, 0, 0, 1);
}
void odk_stop(odk_t *odk) {
gui_stop(NULL, NULL);
}
static int get_pos_length(xine_stream_t *stream, int *pos, int *time, int *length) {
int t = 0, ret = 0;
if(stream && (xine_get_status(stream) == XINE_STATUS_PLAY)) {
while(((ret = xine_get_pos_length(stream, pos, time, length)) == 0) && (++t < \
10)) /*printf("wait");*/
usleep(100000); /* wait before trying again */
}
return ret;
}
int odk_get_pos_length_high(odk_t *odk, int *pos, int *time, int *length) {
int ret = 0;
#if 0
static int last_time = 0;
#endif
xine_stream_t *stream = odk->stream;
if(stream && (xine_get_status(stream) == XINE_STATUS_PLAY)) {
ret = xine_get_pos_length(stream, pos, time, length);
}
/*
* smoothen the times xine returns a bit. filtering out small backjumps here.
*/
#if 0
if (ret) {
if ((*time < last_time) && (*time+1000 > last_time)) {
*time = last_time;
} else {
last_time = *time;
}
}
#endif
return ret;
}
int odk_get_pos_length(odk_t *odk, int *pos, int *time, int *length) {
return get_pos_length(odk->stream, pos, time, length);
}
/* Return stream position 1..100 */
int odk_get_seek(odk_t *odk) {
int pos_time, length;
int pos=1;
if(!odk_get_pos_length_high(odk, NULL, &pos_time, &length)) {
return -1;
}
if (length) pos = ((pos_time*100) / length);
/* printf("seek pos : %d\n", pos); */
return pos;
}
void odk_seek(odk_t *odk, int how) {
gui_seek_relative(how);
}
void odk_set_speed(odk_t *odk, uint32_t speed) {
uint32_t s = XINE_SPEED_NORMAL;
switch(speed) {
case ODK_SPEED_PAUSE:
s = XINE_SPEED_PAUSE;
break;
case ODK_SPEED_NORMAL:
s = XINE_SPEED_NORMAL;
break;
case ODK_SPEED_SLOW_4:
s = XINE_SPEED_SLOW_4;
break;
case ODK_SPEED_SLOW_2:
s = XINE_SPEED_SLOW_2;
break;
case ODK_SPEED_FAST_4:
s = XINE_SPEED_FAST_4;
break;
case ODK_SPEED_FAST_2:
s = XINE_SPEED_FAST_2;
break;
default:
printf("odk: odk_set_speed: invalid speed\n");
}
xine_set_param(odk->stream, XINE_PARAM_SPEED, s);
}
uint32_t odk_get_speed(odk_t *odk) {
int s=xine_get_param(odk->stream, XINE_PARAM_SPEED);
switch(s) {
case XINE_SPEED_PAUSE:
return ODK_SPEED_PAUSE;
break;
case XINE_SPEED_NORMAL:
return ODK_SPEED_NORMAL;
break;
case XINE_SPEED_SLOW_4:
return ODK_SPEED_SLOW_4;
break;
case XINE_SPEED_SLOW_2:
return ODK_SPEED_SLOW_2;
break;
case XINE_SPEED_FAST_4:
return ODK_SPEED_FAST_4;
break;
case XINE_SPEED_FAST_2:
return ODK_SPEED_FAST_2;
break;
default:
printf("odk: odk_get_speed: invalid speed\n");
}
return -1;
}
void odk_toggle_pause(odk_t *odk) {
gui_pause (NULL, (void*)(1), 0);
}
void odk_eject(odk_t *odk) {
xine_eject(odk->stream);
}
char *odk_get_mrl(odk_t *odk) {
return (char *)mediamark_get_current_mrl();
}
char *odk_get_meta_info(odk_t *odk, int info) {
const char *str = xine_get_meta_info(odk->stream, info);
if (!str) return NULL;
return ho_strdup(str);
}
void odk_user_color(odk_t *odk, char *name, uint32_t *color, uint8_t *trans) {
char id[512];
char value[64];
const char *v;
unsigned int c, t;
snprintf(id, 511, "gui.osdmenu.color_%s", name);
snprintf(value, 63, "%06x-%01x", *color, *trans);
v = xine_config_register_string (odk->xine, id, value,
"color specification yuv-opacity",
"color spec. format: [YUV color]-[opacity 0-f]",
10, NULL, NULL);
if (sscanf(v, "%06x-%01x", &c, &t) != 2) {
printf("odk: bad formated color spec in entry '%s'\n", id);
printf("odk: using standard color\n");
return;
}
*color = c;
*trans = t;
}
/*
* error handling
*/
int odk_get_error(odk_t *odk) {
return xine_get_error(odk->stream);
}
--- NEW FILE: odk.h ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: odk.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* odk abstracts from xine and other software / hardware interfaces
*/
/*
* the features of odk are:
*
* - framesize independent (virtual) grid (currently 800x600)
* - color palette management and generation of text palettes
* - text alignments
*/
#ifndef HAVE_ODK_H
#define HAVE_ODK_H
#include <xine.h>
#include <pthread.h>
#include "event.h"
/*
* alignments for text
*/
#define ODK_ALIGN_LEFT 0x001
#define ODK_ALIGN_CENTER 0x002
#define ODK_ALIGN_RIGHT 0x004
#define ODK_ALIGN_TOP 0x008
#define ODK_ALIGN_VCENTER 0x010
#define ODK_ALIGN_BOTTOM 0x020
#define PIXMAP_SIMPLE_ARROW_UP 1
#define PIXMAP_SIMPLE_ARROW_DOWN 2
/*
* stream speeds
*/
#define ODK_SPEED_PAUSE 0
#define ODK_SPEED_SLOW_4 1
#define ODK_SPEED_SLOW_2 2
#define ODK_SPEED_NORMAL 4
#define ODK_SPEED_FAST_2 8
#define ODK_SPEED_FAST_4 16
/*
* opaque odk data type
*/
typedef struct odk_s odk_t;
/*
* initializes xine streams, create a drawable and returns a new odk object.
* the given xine struct must have been initialized.
*/
odk_t *odk_init(void);
/*
* draw primitives
*/
void odk_draw_point(odk_t *odk, int x, int y, int color);
void odk_draw_line(odk_t *odk, int x1, int y1, int x2, int y2, int color);
void odk_draw_rect(odk_t *odk, int x1, int y1, int x2, int y2, int filled, int \
color); void odk_draw_text(odk_t *odk, int x, int y, const char *text, int alignment, \
int color);
/*
* show and hide an osd
*/
void odk_show(odk_t *odk);
void odk_hide(odk_t *odk);
/*
* clears osd
*/
void odk_clear(odk_t *odk);
/*
* simple pixmaps
*/
uint8_t *odk_get_pixmap(int type);
void odk_draw_bitmap(odk_t *odk, uint8_t *bitmap, int x1, int y1, int width, int \
height, uint8_t *palette_map);
/*
* closes streams, osd and frees resources and odk object
*/
void odk_free(odk_t *odk);
/*
* returns sizes of text if the text would have been drawn with current font
*/
void odk_get_text_size(odk_t *odk, const char *text, int *width, int *height);
/*
* change current font
*/
void odk_set_font(odk_t *odk, const char *font, int size);
/*
* allocates 10 colors from palette and returns the index to the first
* color
*/
int odk_alloc_text_palette(odk_t *odk, uint32_t fg_color, uint8_t fg_trans,
uint32_t bg_color, uint8_t bg_trans,
uint32_t bo_color, uint8_t bo_trans);
/*
* returns index to given color.
*/
int odk_get_color(odk_t *odk, uint32_t color, uint8_t trans);
/*
* use these functions to register your callbacks for different events
*/
void odk_set_event_handler(odk_t *odk, int (*cb)(void *data, oxine_event_t *ev), void \
*data);
int odk_send_event(odk_t *odk, oxine_event_t *event);
/*
* stops a running stream (if there is one),
* opens a new stream, returns 0 on success.
*/
int odk_open_and_play(odk_t *odk, const char *mrl);
void odk_enqueue(odk_t *odk, const char *mrl);
/*
* play, stop, pause, seek a stream
*/
void odk_play(odk_t *odk);
void odk_stop(odk_t *odk);
void odk_set_speed(odk_t *odk, uint32_t speed);
uint32_t odk_get_speed(odk_t *odk);
void odk_seek(odk_t *odk, int how);
void odk_eject(odk_t *odk);
/*
* Stream info
*/
char *odk_get_meta_info(odk_t *odk, int info);
int odk_get_seek(odk_t *odk); /* 1..100 */
int odk_get_pos_length(odk_t *odk, int *pos, int *time, int *length);
int odk_get_pos_length_high(odk_t *odk, int *pos, int *time, int *length);
char *odk_get_mrl(odk_t *odk);
/*
* error handling
*/
int odk_get_error(odk_t *odk);
void odk_user_color(odk_t *odk, char *name, uint32_t *color, uint8_t *trans);
#endif
--- NEW FILE: otk.c ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: otk.c,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
[...1817 lines suppressed...]
void otk_free (otk_t *otk) {
lock_job_mutex();
if(otk->update_job)
cancel_job(otk->update_job);
unlock_job_mutex();
otk_clear(otk);
g_list_free(otk->windows);
if (otk->title_font) free(otk->title_font);
if (otk->button_font) free(otk->button_font);
odk_set_event_handler(otk->odk, NULL, NULL);
pthread_mutex_destroy(&otk->draw_mutex);
ho_free (otk);
}
--- NEW FILE: otk.h ---
/*
* Copyright (C) 2002 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: otk.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* otk - the osd toolkit
*/
#ifndef HAVE_OTK_H
#define HAVE_OTK_H
#include "odk.h"
#include "list.h"
#include "event.h"
/*
* alignments for text
*/
#define OTK_ALIGN_LEFT 0x001
#define OTK_ALIGN_CENTER 0x002
#define OTK_ALIGN_RIGHT 0x004
#define OTK_ALIGN_TOP 0x008
#define OTK_ALIGN_VCENTER 0x010
#define OTK_ALIGN_BOTTOM 0x020
/*
* opaque data types
*/
typedef struct otk_s otk_t;
typedef struct otk_widget_s otk_widget_t;
/*
* user contributed callbacks
*/
typedef void (*otk_button_cb_t) (void *user_data);
typedef void (*otk_list_cb_t) (void *user_data, void *entry);
typedef void (*otk_selector_cb_t) (void *user_data, int entry);
typedef int (*otk_slider_cb_t) (odk_t *odk);
typedef void (*otk_button_uc_t) (void *data);
/*
* initialisation
*/
otk_t *otk_init (odk_t *odk);
/*
* creating widgets
*/
otk_widget_t *otk_window_new (otk_t *this, const char *title, int x, int y,
int w, int h);
otk_widget_t *otk_button_new (otk_widget_t *win, int x, int y,
int w, int h, char *text,
otk_button_cb_t cb,
void *user_data);
otk_widget_t *otk_button_grid_new (char *text,
otk_button_cb_t cb,
void *user_data);
otk_widget_t *otk_label_new (otk_widget_t *win, int x, int y, int alignment,
char *text);
otk_widget_t *otk_list_new (otk_widget_t *win, int x, int y, int w, int h,
otk_list_cb_t cb,
void *user_data);
otk_widget_t *otk_slider_new (otk_widget_t *win, int x, int y, int w, int h, \
otk_slider_cb_t cb); otk_widget_t *otk_slider_grid_new (otk_slider_cb_t cb);
otk_widget_t *otk_selector_new(otk_widget_t *win, int x, int y,
int w, int h, const char **items, int num,
otk_selector_cb_t cb,
void *cb_data);
otk_widget_t *otk_selector_grid_new (const char **items, int num,
otk_selector_cb_t cb,
void *cb_data);
otk_widget_t *otk_layout_new(otk_widget_t *win, int x, int y, int w, int h, int rows, \
int columns);
/*
* selector widget functions
*/
void otk_selector_set(otk_widget_t *this, int pos);
/*
* button widget functions
*/
void otk_button_uc_set(otk_widget_t *wid, otk_button_uc_t uc, void *data);
/*
* layout widget functions
*/
/* layout widget use widget's x,y,w,h to set positions and sizes :
x = start row : y = start column
w = columns to be uses : h = rows to be used
*/
void otk_layout_add_widget(otk_widget_t *layout, otk_widget_t *widget, int srow, int \
scol, int frow, int fcol);
/*
* list widget functions
*/
void otk_add_listentry(otk_widget_t *this, char *text, void *data, int pos);
void otk_remove_listentries(otk_widget_t *this);
int otk_list_get_pos(otk_widget_t *this);
void otk_list_set_pos(otk_widget_t *this, int newpos);
/* returns number of last selected entry (first entry in list is 1) */
int otk_list_get_entry_number(otk_widget_t *this);
/*
* update drawing area
*/
void otk_draw_all (otk_t *otk);
/* on 1, update this widget continously (every 100 ms) */
void otk_set_update(otk_widget_t *this, int update);
/*
* set focus to a specific widget (causes buttons lighting up)
*/
void otk_set_focus (otk_widget_t *widget);
/*
* frees given widget and all its childs
*/
void otk_destroy_widget (otk_widget_t *widget);
/*
* frees all widgets
*/
void otk_clear (otk_t *otk);
/*
* frees otk struct
*/
void otk_free (otk_t *otk);
/*
* event stuff
*/
void otk_set_event_handler(otk_t *otk, int (*cb)(void *data, oxine_event_t *ev), void \
*data);
int otk_send_event(otk_t *otk, oxine_event_t *event);
#endif
--- NEW FILE: oxine.c ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: oxine.c,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* oxine main program
*/
#define LOG
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
#include <xine.h>
#include "common.h"
#include "oxine.h"
#include "odk.h"
#include "otk.h"
#include "event.h"
#include "utils.h"
#include "mediamarks.h"
extern gGui_t *gGui;
static oxine_t *oxine_instance = NULL;
static void main_menu_cb(void *data);
static void playing_menu_cb(void *data);
static void media_stop_cb(void *data);
static void media_info_cb(void *data);
//static void media_returnto_cb(void *data);
//static void media_freeandreturnto_cb(void *data);
static void media_pause_cb(void *data, int i);
//static void event_delay(void *data);
const char *playpause_strings[] = { "<", ">" };
static void media_pause_cb(void *data, int i) {
oxine_t *oxine = (oxine_t*) data;
switch(i) {
case 1:
odk_set_speed(oxine->odk, ODK_SPEED_NORMAL);
break;
case 2:
odk_set_speed(oxine->odk, ODK_SPEED_PAUSE);
break;
}
}
static void format_time(char *buf, int sec) {
sprintf(buf, "%d:%02d:%02d", sec/3600, (sec%3600)/60, ((sec%3600)%60));
}
static void media_stop_cb(void *data) {
oxine_t *oxine = (oxine_t*) data;
odk_stop(oxine->odk);
/*
odk_open_and_play(oxine->odk, oxine->menu_bg);
*/
oxine->main_menu_cb(oxine);
}
static void media_tracks_list_cb(void *data, void *entry) {
oxine_t *oxine = (oxine_t *) data;
char *mrl = (char *) entry;
odk_stop(oxine->odk);
odk_open_and_play(oxine->odk, mrl);
}
/*
static void media_tracks_quit(void *data) {
oxine_t *oxine = (oxine_t*) data;
oxine->need_draw = 0;
printf("%d\n", oxine->mode);
oxine->mode = OXINE_MODE_NORMAL;
printf("%d\n", oxine->mode);
oxine->pauseplay = NULL;
otk_clear(oxine->otk);
}
*/
static void media_tracks_cb(void *data) {
oxine_t *oxine = (oxine_t *) data;
int num, i = 0;
char **str;
otk_widget_t *list;
oxine->pauseplay = NULL;
oxine->main_window = NULL;
oxine->info_window = NULL;
otk_clear(oxine->otk);
oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 50, 550, 500);
list = otk_list_new(oxine->main_window, 10, 10, 500, 490, media_tracks_list_cb, \
oxine);
str = xine_get_autoplay_mrls (oxine->xine, "CD", &num);
while(i < num) {
/* printf("%d %s\n", i, str[i]); */
otk_add_listentry(list, str[i], str[i], -1);
i++;
}
otk_list_set_pos(list, 0);
otk_set_focus(list);
otk_draw_all(oxine->otk);
}
#if 0
static void info_button_time(void *data) {
oxine_t *oxine = (oxine_t *)data;
int ret, pos_time, length;
ret = odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length);
/* oxine->time = malloc(sizeof(char)*255); */
if(ret) {
pos_time /= 1000;
length /= 1000;
sprintf(oxine->time, "(%d:%02d:%02d / %d:%02d:%02d)", pos_time/3600, \
(pos_time%3600)/60, ((pos_time%3600)%60), length/3600, (length%3600)/60, \
((length%3600)%60)); }
else sprintf(oxine->time, "N/A");
}
#endif
static void media_info_close_cb(void *data) {
oxine_t *oxine = (oxine_t*) data;
if (!oxine->info_window) return;
otk_destroy_widget(oxine->info_window);
oxine->info_window = NULL;
otk_draw_all(oxine->otk);
if (oxine->lines[0]) ho_free(oxine->lines[0]);
if (oxine->lines[1]) ho_free(oxine->lines[1]);
if (oxine->lines[2]) ho_free(oxine->lines[2]);
}
static void media_info_cb(void *data) {
oxine_t *oxine = (oxine_t*) data;
int pos_time, length, ret;
int cline = 0;
char *buf1, *buf2;
/* otk_widget_t *b, *layout; */
oxine->media_info_close_cb = media_info_close_cb;
oxine->pauseplay = NULL;
if (oxine->info_window) {
otk_destroy_widget(oxine->info_window);
oxine->info_window = NULL;
otk_draw_all(oxine->otk);
return;
}
/* otk_clear(oxine->otk); */
buf2 = NULL;
buf1 = odk_get_mrl(oxine->odk);
if (buf1) {
buf2 = strrchr(buf1,'/');
if (buf2) buf2++; else buf2 = buf1;
}
if (oxine->lines[0]) ho_free(oxine->lines[0]);
if (oxine->lines[1]) ho_free(oxine->lines[1]);
if (oxine->lines[2]) ho_free(oxine->lines[2]);
oxine->lines[0] = odk_get_meta_info(oxine->odk, XINE_META_INFO_TITLE);
if(!oxine->lines[0] && buf2) oxine->lines[0] = ho_strdup(buf2);
if(oxine->lines[0]) cline++;
buf1 = odk_get_meta_info(oxine->odk, XINE_META_INFO_ARTIST);
buf2 = odk_get_meta_info(oxine->odk, XINE_META_INFO_ALBUM);
if (buf1 && buf2) {
oxine->lines[cline] = ho_newstring(strlen(buf1)+strlen(buf2)+10);
sprintf(oxine->lines[cline], "%s: %s", buf1, buf2);
cline++;
} else if (buf1 && (strlen(buf1)>0)) {
oxine->lines[cline++] = ho_strdup(buf1);
} else if (buf2 && (strlen(buf2)>0)) {
oxine->lines[cline++] = ho_strdup(buf2);
}
/*
oxine->genre = odk_get_meta_info(oxine->odk, XINE_META_INFO_GENRE);
if(!oxine->genre) oxine->genre = ho_strdup("Genre N/A");
oxine->year = odk_get_meta_info(oxine->odk, XINE_META_INFO_YEAR);
if(!oxine->year) oxine->year = ho_strdup("Year N/A");
*/
ret = odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length);
if(ret && (length > 0)) {
oxine->lines[cline] = ho_newstring(255);
pos_time /= 1000;
length /= 1000;
format_time(oxine->lines[cline], length);
}
oxine->info_window = otk_window_new (oxine->otk, NULL, 5, 5, 790, 240);
if (oxine->lines[0])
otk_label_new(oxine->info_window, 5, 40, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, \
oxine->lines[0]);
if (oxine->lines[1])
otk_label_new(oxine->info_window, 5, 110, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, \
oxine->lines[1]);
if (oxine->lines[2])
otk_label_new(oxine->info_window, 5, 180, OTK_ALIGN_LEFT|OTK_ALIGN_VCENTER, \
oxine->lines[2]);
/*
layout = otk_layout_new(oxine->info_window, 10, 10, 680, 480, 6, 1);
b = otk_button_grid_new(oxine->title, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 0, 1, 1);
otk_set_focus(b);
b = otk_button_grid_new(oxine->artist, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 1, 1, 1);
b = otk_button_grid_new(oxine->genre, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 2, 1, 1);
b = otk_button_grid_new(oxine->album, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 3, 1, 1);
b = otk_button_grid_new(oxine->year, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 4, 1, 1);
b = otk_button_grid_new(oxine->time, media_freeandreturnto_cb, oxine);
otk_layout_add_widget(layout, b, 0, 5, 1, 1);
otk_button_uc_set(b, info_button_time, oxine);
*/
otk_draw_all(oxine->otk);
schedule_job(5000, media_info_close_cb, oxine);
}
/*
static void media_returnto_cb(void *data) {
oxine_t *oxine = (oxine_t*) data;
oxine->need_draw = 0;
printf("%d\n", oxine->mode);
oxine->mode = OXINE_MODE_NORMAL;
printf("%d\n", oxine->mode);
oxine->pauseplay = NULL;
otk_clear(oxine->otk);
}
*/
static void shutdown_cb (void *data) {
/*
oxine_t *oxine = (oxine_t*) data;
*/
}
static void dvb_cb (void *data) {
oxine_t *oxine = (oxine_t*) data;
oxine->pauseplay = NULL;
oxine->main_window = NULL;
otk_clear(oxine->otk);
oxine->mode = OXINE_MODE_NORMAL;
odk_open_and_play(oxine->odk, "dvb://");
}
static void tv_cb (void *data) {
oxine_t *oxine = (oxine_t*) data;
oxine->pauseplay = NULL;
oxine->main_window = NULL;
otk_clear(oxine->otk);
oxine->mode = OXINE_MODE_NORMAL;
odk_open_and_play(oxine->odk, "v4l://");
}
static void playing_menu_update(void *data) {
oxine_t *oxine = (oxine_t *) data;
int pos_time, length;
if (oxine->pos_str)
if (odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length)) {
pos_time /= 1000;
format_time(oxine->pos_str, pos_time);
}
}
static void playing_menu_cb(void *data) {
oxine_t *oxine = (oxine_t *) data;
otk_widget_t *b, *l;
otk_widget_t *layout;
int pos_time, length;
oxine->pauseplay = NULL;
if (oxine->main_window) {
otk_destroy_widget(oxine->main_window);
oxine->main_window = NULL;
otk_draw_all(oxine->otk);
}
/* otk_clear(oxine->otk); */
if(oxine->mode == OXINE_MODE_PLAY_MENU) {
oxine->mode = OXINE_MODE_NORMAL;
return ;
}
oxine->mode = OXINE_MODE_PLAY_MENU;
oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 400, 700, 150);
layout = otk_layout_new(oxine->main_window, 10, 10, 680, 130, 2, 6);
oxine->pauseplay = otk_selector_grid_new (playpause_strings, 2, media_pause_cb, \
oxine); otk_layout_add_widget(layout, oxine->pauseplay, 0, 0, 1, 1);
otk_set_focus(oxine->pauseplay);
if (odk_get_speed(oxine->odk) == ODK_SPEED_PAUSE) \
otk_selector_set(oxine->pauseplay, 2);
b = otk_button_grid_new ("}", media_stop_cb, oxine);
otk_layout_add_widget(layout, b, 1, 0, 1, 1);
/* b = otk_button_grid_new ("Volume", NULL, NULL);
otk_layout_add_widget(layout, b, 0, 1, 1, 1);
b = otk_slider_grid_new (odk_get_volume);
otk_layout_add_widget(layout, b, 1, 1, 1, 1);
if(!oxine->cd_in_use) {
b = otk_button_grid_new("Seek", NULL, NULL);
otk_layout_add_widget(layout, b, 0, 2, 1, 1);
}else {
b = otk_button_grid_new ("T", media_tracks_cb, oxine);
otk_layout_add_widget(layout, b, 0, 2, 1, 1);
}*/
if(oxine->cd_in_use) {
b = otk_button_grid_new ("T", media_tracks_cb, oxine);
otk_layout_add_widget(layout, b, 3, 0, 1, 1);
}
b = otk_slider_grid_new (odk_get_seek);
otk_layout_add_widget(layout, b, 2, 1, 4, 1);
otk_set_update(b,1);
b = otk_button_grid_new ("i", media_info_cb, oxine);
otk_layout_add_widget(layout, b, 2, 0, 1, 1);
if (!oxine->pos_str) oxine->pos_str = ho_newstring(64);
if (odk_get_pos_length_high(oxine->odk, NULL, &pos_time, &length)) {
pos_time /= 1000;
format_time(oxine->pos_str, pos_time);
}
l = otk_label_new (oxine->main_window, 110, 100, \
OTK_ALIGN_CENTER|OTK_ALIGN_VCENTER, oxine->pos_str); otk_set_update(l,1);
otk_button_uc_set(b, playing_menu_update, oxine);
/* oxine->need_draw = 1; */
otk_draw_all(oxine->otk);
}
static void main_menu_cb(void *data) {
oxine_t *oxine = (oxine_t*) data;
otk_widget_t *b;
lock_job_mutex();
if (oxine->info_window) {
media_info_close_cb(oxine);
}
unlock_job_mutex();
oxine->pauseplay = NULL;
oxine->main_window = NULL;
otk_clear(oxine->otk);
oxine->main_window = otk_window_new (oxine->otk, NULL, 50, 130, 700, 420);
/*
b = otk_button_new (oxine->main_window, 50, 45, 290, 60, "Play Disc", disc_cb, \
oxine); otk_set_focus(b);
*/
b = otk_button_new (oxine->main_window, 360, 45, 290, 60, "Mediamarks", \
mediamarks_cb, oxine); otk_set_focus(b);
b = otk_button_new (oxine->main_window, 50, 150, 290, 60, "Analogue TV", tv_cb, \
oxine); otk_set_focus(b);
/*
otk_button_new (oxine->main_window, 360, 150, 290, 60, "Playlist", playlist_cb, \
oxine);
*/
otk_button_new (oxine->main_window, 50, 255, 290, 60, "Digital TV", dvb_cb, oxine);
/*
otk_button_new (oxine->main_window, 360, 255, 290, 60, "Control", control_cb, \
oxine);
*/
otk_button_new (oxine->main_window, 205, 320, 290, 60, "Shutdown", shutdown_cb, \
oxine);
/* otk_button_new (oxine->main_window, 50, 180, 290, 60, "File", file_cb, oxine);
otk_button_new (oxine->main_window, 50, 260, 290, 60, "Streaming", streaming_cb, \
oxine);*/
otk_draw_all(oxine->otk);
}
/*
* initialisation
*/
oxine_t *create_oxine(void) {
oxine_t *oxine;
xine_cfg_entry_t centry;
oxine = ho_new(oxine_t);
oxine->main_menu_cb = main_menu_cb;
oxine->xine = gGui->xine;
oxine->cd_mountpoint =
xine_config_register_string (oxine->xine,
"gui.osdmenu.dvd_mountpoint",
"/dvd",
"directory a media in dvd device will be mounted",
"directory a media in dvd device will be mounted",
10,
NULL,
NULL);
xine_config_lookup_entry (oxine->xine, "input.dvd_device", ¢ry);
oxine->cd_device = centry.str_value;
start_scheduler();
oxine->odk = odk_init();
oxine->otk = otk_init(oxine->odk);
oxine->mode = OXINE_MODE_NORMAL;
return oxine;
}
void destroy_oxine(oxine_t *oxine) {
if (oxine->otk) otk_free(oxine->otk);
if (oxine->odk) odk_free(oxine->odk);
ho_free(oxine);
stop_scheduler();
#ifdef DEBUG
heapstat();
#endif
}
void oxine_init(void)
{
oxine_instance = create_oxine();
}
void oxine_exit(void)
{
destroy_oxine(oxine_instance);
oxine_instance = NULL;
}
void oxine_menu(void)
{
oxine_t *oxine = oxine_instance;
if( !oxine )
return;
oxine_adapt();
if( oxine->mode != OXINE_MODE_MAINMENU ) {
if( oxine->reentry )
oxine->reentry(oxine->reentry_data);
else
main_menu_cb(oxine);
oxine->mode = OXINE_MODE_MAINMENU;
} else {
oxine->mode = OXINE_MODE_NORMAL;
otk_clear(oxine->otk);
}
}
int oxine_action_event(int xine_event_type)
{
oxine_t *oxine = oxine_instance;
oxine_event_t ev;
if( !oxine )
return 0;
if( oxine->mode == OXINE_MODE_NORMAL )
return 0;
ev.type = OXINE_EVENT_KEY;
switch( xine_event_type ) {
case XINE_EVENT_INPUT_UP:
ev.key = OXINE_KEY_UP;
otk_send_event(oxine->otk, &ev);
return 1;
case XINE_EVENT_INPUT_DOWN:
ev.key = OXINE_KEY_DOWN;
otk_send_event(oxine->otk, &ev);
return 1;
case XINE_EVENT_INPUT_LEFT:
ev.key = OXINE_KEY_LEFT;
otk_send_event(oxine->otk, &ev);
return 1;
case XINE_EVENT_INPUT_RIGHT:
ev.key = OXINE_KEY_RIGHT;
otk_send_event(oxine->otk, &ev);
return 1;
case XINE_EVENT_INPUT_SELECT:
ev.key = OXINE_KEY_SELECT;
otk_send_event(oxine->otk, &ev);
return 1;
}
return 0;
}
int oxine_mouse_event(int xine_event_type, int x, int y) {
oxine_t *oxine = oxine_instance;
oxine_event_t ev;
if( !oxine )
return 0;
if( oxine->mode == OXINE_MODE_NORMAL )
return 0;
ev.x = x;
ev.y = y;
switch( xine_event_type ) {
case XINE_EVENT_INPUT_MOUSE_MOVE:
ev.type = OXINE_EVENT_MOTION;
return otk_send_event(oxine->otk, &ev);
case XINE_EVENT_INPUT_MOUSE_BUTTON:
ev.type = OXINE_EVENT_BUTTON;
ev.key = OXINE_BUTTON1;
return otk_send_event(oxine->otk, &ev);
}
return 0;
}
void oxine_adapt(void)
{
oxine_t *oxine = oxine_instance;
oxine_event_t ev;
if( !oxine )
return;
ev.type = OXINE_EVENT_FORMAT_CHANGED;
otk_send_event(oxine->otk, &ev);
}
--- NEW FILE: oxine.h ---
/*
* Copyright (C) 2002 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: oxine.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* oxine data structures
*/
#ifndef HAVE_OXINE_H
#define HAVE_OXINE_H
#include <stdlib.h>
#include <sys/types.h>
#include <X11/Xlib.h>
#include <pthread.h>
#include <xine.h>
#include "otk.h"
#include "odk.h"
/* I assume that we can have only an osd window *
* displayed */
#define OXINE_MODE_PLAY_MENU (1)
#define OXINE_MODE_INFO_MENU (2)
#define OXINE_MODE_NORMAL (3)
#define OXINE_MODE_MAINMENU (4)
typedef struct oxine_s oxine_t;
typedef struct oxine_window_s oxine_window_t;
struct oxine_s {
xine_t *xine;
otk_t *otk;
odk_t *odk;
otk_widget_t *main_window;
otk_widget_t *pauseplay;
int mode;
int cd_is_mounted;
int cd_in_use;
/* int need_draw; */
const char *cd_mountpoint;
const char *cd_device;
int mm_sort_type;
void (*main_menu_cb) (void *data);
void (*reentry) (void *data);
void *reentry_data;
char *pos_str;
/*
* stream info blending
*/
char *lines[3];
otk_widget_t *info_window;
int info_window_job;
void (*media_info_close_cb)(void *data);
};
void oxine_init(void);
void oxine_exit(void);
void oxine_menu(void);
int oxine_action_event(int xine_event_type);
int oxine_mouse_event(int xine_event_type, int x, int y);
void oxine_adapt(void);
#endif
--- NEW FILE: utils.c ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: utils.c,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* utilities
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>
#include "list.h"
#include "utils.h"
/*
* multi purpose scheduler
*/
typedef struct {
time_t start_time;
xine_list_t *jobs;
pthread_t scheduler_thread;
pthread_mutex_t jobs_mutex;
pthread_mutex_t job_execution_mutex;
pthread_mutex_t wait_mutex;
pthread_cond_t jobs_reorganize;
int job_id;
int keep_going;
} ox_scheduler_t;
/*
* GLOBAL scheduler instance
*/
static ox_scheduler_t *ox_scheduler = NULL;
typedef struct {
struct timespec ts; /* when to do */
void (*cb)(void *data);
void *data;
int id;
} job_t;
static void *scheduler_thread(void *data) {
job_t *job;
int ret;
void (*cb)(void *data);
void *cb_data;
#ifdef LOG
printf("utils: scheduler thread created\n");
#endif
if (!ox_scheduler) {
pthread_exit(NULL);
return NULL;
}
pthread_mutex_lock(&ox_scheduler->wait_mutex);
while (ox_scheduler->keep_going) {
pthread_mutex_lock(&ox_scheduler->jobs_mutex);
job = xine_list_last_content(ox_scheduler->jobs);
if (!job) { /* no jobs for me */
pthread_mutex_unlock(&ox_scheduler->jobs_mutex);
#ifdef LOG
printf("utils: no jobs in queue\n");
#endif
pthread_cond_wait(&ox_scheduler->jobs_reorganize, &ox_scheduler->wait_mutex);
continue;
} else pthread_mutex_unlock(&ox_scheduler->jobs_mutex);
#ifdef LOG
printf("utils: sleeping until next job\n");
#endif
ret = pthread_cond_timedwait(&ox_scheduler->jobs_reorganize,
&ox_scheduler->wait_mutex, &job->ts);
if (ret == ETIMEDOUT) {
/* lets do a job */
pthread_mutex_lock(&ox_scheduler->job_execution_mutex);
pthread_mutex_lock(&ox_scheduler->jobs_mutex);
job = xine_list_last_content(ox_scheduler->jobs);
cb = NULL;
cb_data = NULL;
if (job) {
#ifdef LOG
printf("utils: executing job %i\n", job->id);
#endif
cb = job->cb;
cb_data = job->data;
}
xine_list_delete_current(ox_scheduler->jobs);
pthread_mutex_unlock(&ox_scheduler->jobs_mutex);
if (cb) cb(cb_data);
pthread_mutex_unlock(&ox_scheduler->job_execution_mutex);
} else {
#ifdef LOG
printf("utils: reorganizing queue\n");
#endif
}
}
pthread_mutex_unlock(&ox_scheduler->wait_mutex);
pthread_exit(NULL);
}
void start_scheduler() {
struct timeval tv;
struct timezone tz;
ox_scheduler = malloc(sizeof(ox_scheduler_t));
gettimeofday(&tv, &tz);
ox_scheduler->start_time = tv.tv_sec;
ox_scheduler->jobs = xine_list_new();
pthread_mutex_init(&ox_scheduler->wait_mutex, NULL);
pthread_mutex_init(&ox_scheduler->jobs_mutex, NULL);
pthread_mutex_init(&ox_scheduler->job_execution_mutex, NULL);
pthread_cond_init(&ox_scheduler->jobs_reorganize, NULL);
ox_scheduler->job_id = 0;
ox_scheduler->keep_going = 1;
if (pthread_create(&ox_scheduler->scheduler_thread, NULL, scheduler_thread, \
ox_scheduler)) { printf("utils: error creating scheduler thread\n");
abort();
}
}
void stop_scheduler() {
job_t *job;
void *ret = NULL;
if (!ox_scheduler) return;
ox_scheduler->keep_going = 0;
pthread_cond_signal(&ox_scheduler->jobs_reorganize);
pthread_join(ox_scheduler->scheduler_thread, ret);
job = xine_list_first_content(ox_scheduler->jobs);
while(job) {
#ifdef LOG
printf("utils: cancelling pending job %i\n", job->id);
#endif
free(job);
job = xine_list_next_content(ox_scheduler->jobs);
}
xine_list_free(ox_scheduler->jobs);
pthread_mutex_destroy(&ox_scheduler->wait_mutex);
pthread_mutex_destroy(&ox_scheduler->jobs_mutex);
pthread_cond_destroy(&ox_scheduler->jobs_reorganize);
free(ox_scheduler);
ox_scheduler = NULL;
}
int schedule_job(int delay, void (*cb)(void *data), void *data) {
struct timeval tv;
struct timezone tz;
job_t *job = malloc(sizeof(job_t));
int msec;
int priority;
if (!ox_scheduler) return -1;
gettimeofday(&tv, &tz);
job->ts.tv_sec = (delay / 1000) + tv.tv_sec;
msec = delay % 1000;
if ((msec + tv.tv_usec/1000)>=1000) job->ts.tv_sec++;
msec = (msec + tv.tv_usec/1000) % 1000;
job->ts.tv_nsec = msec * 1000000;
job->cb = cb;
job->data = data;
job->id = ++ox_scheduler->job_id;
priority = (job->ts.tv_sec - ox_scheduler->start_time) * 1000 + msec;
pthread_mutex_lock(&ox_scheduler->jobs_mutex);
xine_list_append_priority_content(ox_scheduler->jobs, job, priority);
pthread_mutex_unlock(&ox_scheduler->jobs_mutex);
pthread_cond_signal(&ox_scheduler->jobs_reorganize);
return ox_scheduler->job_id;
}
void cancel_job(int job_id) {
job_t *job;
if (!ox_scheduler) return;
pthread_mutex_lock(&ox_scheduler->jobs_mutex);
job = xine_list_first_content(ox_scheduler->jobs);
while(job) {
if (job->id == job_id) break;
job = xine_list_next_content(ox_scheduler->jobs);
}
if (job) {
xine_list_delete_current(ox_scheduler->jobs);
#ifdef LOG
printf("utils: job %i cancelled\n", job->id);
#endif
free(job);
}
pthread_mutex_unlock(&ox_scheduler->jobs_mutex);
pthread_cond_signal(&ox_scheduler->jobs_reorganize);
}
void lock_job_mutex() {
if (!ox_scheduler) return;
pthread_mutex_lock(&ox_scheduler->job_execution_mutex);
}
void unlock_job_mutex() {
if (!ox_scheduler) return;
pthread_mutex_unlock(&ox_scheduler->job_execution_mutex);
}
/*
* heap management
*/
/*
* Heap objects are aligned on sizeof(int) boundaries
*/
#define ALIGNMENT (sizeof(int))
#define DOALIGN(num) (((num)+ALIGNMENT-1)&~(ALIGNMENT-1))
/*
* tag datastructures
*/
typedef struct prefix_tag_s prefix_tag_t;
typedef struct postfix_tag_s postfix_tag_t;
struct prefix_tag_s {
prefix_tag_t *prev; /* previous object in heap */
prefix_tag_t* next; /* next object in heap */
postfix_tag_t* postfix; /* ptr to postfix object */
char* filename; /* filename ptr or NULL */
long line; /* line number or 0 */
size_t size; /* size of allocated block */
void* content; /* _gen_malloc() ptr of object */
char* tag; /* description string or NULL */
};
struct postfix_tag_s {
prefix_tag_t* prefix;
};
/*
* GLOBAL: Points to first object in linked list of heap objects
*/
static prefix_tag_t* heap_head=NULL;
void static AddToLinkedList ( prefix_tag_t* );
void static RemoveFromLinkedList ( prefix_tag_t* );
void static RenderDesc ( prefix_tag_t*, char* );
void *_gen_malloc(size_t wSize, const char* tag, char* lpFile, int nLine) {
prefix_tag_t* prefix;
wSize = DOALIGN(wSize);
prefix=(prefix_tag_t*)malloc(sizeof(prefix_tag_t)+wSize+sizeof(postfix_tag_t));
if (prefix) {
AddToLinkedList( prefix );
prefix->postfix = (postfix_tag_t*)((char*)(prefix+1)+wSize);
prefix->postfix->prefix = prefix;
prefix->filename = lpFile;
prefix->line = nLine;
prefix->content = prefix+1;
prefix->size = wSize;
prefix->tag = NULL;
if (tag) prefix->tag = strdup(tag);
memset( prefix->content, 0, wSize );
}
else {
printf("utils: failed to alloc memory\n");
abort();
}
return(prefix ? prefix+1 : NULL);
}
void *_gen_free(void* content) {
if (ho_verify(content)) {
prefix_tag_t* prefix=(prefix_tag_t*)content-1;
size_t wSize=(char*)(prefix->postfix+1)-(char*)prefix;
RemoveFromLinkedList( prefix );
memset( prefix, 0, wSize );
if (prefix->tag) free(prefix->tag);
free(prefix);
}
return (NULL);
}
void *_gen_strdup(const char* lpS, char* lpFile, int nLine) {
void* lpReturn=NULL;
if (lpS) {
size_t wSize = (size_t)(strlen(lpS)+1);
lpReturn = _gen_malloc( wSize, "strdup'ed string", lpFile, nLine );
if (lpReturn) {
memcpy( lpReturn, lpS, wSize );
}
}
return(lpReturn);
}
void *_gen_realloc(void* lpOld, size_t wSize, char* lpFile, int nLine) {
void* lpNew=NULL;
/*--- Try to realloc ---*/
if (lpOld) {
if (ho_verify(lpOld)) {
prefix_tag_t* prefix=(prefix_tag_t*)lpOld-1;
prefix_tag_t* lpNewPrefix;
prefix_tag_t* lpPre;
/*--- Try to reallocate block ---*/
RemoveFromLinkedList( prefix );
memset( prefix->postfix, 0, sizeof(postfix_tag_t) );
wSize = DOALIGN(wSize);
lpNewPrefix=(prefix_tag_t*)realloc(prefix,
sizeof(prefix_tag_t)+wSize+sizeof(postfix_tag_t));
/*--- Add new (or failed old) back in ---*/
lpPre=(lpNewPrefix?lpNewPrefix:prefix);
AddToLinkedList( lpPre );
lpPre->postfix = (postfix_tag_t*)((char*)(lpPre+1)+wSize);
lpPre->postfix->prefix = lpPre;
lpPre->content = lpPre+1;
lpPre->size = wSize;
/*--- Finish ---*/
lpNew = (lpNewPrefix ? &lpNewPrefix[1] : NULL);
if (!lpNew) {
printf("utils: failed to alloc memory\n");
abort();
}
}
}
/*--- Else try new allocation ---*/
else {
lpNew = _gen_malloc( wSize, NULL, lpFile, nLine );
}
/*--- Return address to object ---*/
return(lpNew);
}
void heapstat(void) {
unsigned long total = 0;
unsigned long chunks = 0;
if (heap_head) {
prefix_tag_t* lpCur=heap_head;
while (ho_verify(&lpCur[1])) {
char buffer[100];
RenderDesc( lpCur, buffer );
/*--- print out buffer ---*/
printf( "heapstat: %s\n", buffer );
total+=lpCur->size;
chunks++;
lpCur = lpCur->next;
if (lpCur==heap_head) {
break;
}
}
if (total)
printf("heapstat: memory usage: %li words in %li chunks\n", total, chunks);
}
}
void static AddToLinkedList(prefix_tag_t* lpAdd) {
/*--- Add before current head of list ---*/
if (heap_head) {
lpAdd->prev = heap_head->prev;
(lpAdd->prev)->next = lpAdd;
lpAdd->next = heap_head;
(lpAdd->next)->prev = lpAdd;
}
/*--- Else first node ---*/
else {
lpAdd->prev = lpAdd;
lpAdd->next = lpAdd;
}
/*--- Make new item head of list ---*/
heap_head = lpAdd;
}
void static RemoveFromLinkedList(prefix_tag_t* lpRemove) {
/*--- Remove from doubly linked list ---*/
(lpRemove->prev)->next = lpRemove->next;
(lpRemove->next)->prev = lpRemove->prev;
/*--- Possibly correct head pointer ---*/
if (lpRemove==heap_head) {
heap_head = ((lpRemove->next==lpRemove) ? NULL :
lpRemove->next);
}
}
int static ho_is_ok(void* content)
{
return ((content) && (!((long)content&(ALIGNMENT-1))));
}
int ho_verify(void *content) {
int bOk=0;
if (content) {
if (ho_is_ok(content)) {
prefix_tag_t* prefix=(prefix_tag_t*)content-1;
if(prefix->content==content) {
if(prefix->postfix->prefix==prefix) {
bOk = 1;
}
}
}
}
return (bOk);
}
void static RenderDesc(prefix_tag_t* prefix, char* lpBuffer) {
if (prefix->content==&prefix[1]) {
sprintf( lpBuffer, "%i words @ 0x%08lx:", prefix->size, (unsigned \
long)prefix->content ); if (prefix->filename) {
sprintf( lpBuffer+strlen(lpBuffer), "%s:%ld ",
prefix->filename, prefix->line );
}
if (prefix->tag) {
sprintf( lpBuffer+strlen(lpBuffer), "%s",
prefix->tag );
}
}
else {
strcpy( lpBuffer, "(bad pointer given)" );
}
}
--- NEW FILE: utils.h ---
/*
* Copyright (C) 2002-2003 Stefan Holst
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id: utils.h,v 1.1 2005/01/31 02:49:48 miguelfreitas Exp $
*
* utilities
*/
#ifndef HAVE_UTILS_H
#define HAVE_UTILS_H
/*
* multi purpose scheduler
*/
void start_scheduler();
void stop_scheduler();
/*
* will execute cb(data) after <delay> ms.
* returns job id.
*/
int schedule_job(int delay, void (*cb)(void *data), void *data);
/*
* cancel pending job width given job id.
*/
void cancel_job(int job_id);
void lock_job_mutex();
void unlock_job_mutex();
/*
* heap management
*/
/* semipublic functions*/
void *_gen_malloc ( size_t, const char * , char *, int );
void *_gen_free ( void * );
void *_gen_realloc ( void *, size_t, char *, int );
void *_gen_strdup ( const char *, char *, int );
/*
* allocs a new heap object of given type
*/
#define ho_new(type) (_gen_malloc(sizeof(type),NULL,__FILE__,__LINE__))
#define ho_new_tagged(type,text) (_gen_malloc(sizeof(type),text,__FILE__,__LINE__))
/*
* resizes a heap object
*/
#define ho_resize(hObj, size) (hObj=_gen_realloc((hObj), \
(size_t)(size),__FILE__,__LINE__))
/*
* frees a heap object
*/
#define ho_free(hObj) (hObj=_gen_free(hObj))
/*
* allocs a new string of given size
*/
#define ho_newstring(wSize) (_gen_malloc((size_t)(wSize),"string",__FILE__,__LINE__))
/*
* like strdup, but returns a valid heap object
*/
#define ho_strdup(lpSrc) (_gen_strdup(lpSrc,__FILE__,__LINE__))
/*
* test wether a heap pointer is valid
*/
int ho_verify(void *ho);
/*
* prints info about all allocated data chunks to stdout
*/
void heapstat();
#if 0
#define _LPV(hObj) *(void*)&hObj
/*--- Array interface macros ---*/
#define NEWARRAY(lpArray, wSize) \
(_LPV(lpArray)=FmNew((SIZET)(sizeof(*(lpArray))*(wSize)), \
NULL,szSRCFILE,__LINE__))
#endif
#endif
-------------------------------------------------------
This SF.Net email is sponsored by: IntelliVIEW -- Interactive Reporting
Tool for open source databases. Create drag-&-drop reports. Save time
by over 75%! Publish reports on the web. Export to DOC, XLS, RTF, etc.
Download a FREE copy at http://www.intelliview.com/go/osdn_nl
_______________________________________________
Xine-cvslog mailing list
Xine-cvslog@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/xine-cvslog
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic