37
47
# include <X11/extensions/Xinerama.h>
57
#define XINE_ENABLE_EXPERIMENTAL_FEATURES
42
#define LOG_MODULENAME "[vdr-sxfe] "
60
#ifndef XINE_ENGINE_INTERNAL
61
# define XINE_ENGINE_INTERNAL
62
# include <xine/xine_internal.h>
63
# undef XINE_ENGINE_INTERNAL
65
# include <xine/xine_internal.h>
67
#include <xine/xineutils.h>
68
#include <xine/input_plugin.h>
69
#include <xine/plugin_catalog.h>
71
#include "xine_input_vdr.h"
45
72
#include "xine_osd_command.h"
46
#include "xine_frontend_internal.h"
74
#include "xine_frontend.h"
75
#include "xine/post.h"
48
77
#ifdef HAVE_DBUS_GLIB_1
49
78
# include "tools/gnome_screensaver.h"
88
117
/* function pointers / base class */
90
119
frontend_t fe; /* generic frontend */
91
fe_t x; /* xine frontend */
122
void (*update_display_size_cb)(frontend_t*);
123
void (*toggle_fullscreen_cb) (frontend_t*);
125
/* from xine_frontend.c */
126
double (*dest_pixel_aspect) (const frontend_t *,
127
double video_pixel_aspect,
128
int video_width, int video_height);
129
void (*frame_output_handler)(void *data,
130
int video_width, int video_height,
131
double video_pixel_aspect,
132
int *dest_x, int *dest_y,
133
int *dest_width, int *dest_height,
134
double *dest_pixel_aspect,
135
int *win_x, int *win_y);
138
fe_keypress_f keypress;
94
140
/* stored original handlers */
95
141
int (*fe_xine_open)(frontend_t *this_gen, const char *mrl);
96
142
int (*fe_xine_play)(frontend_t *this_gen);
147
193
uint8_t gui_hotkeys : 1;
148
194
uint8_t no_x_kbd : 1;
198
xine_stream_t *stream;
199
xine_stream_t *slave_stream;
200
vdr_input_plugin_if_t *input_plugin;
201
xine_video_port_t *video_port;
202
xine_video_port_t *video_port_none;
203
xine_audio_port_t *audio_port;
204
xine_audio_port_t *audio_port_none;
205
xine_event_queue_t *event_queue;
207
post_plugins_t *postplugins;
210
int xine_visual_type;
212
uint16_t pes_buffers;
215
double display_ratio;
217
char *aspect_controller;
218
char *video_port_name;
220
uint16_t video_width, video_height;
221
uint16_t width, height;
226
uint8_t terminate_key_pressed;
227
uint8_t playback_finished;
228
uint8_t slave_playback_finished;
151
235
#ifdef HAVE_XRENDER
186
271
*dest_width = this->width;
187
272
*dest_height = this->height;
189
*dest_pixel_aspect = this->dest_pixel_aspect(this, video_pixel_aspect,
274
*dest_pixel_aspect = this->dest_pixel_aspect((frontend_t*)this, video_pixel_aspect,
190
275
video_width, video_height);
215
300
hint.flags = USSize | USPosition | PPosition | PSize;
216
301
hint.x = this->xinerama_x;
217
302
hint.y = this->xinerama_y;
218
hint.width = this->x.width;
219
hint.height = this->x.height;
303
hint.width = this->width;
304
hint.height = this->height;
220
305
XLockDisplay(this->display);
221
306
XSetNormalHints(this->display, this->window[1], &hint);
222
307
XUnlockDisplay(this->display);
494
579
static void update_screen_size(sxfe_t *this)
496
this->x.width = DisplayWidth(this->display, this->screen);
497
this->x.height = DisplayHeight(this->display, this->screen);
581
this->width = DisplayWidth(this->display, this->screen);
582
this->height = DisplayHeight(this->display, this->screen);
498
583
update_xinerama_info(this);
542
627
xf.matrix[2][0] = 0; xf.matrix[2][1] = 0; xf.matrix[2][2] = XDoubleToFixed(1.0);
543
628
XRenderSetPictureFilter(dpy, src->pic, smooth ? "bilinear" : "nearest", NULL, 0);
544
629
XRenderSetPictureTransform(dpy, src->pic, &xf);
545
x = (int)ceil((double)(x>0?x-1:0) * scale_x);
546
y = (int)ceil((double)(y>0?y-1:0) * scale_y);
630
x = (int)ceil((double)(x?x-1:0) * scale_x);
631
y = (int)ceil((double)(y?y-1:0) * scale_y);
547
632
w = (int)floor((double)(w+2) * scale_x);
548
633
h = (int)floor((double)(h+2) * scale_y);
549
634
XRenderComposite(dpy, PictOpSrc, src->pic, None, dst->pic, x, y, 0, 0, x, y, w, h);
690
774
cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1,
691
775
cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1,
692
776
cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1,
693
(XDouble)this->x.width / (XDouble)this->osd_width,
694
(XDouble)this->x.height / (XDouble)this->osd_height,
777
(XDouble)this->width / (XDouble)this->osd_width,
778
(XDouble)this->height / (XDouble)this->osd_height,
695
779
(cmd->scaling & 2)); // Note: HUD_SCALING_BILINEAR=2
701
784
hud_fill_img_memory(this->hud_img_mem, cmd);
702
785
if(!cmd->scaling) {
717
800
cmd->x + cmd->dirty_area.x1, cmd->y + cmd->dirty_area.y1,
718
801
cmd->dirty_area.x2 - cmd->dirty_area.x1 + 1,
719
802
cmd->dirty_area.y2 - cmd->dirty_area.y1 + 1,
720
(XDouble)this->x.width / (XDouble)this->osd_width,
721
(XDouble)this->x.height / (XDouble)this->osd_height,
803
(XDouble)this->width / (XDouble)this->osd_width,
804
(XDouble)this->height / (XDouble)this->osd_height,
722
805
(cmd->scaling & 2)); // Note: HUD_SCALING_BILINEAR=2
743
826
XSetForeground(this->display, this->gc, 0x00000000);
744
827
XFillRectangle(this->display, this->hud_window, this->gc,
745
0, 0, this->x.width, this->x.height);
828
0, 0, this->width, this->height);
746
829
XFillRectangle(this->display, this->surf_img->draw, this->gc,
747
830
0, 0, this->osd_width+2, this->osd_height+2);
748
831
XFlush(this->display);
794
877
attributes.backing_store = Always;
796
879
this->hud_window = XCreateWindow(this->display, DefaultRootWindow(this->display),
797
this->x.xpos, this->x.ypos,
798
this->x.width, this->x.height,
880
this->xpos, this->ypos,
881
this->width, this->height,
799
882
0, 32, InputOutput, this->hud_vis,
800
883
CWBackPixel | CWBorderPixel |
801
884
CWOverrideRedirect | CWColormap,
811
894
XStoreName(this->display, this->hud_window, "HUD");
812
895
this->gc = XCreateGC(this->display, this->hud_window, 0, NULL);
815
897
if(this->completion_event != -1) {
816
898
this->hud_img = XShmCreateImage(this->display, this->hud_vis, 32, ZPixmap, NULL, &(this->hud_shminfo),
817
899
HUD_MAX_WIDTH, HUD_MAX_HEIGHT);
1062
1139
/* create and display our video window */
1063
1140
this->window[0] = XCreateSimpleWindow (this->display,
1064
1141
DefaultRootWindow(this->display),
1065
this->x.xpos, this->x.ypos,
1066
this->x.width, this->x.height,
1142
this->xpos, this->ypos,
1143
this->width, this->height,
1068
1145
this->window[1] = XCreateSimpleWindow(this->display, XDefaultRootWindow(this->display),
1069
1146
this->xinerama_x, this->xinerama_y,
1070
this->x.width, this->x.height,
1147
this->width, this->height,
1073
1150
/* full-screen window */
1112
1189
this->fe.fe_display_close(this_gen);
1115
this->x.keypress = keyfunc;
1116
this->x.keypress("XKeySym", ""); /* triggers learning mode */
1192
this->keypress = keyfunc;
1193
this->keypress("XKeySym", ""); /* triggers learning mode */
1119
1196
LOGDBG("sxfe_display_open(width=%d, height=%d, fullscreen=%d, display=%s)",
1133
this->x.xpos = xpos;
1134
this->x.ypos = ypos;
1135
this->x.width = width;
1136
this->x.height = height;
1137
this->x.aspect = aspect;
1138
/*this->x.cropping = 0;*/
1139
this->x.overscan = 0;
1140
this->x.scale_video = scale_video;
1141
this->x.field_order = field_order ? 1 : 0;
1142
this->x.aspect_controller = aspect_controller ? strdup(aspect_controller) : NULL;
1212
this->width = width;
1213
this->height = height;
1214
this->aspect = aspect;
1217
this->scale_video = scale_video;
1218
this->field_order = field_order ? 1 : 0;
1219
this->aspect_controller = aspect_controller ? strdup(aspect_controller) : NULL;
1221
this->origxpos = xpos;
1222
this->origypos = ypos;
1146
1223
this->origwidth = width>0 ? width : OSD_DEF_WIDTH;
1147
1224
this->origheight = height>0 ? height : OSD_DEF_HEIGHT;
1154
1231
this->fullscreen = fullscreen;
1155
1232
/*this->vmode_switch = modeswitch;*/
1156
1233
this->fullscreen_state_forced = 0;
1157
/*this->modeline = strdup(modeline ?: "");*/
1234
/*strn0cpy(this->modeline, modeline ? : "", sizeof(this->modeline));*/
1158
1235
this->window_id = window_id;
1160
1237
this->xinerama_screen = -1;
1197
1272
/* Output to existing window ? (embedded to another app) */
1198
1273
if(this->window_id > 0) {
1199
LOGMSG("sxfe_display_open(): Using X11 window %d for output", this->window_id);
1274
LOGMSG("sxfe_diaplay_open(): Using X11 window %d for output", this->window_id);
1200
1275
this->window[0] = this->window[1] = (Window)this->window_id;
1201
1276
XUnmapWindow(this->display, this->window[0]);
1220
1295
/* Map current window */
1221
1296
XMapRaised (this->display, this->window[this->fullscreen ? 1 : 0]);
1222
XMoveWindow(this->display, this->window[0], this->x.xpos, this->x.ypos);
1297
XMoveWindow(this->display, this->window[0], this->xpos, this->ypos);
1224
1299
/* determine display aspect ratio */
1225
this->x.display_ratio = detect_display_ratio(this->display, this->screen);
1300
this->display_ratio = detect_display_ratio(this->display, this->screen);
1227
1302
/* we want to get notified if user closes the window */
1228
1303
XSetWMProtocols(this->display, this->window[this->fullscreen ? 1 : 0], &(this->xa_WM_DELETE_WINDOW), 1);
1243
1318
gnome_screensaver_control(0);
1246
/* setup xine visual type */
1247
this->x.xine_visual_type = XINE_VISUAL_TYPE_X11;
1248
this->x.vis_x11.display = this->display;
1249
this->x.vis_x11.screen = this->screen;
1250
this->x.vis_x11.d = this->window[this->fullscreen ? 1 : 0];
1251
this->x.vis_x11.dest_size_cb = sxfe_dest_size_cb;
1252
this->x.vis_x11.frame_output_cb = this->x.frame_output_handler;
1253
this->x.vis_x11.user_data = this;
1321
this->xine_visual_type = XINE_VISUAL_TYPE_X11;
1322
this->vis.display = this->display;
1323
this->vis.screen = this->screen;
1324
this->vis.d = this->window[this->fullscreen ? 1 : 0];
1325
this->vis.dest_size_cb = sxfe_dest_size_cb;
1326
this->vis.frame_output_cb = fe_frame_output_cb;
1327
this->vis.user_data = this;
1255
1329
set_fullscreen_props(this);
1279
1353
if(this->fullscreen_state_forced)
1280
1354
fullscreen = this->fullscreen ? 1 : 0;
1282
if(!fullscreen && (this->x.width != width || this->x.height != height)) {
1283
this->x.width = width;
1284
this->x.height = height;
1356
if (xpos < 0) xpos = this->xpos;
1357
if (ypos < 0) ypos = this->ypos;
1360
( this->width != width || this->height != height ||
1361
this->xpos != xpos || this->ypos != ypos)) {
1364
this->width = width;
1365
this->height = height;
1286
1367
XLockDisplay(this->display);
1287
XResizeWindow(this->display, this->window[0], this->x.width, this->x.height);
1368
XResizeWindow(this->display, this->window[0], this->width, this->height);
1369
XMoveWindow(this->display, this->window[0], this->xpos, this->ypos);
1288
1370
XUnlockDisplay(this->display);
1289
1371
if(!fullscreen && !this->fullscreen)
1290
xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
1372
xine_port_send_gui_data(this->video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
1291
1373
(void*) this->window[0]);
1306
1388
set_above(this, this->stay_above);
1307
1389
XMapRaised(this->display, this->window[this->fullscreen ? 1 : 0]);
1308
1390
if(!fullscreen) {
1309
XResizeWindow(this->display, this->window[0], this->x.width, this->x.height);
1310
XMoveWindow(this->display, this->window[0], this->x.xpos, this->x.ypos);
1391
XResizeWindow(this->display, this->window[0], this->width, this->height);
1392
XMoveWindow(this->display, this->window[0], this->xpos, this->ypos);
1311
1393
LOGDBG("sxfe_display_config: XMoveWindow called with x=%d and y=%d",
1312
this->x.xpos, this->x.ypos);
1394
this->xpos, this->ypos);
1313
1395
this->check_move = 1;
1314
1396
set_above(this, this->stay_above);
1316
1398
set_fullscreen_props(this);
1317
XResizeWindow(this->display, this->window[1], this->x.width, this->x.height);
1399
XResizeWindow(this->display, this->window[1], this->width, this->height);
1318
1400
XMoveWindow(this->display, this->window[1], this->xinerama_x, this->xinerama_y);
1320
1402
XSync(this->display, False);
1321
1403
if(XTranslateCoordinates(this->display, this->window[this->fullscreen ? 1 : 0],
1322
1404
DefaultRootWindow(this->display),
1323
1405
0, 0, &tmp_x, &tmp_y, &tmp_win)) {
1324
this->x.xpos = tmp_x;
1325
this->x.ypos = tmp_y;
1327
1409
XUnlockDisplay(this->display);
1328
xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
1410
xine_port_send_gui_data(this->video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
1329
1411
(void*) this->window[this->fullscreen ? 1 : 0]);
1333
1415
if(!modeswitch && strcmp(modeline, this->modeline)) {
1334
free(this->modeline);
1335
this->modeline = strdup(modeline ?: "");
1416
strn0cpy(this->modeline, modeline, sizeof(this->modeline));
1336
1417
/* #warning TODO - switch vmode */
1340
1421
/*this->vmode_switch = modeswitch;*/
1341
this->x.aspect = aspect;
1342
this->x.scale_video = scale_video;
1343
this->x.field_order = field_order ? 1 : 0;
1422
this->aspect = aspect;
1423
this->scale_video = scale_video;
1424
this->field_order = field_order ? 1 : 0;
1348
static void sxfe_toggle_fullscreen(fe_t *this_gen)
1429
static void sxfe_toggle_fullscreen(frontend_t *this_gen)
1350
1431
sxfe_t *this = (sxfe_t*)this_gen;
1353
1434
this->fullscreen_state_forced = 0;
1355
1436
if(!this->fullscreen) {
1356
this->origwidth = this->x.width;
1357
this->origheight = this->x.height;
1358
this->origxpos = this->x.xpos;
1359
this->origypos = this->x.ypos;
1437
this->origwidth = this->width;
1438
this->origheight = this->height;
1439
this->origxpos = this->xpos;
1440
this->origypos = this->ypos;
1361
this->x.xpos = this->origxpos;
1362
this->x.ypos = this->origypos;
1442
this->xpos = this->origxpos;
1443
this->ypos = this->origypos;
1365
1446
this->fe.fe_display_config((frontend_t*)this, -1, -1, this->origwidth, this->origheight,
1366
1447
this->fullscreen ? 0 : 1,
1367
1448
0/*this->vmode_switch*/, NULL/*this->modeline*/,
1368
this->x.aspect, this->x.scale_video, this->x.field_order);
1449
this->aspect, this->scale_video, this->field_order);
1370
1451
this->fullscreen_state_forced = !force;
1427
1508
fe_event = "TOGGLE_DEINTERLACE";
1429
1510
case XK_Escape:
1430
if (!this->x.keypress) /* ESC exits only in remote mode */
1511
if (!this->keypress) { /* ESC exits only in remote mode */
1431
1512
fe_event = "QUIT";
1436
this->x.fe.send_event((frontend_t*)this, fe_event);
1518
this->fe.send_event((frontend_t*)this, fe_event);
1437
1519
else if (!this->no_x_kbd)
1438
this->x.fe.send_input_event((frontend_t*)this, "XKeySym", XKeysymToString(ks), 0, 0);
1520
this->fe.send_input_event((frontend_t*)this, "XKeySym", XKeysymToString(ks), 0, 0);
1451
1533
hud_osd_resize(this, cev->window, cev->width, cev->height);
1454
if (this->x.width != cev->width || this->x.height != cev->height) {
1536
/* update video window size */
1537
if (this->width != cev->width || this->height != cev->height) {
1538
this->width = cev->width;
1539
this->height = cev->height;
1541
/* inform VDR about new size */
1456
snprintf(str, sizeof(str), "INFO WINDOW %dx%d", this->x.width, this->x.height);
1457
this->x.fe.send_event((frontend_t*)this, str);
1543
snprintf(str, sizeof(str), "INFO WINDOW %dx%d", this->width, this->height);
1544
this->fe.send_event((frontend_t*)this, str);
1460
/* update video window size */
1461
this->x.width = cev->width;
1462
this->x.height = cev->height;
1464
1547
if(this->window[0] == cev->window && this->check_move) {
1465
1548
LOGDBG("ConfigureNotify reveived with x=%d, y=%d, check_move=%d",
1466
1549
cev->x, cev->y, this->check_move);
1467
1550
this->check_move = 0;
1468
if(this->x.xpos != cev->x && this->x.ypos != cev->y) {
1551
if(this->xpos != cev->x && this->ypos != cev->y) {
1469
1552
XLockDisplay (this->display);
1470
1553
XMoveWindow(this->display, this->window[0], cev->x, cev->y);
1471
1554
XUnlockDisplay (this->display);
1480
1563
if(XTranslateCoordinates(this->display, cev->window,
1481
1564
DefaultRootWindow(this->display),
1482
1565
0, 0, &tmp_x, &tmp_y, &tmp_win)) {
1483
this->x.xpos = tmp_x;
1484
this->x.ypos = tmp_y;
1486
1569
XUnlockDisplay(this->display);
1489
1572
if(!this->fullscreen) {
1490
1573
/* update video window position */
1491
this->x.xpos = cev->x;
1492
this->x.ypos = cev->y;
1574
this->xpos = cev->x;
1575
this->ypos = cev->y;
1515
1598
DefaultRootWindow(this->display),
1516
1599
0, 0, &xpos, &ypos, &tmp_win);
1518
this->x.xpos = (xpos += mev->x_root - this->dragging_x);
1519
this->x.ypos = (ypos += mev->y_root - this->dragging_y);
1601
this->xpos = (xpos += mev->x_root - this->dragging_x);
1602
this->ypos = (ypos += mev->y_root - this->dragging_y);
1520
1603
this->dragging_x = mev->x_root;
1521
1604
this->dragging_y = mev->y_root;
1649
1732
/* we got a window deletion message from out window manager.*/
1650
1733
LOGDBG("ClientMessage: WM_DELETE_WINDOW");
1652
this->x.fe.send_event((frontend_t*)this, "QUIT");
1735
this->fe.send_event((frontend_t*)this, "QUIT");
1658
1741
if (event.type == this->completion_event)
1659
xine_port_send_gui_data (this->x.video_port, XINE_GUI_SEND_COMPLETION_EVENT, &event);
1742
xine_port_send_gui_data (this->video_port, XINE_GUI_SEND_COMPLETION_EVENT, &event);
1662
return !this->x.fe.xine_is_finished((frontend_t*)this, 0);
1745
return !this->fe.xine_is_finished((frontend_t*)this, 0);
1665
1748
static void sxfe_display_close(frontend_t *this_gen)
1740
1823
int result = this->fe_xine_play(this_gen);
1742
1825
#ifdef HAVE_XRENDER
1743
if (result && this->x.input_plugin && this->hud) {
1826
if (result && this->input_plugin && this->hud) {
1744
1827
LOGDBG("sxfe_xine_play: Enabling HUD OSD");
1745
this->x.input_plugin->f.fe_handle = this_gen;
1746
this->x.input_plugin->f.intercept_osd = hud_osd_command;
1828
this->input_plugin->f.fe_handle = this_gen;
1829
this->input_plugin->f.intercept_osd = hud_osd_command;
1748
1831
#endif /* HAVE_XRENDER */