38
38
#include "globals.h"
39
39
#include "zvideo.h"
41
/* This code clips DMA overlay into video memory against X window
42
boundaries. Which is really the job of the X server, but without
43
XVideo extension we have little choice. If XVideo is available
44
it merely adjusts the overlay to fill the video window. Actually
45
all this should be integrated into zvideo.c. */
40
#include "v4linterface.h"
43
/* This code implements video overlay. It supports three methods:
45
We can ask a kernel device to continuously store video images in
46
some arbitrary memory area, i.e. video memory, with clipping
47
rectangles. Of course the device won't know about windows
48
"obscuring" the overlay, so we can either disable X11 completely,
49
or ask the X server to send events before opening or moving
50
windows, and after closing windows. Alas, there are no "before"
51
events, we have to disable the overlay after the fact, redraw the
52
areas we shouldn't have overlaid, and restart the overlay at the
53
new coordinates and with new clipping rectangles.
55
Second we can ask a kernel device which can somehow overlay a VGA
56
signal to replace all pixels of a specific color by video image
57
pixels. Here we only have to reprogram the device when the size or
58
position of the target window which shall display the video
61
An XVideo driver handles clipping or chromakeying automatically,
62
we only have to pick a target window and adjust the overlay size
63
and position relative to the window.
48
+ Special mode for devices without clipping. Hint: think twice.
67
+ Special mode for devices without clipping.
68
Attn: disable OSD and subtitles.
49
69
+ Matte option (clip out WSS, GCR).
50
70
+ Source rectangle, if supported by hardware (e.g. zoom function).
71
+ Perhaps integrate this code into zvideo.c.
53
74
#ifndef OVERLAY_LOG_FP
54
#define OVERLAY_LOG_FP 0
75
# define OVERLAY_LOG_FP 0
57
77
#ifndef OVERLAY_EVENT_LOG_FP
58
#define OVERLAY_EVENT_LOG_FP 0
78
# define OVERLAY_EVENT_LOG_FP 0
61
80
#ifndef OVERLAY_DUMP_CLIPS
62
#define OVERLAY_DUMP_CLIPS 0
81
# define OVERLAY_DUMP_CLIPS 0
65
83
#ifndef OVERLAY_CHROMA_TEST
66
#define OVERLAY_CHROMA_TEST 0
84
# define OVERLAY_CHROMA_TEST 0
86
#ifndef OVERLAY_METHOD_FAILURE_TEST
87
# define OVERLAY_METHOD_FAILURE_TEST 0
89
#ifndef OVERLAY_COLORMAP_FAILURE_TEST
90
# define OVERLAY_COLORMAP_FAILURE_TEST 0
69
93
#define CLEAR_TIMEOUT 50 /* ms for the clear window timeout */
102
/** XVideo or kernel device. */
103
tveng_device_info * info;
105
/** The screen containing video_window (Xinerama). */
106
const tv_screen * screen;
108
/** The root window on the current display. */
72
109
GdkWindow * root_window;
74
GtkWidget * main_window; /* top level parent of video_window */
75
GtkWidget * video_window; /* displays the overlay */
77
const tv_screen * screen; /* screen containing video_window
80
gint mw_x; /* last known main_window position */
81
gint mw_y; /* (root relative) */
83
gint vw_x; /* last known video_window position */
84
gint vw_y; /* (main_window relative) */
86
guint vw_width; /* last known video_window size */
111
/** The Zapping main window, top level parent of video_window. */
112
GtkWidget * main_window;
114
/** The child window which actually displays the overlay. */
115
GtkWidget * video_window;
117
/** Last known position of the main_window, relative to root_window. */
121
/** Last known position of the video_window, relative to main_window. */
125
/** Last known size of the video_window. */
89
gboolean needs_cleaning; /* FALSE for XVideo and chromakey */
91
tveng_device_info * info; /* V4L device */
95
GdkVisibilityState visibility; /* of video_window */
97
tv_window window; /* overlay rectangle */
129
/** The overlay rectangle, relative to root_window. */
130
tv_window overlay_rect;
132
GdkColormap * colormap;
133
GdkColor chroma_key_color;
134
guint chroma_key_color_cnxn_id;
136
GdkEventMask old_root_events;
137
GdkEventMask old_main_events;
138
GdkEventMask old_video_events;
141
enum overlay_mode overlay_mode;
143
/** Additional data for overlay_mode CLIP_OVERLAY. */
145
/** Last known visibility of the video_window. */
146
GdkVisibilityState visibility;
149
* Regions obscuring the overlay_rect,
150
* relative to overlay_rect position.
99
152
tv_clip_vector cur_vector;
100
153
tv_clip_vector tmp_vector;
101
tv_clip_vector set_vector;
103
155
gboolean clean_screen;
104
156
gboolean geometry_changed;
106
158
guint timeout_id;
161
static struct context tv_info;
163
#define DEVICE_USES_XVIDEO(c) \
164
(!OVERLAY_METHOD_FAILURE_TEST \
165
&& (0 != (tv_get_caps ((c)->info)->flags & TVENG_CAPS_XVIDEO)))
167
#define DEVICE_SUPPORTS_CHROMA_KEYING(c) \
168
(!OVERLAY_METHOD_FAILURE_TEST \
169
&& (OVERLAY_CHROMA_TEST \
170
|| (0 != (tv_get_caps ((c)->info)->flags & TVENG_CAPS_CHROMAKEY))))
172
#define DEVICE_SUPPORTS_CLIPPING(c) \
173
(!OVERLAY_METHOD_FAILURE_TEST \
174
&& (0 != (tv_get_caps ((c)->info)->flags & TVENG_CAPS_CLIPPING)))
109
176
static __inline__ tv_bool
110
177
tv_window_equal (const tv_window * window1,
236
expose_screen (struct context * c)
170
tv_info.clean_screen = FALSE;
172
x11_force_expose ((gint) tv_info.screen->x,
173
(gint) tv_info.screen->y,
174
tv_info.screen->width,
175
tv_info.screen->height);
240
c->clean_screen = FALSE;
244
x11_force_expose ((gint) s->x,
251
select_screen (struct context * c)
181
if (tv_set_overlay_window_clipvec (tv_info.info,
183
&tv_info.cur_vector))
255
s = tv_screen_list_find (screens,
259
(guint) c->vw_height);
185
tv_clip_vector_set (&tv_info.set_vector, &tv_info.cur_vector);
262
/* No pixel of the video_window on any screen. */
265
c->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
273
/* Moved to another Xinerama screen. */
277
return tv_set_overlay_buffer (c->info,
193
obscured_timeout (gpointer user_data _unused_)
284
obscured_timeout (gpointer user_data)
286
struct context *c = user_data;
195
287
const tv_window *window;
289
/* The window changed from fully or partially visible
290
to fully obscured. */
292
g_assert (CLIP_OVERLAY == c->overlay_mode);
197
294
if (OVERLAY_LOG_FP)
198
295
fprintf (OVERLAY_LOG_FP, "obscured_timeout\n");
200
/* Changed from partially visible or unobscured to fully obscured. */
202
window = tv_cur_overlay_window (tv_info.info);
204
if (tv_info.clean_screen)
297
window = tv_cur_overlay_window (c->info);
207
x11_force_expose (window->x,
212
tv_clip_vector_clear (&tv_info.cur_vector);
305
x11_force_expose (window->x,
311
tv_clip_vector_clear (&c->cur_vector);
213
313
/* XXX error ignored */
214
tv_clip_vector_add_clip_xy (&tv_info.cur_vector,
215
0, 0, window->width, window->height);
217
tv_info.geometry_changed = TRUE;
219
tv_info.timeout_id = NO_SOURCE_ID;
314
tv_clip_vector_add_clip_xy (&c->cur_vector,
316
window->width, window->height);
318
c->geometry_changed = TRUE;
320
c->timeout_id = NO_SOURCE_ID;
220
322
return FALSE; /* remove timeout */
224
visible_timeout (gpointer user_data _unused_)
326
visible_timeout (gpointer user_data)
328
struct context *c = user_data;
330
/* The Window changed from fully or partially obscured to
331
unobscured (cleaning the clip vector is not enough, we must
332
still clip against the video_window bounds).
334
Or from fully obscured or unobscured to partially obscured.
336
Or the clip vector may have changed while the window is
337
partially obscured. */
339
g_assert (CLIP_OVERLAY == c->overlay_mode);
226
341
if (OVERLAY_LOG_FP)
227
342
fprintf (OVERLAY_LOG_FP, "visible_timeout\n");
230
a) fully obscured or partially visible to unobscured
231
(cleaning the clip vector is not enough, we must
232
still clip against the video_window bounds)
233
b) fully obscured or unobscured to partially visible
234
c) possible clip vector change while partially obscured
238
get_clips (&tv_info.tmp_vector);
240
if (!tv_clip_vector_equal (&tv_info.cur_vector,
241
&tv_info.tmp_vector))
344
/* XXX error ignored */
345
get_clips (c, &c->tmp_vector);
347
if (!tv_clip_vector_equal (&c->cur_vector, &c->tmp_vector))
243
349
/* Delay until the situation stabilizes. */
245
351
if (OVERLAY_LOG_FP)
246
352
fprintf (OVERLAY_LOG_FP, "visible_timeout: delay\n");
248
SWAP (tv_info.cur_vector, tv_info.tmp_vector);
354
SWAP (c->cur_vector, c->tmp_vector);
250
tv_info.geometry_changed = TRUE;
356
c->geometry_changed = TRUE;
252
358
return TRUE; /* call again */
361
SWAP (c->cur_vector, c->tmp_vector);
255
363
/* Resume overlay. */
257
if (tv_info.geometry_changed)
365
if (c->geometry_changed)
260
367
guint retry_count;
262
tv_info.geometry_changed = FALSE;
369
c->geometry_changed = FALSE;
264
371
if (OVERLAY_LOG_FP)
265
372
fprintf (OVERLAY_LOG_FP, "visible_timeout: geometry change\n");
267
xs = tv_screen_list_find (screens,
268
tv_info.mw_x + tv_info.vw_x,
269
tv_info.mw_y + tv_info.vw_y,
270
(guint) tv_info.vw_width,
271
(guint) tv_info.vw_height);
275
if (tv_info.screen != xs)
277
/* Moved to other screen (Xinerama). */
280
if (!z_set_overlay_buffer (tv_info.info,
282
tv_info.video_window->window))
283
goto finish; /* XXX */
286
374
/* Other windows may have received expose events before we
287
375
were able to turn off the overlay. Resend expose
288
376
events for those regions which should be clean now. */
289
if (tv_info.clean_screen)
292
expose_window_clip_vector (tv_cur_overlay_window (tv_info.info),
293
&tv_info.set_vector);
380
expose_window_clip_vector (tv_cur_overlay_window (c->info),
381
tv_cur_overlay_clipvec (c->info));
383
if (!select_screen (c))
384
goto finish; /* XXX */
295
386
/* Desired overlay bounds */
297
tv_info.window.x = tv_info.mw_x + tv_info.vw_x;
298
tv_info.window.y = tv_info.mw_y + tv_info.vw_y;
299
tv_info.window.width = tv_info.vw_width;
300
tv_info.window.height = tv_info.vw_height;
388
c->overlay_rect.x = c->mw_x + c->vw_x;
389
c->overlay_rect.y = c->mw_y + c->vw_y;
390
c->overlay_rect.width = c->vw_width;
391
c->overlay_rect.height = c->vw_height;
393
if (NULL == c->screen)
395
/* video_window is outside all screens. */
306
405
const tv_window *w;
308
if (retry_count-- == 0)
309
goto finish; /* XXX */
314
w = tv_cur_overlay_window (tv_info.info);
316
if (tv_window_equal (&tv_info.window, w))
406
unsigned int old_size;
408
if (0 == retry_count--)
409
goto finish; /* XXX */
413
swin = c->overlay_rect;
417
w = tv_set_overlay_window_clipvec (c->info, &swin, &c->cur_vector);
419
goto finish; /* XXX */
421
if (tv_window_equal (&swin, w))
319
424
/* The driver modified the overlay bounds (alignment, limits),
320
425
we must update the clips. */
322
tv_info.window.x = w->x;
323
tv_info.window.y = w->y;
324
tv_info.window.width = w->width;
325
tv_info.window.height = w->height;
328
get_clips (&tv_info.tmp_vector);
427
old_size = c->cur_vector.size;
429
c->overlay_rect = *w;
430
c->overlay_rect.x += s->x;
431
c->overlay_rect.y += s->y;
433
/* XXX error ignored */
434
get_clips (c, &c->cur_vector);
436
if (0 == (old_size | c->cur_vector.size))
331
else if (tv_info.clean_screen)
440
else if (c->clean_screen)
336
if (!OVERLAY_CHROMA_TEST)
338
/* XXX error ignored */
339
tv_enable_overlay (tv_info.info, TRUE);
445
/* XXX error ignored */
446
tv_enable_overlay (c->info, TRUE);
343
tv_info.timeout_id = NO_SOURCE_ID;
449
c->timeout_id = NO_SOURCE_ID;
344
451
return FALSE; /* remove timeout */
455
stop_timeout (struct context * c)
350
if (tv_info.timeout_id > 0)
351
g_source_remove (tv_info.timeout_id);
457
if (c->timeout_id > 0)
458
g_source_remove (c->timeout_id);
353
tv_info.timeout_id = NO_SOURCE_ID;
460
c->timeout_id = NO_SOURCE_ID;
357
restart_timeout (void)
464
restart_timeout (struct context * c)
466
g_assert (CLIP_OVERLAY == c->overlay_mode);
359
468
if (OVERLAY_LOG_FP)
360
469
fprintf (OVERLAY_LOG_FP, "restart_timeout\n");
362
tv_enable_overlay (tv_info.info, FALSE);
366
if (tv_info.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
368
g_timeout_add (CLEAR_TIMEOUT,
369
(GSourceFunc) obscured_timeout, &tv_info);
471
tv_enable_overlay (c->info, FALSE);
475
if (GDK_VISIBILITY_FULLY_OBSCURED == c->visibility)
477
c->timeout_id = g_timeout_add (CLEAR_TIMEOUT,
478
(GSourceFunc) obscured_timeout,
372
g_timeout_add (CLEAR_TIMEOUT,
373
(GSourceFunc) visible_timeout, &tv_info);
376
static __inline__ void
379
tv_info.geometry_changed = TRUE;
380
tv_info.clean_screen = TRUE; /* see root_filter() below */
382
if (tv_info.visibility != GDK_VISIBILITY_FULLY_OBSCURED)
387
on_video_window_event (GtkWidget * widget _unused_,
483
c->timeout_id = g_timeout_add (CLEAR_TIMEOUT,
484
(GSourceFunc) visible_timeout,
490
chroma_key_rgb (GdkColor * color)
492
return ((color->red >> 8) |
493
(color->green & 0xFF00) |
494
((color->blue & 0xFF00) << 8));
498
reconfigure (struct context * c)
500
switch (c->overlay_mode)
506
c->geometry_changed = TRUE;
507
c->clean_screen = TRUE; /* see root_filter() */
509
if (GDK_VISIBILITY_FULLY_OBSCURED != c->visibility)
514
case CHROMA_KEY_OVERLAY:
515
/* Implied by tv_set_overlay_window_chromakey():
516
tv_enable_overlay (c->info, FALSE); */
518
/* Restore background color (chroma key). XXX the X server
519
should do this automatically, did we we disabled that
520
somewhere to avoid flicker in capture overlay_mode? */
521
gdk_window_clear_area (c->video_window->window,
526
if (!select_screen (c))
529
c->overlay_rect.x = c->mw_x + c->vw_x;
530
c->overlay_rect.y = c->mw_y + c->vw_y;
531
c->overlay_rect.width = c->vw_width;
532
c->overlay_rect.height = c->vw_height;
535
fprintf (stderr, "reconfigure overlay_rect: %ux%u%+d%+d\n",
536
c->overlay_rect.width,
537
c->overlay_rect.height,
541
if (NULL == c->screen)
543
/* video_window is outside all screens. */
545
tv_enable_overlay (c->info, FALSE);
550
c->visibility = GDK_VISIBILITY_PARTIAL; /* or full */
552
if (OVERLAY_CHROMA_TEST)
554
/* Show me the chroma key color. */
555
c->overlay_rect.width /= 2;
558
swin = c->overlay_rect;
559
swin.x -= c->screen->x;
560
swin.y -= c->screen->y;
562
rgb = chroma_key_rgb (&c->chroma_key_color);
564
if (NULL == tv_set_overlay_window_chromakey (c->info, &swin, rgb))
567
if (!tv_enable_overlay (c->info, TRUE))
573
/* XVideo overlay is automatically positioned relative to
574
the video_window origin, we only have to adjust the
577
tv_enable_overlay (c->info, FALSE);
581
/* Restore background color (chroma key). */
582
gdk_window_clear_area (c->video_window->window,
588
/* XXX set overlay rectangle here, currently the XVideo
589
interface fills the entire window when overlay is enabled. */
591
/* XXX off/on is inefficient, XVideo drivers
592
do that automatically. */
593
if (!tv_enable_overlay (c->info, TRUE))
603
on_video_window_event (GtkWidget * widget,
388
604
GdkEvent * event,
389
gpointer user_data _unused_)
607
struct context *c = user_data;
609
g_assert (widget == c->video_window);
391
611
if (OVERLAY_EVENT_LOG_FP)
392
fprintf (OVERLAY_EVENT_LOG_FP, "on_video_window_event: GDK_%s\n",
612
fprintf (OVERLAY_EVENT_LOG_FP,
613
"on_video_window_event: GDK_%s\n",
393
614
z_gdk_event_name (event));
395
616
switch (event->type)
581
851
/* The osd pieces have changed, avoid flicker if not needed. */
583
on_osd_model_changed (ZModel * osd_model _unused_,
584
gpointer ignored _unused_)
853
on_osd_model_changed (ZModel * osd_model,
586
if (tv_info.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
589
tv_info.visibility = GDK_VISIBILITY_PARTIAL;
856
struct context *c = user_data;
858
osd_model = osd_model;
860
if (CLIP_OVERLAY == c->overlay_mode
861
&& GDK_VISIBILITY_FULLY_OBSCURED != c->visibility)
863
c->visibility = GDK_VISIBILITY_PARTIAL;
869
terminate (struct context * c)
598
tv_enable_overlay (tv_info.info, FALSE);
600
if (tv_info.needs_cleaning)
873
tv_enable_overlay (c->info, FALSE);
875
if (CLIP_OVERLAY == c->overlay_mode)
602
877
usleep (CLEAR_TIMEOUT * 1000);
604
if (tv_info.clean_screen)
607
expose_window_clip_vector (tv_cur_overlay_window (tv_info.info),
608
&tv_info.set_vector);
882
expose_window_clip_vector (tv_cur_overlay_window (c->info),
883
tv_cur_overlay_clipvec (c->info));
613
on_main_window_delete_event (GtkWidget * widget _unused_,
614
GdkEvent * event _unused_,
615
gpointer user_data _unused_)
888
on_main_window_delete_event (GtkWidget * widget,
892
struct context *c = user_data;
619
899
return FALSE; /* pass on */
903
event_function (GtkWidget * widget,
908
event_signal_disconnect (struct context * c,
910
event_function * callback,
911
GdkEventMask old_events)
913
if (NULL != callback)
914
g_signal_handlers_disconnect_matched (G_OBJECT (widget),
915
(G_SIGNAL_MATCH_FUNC |
916
G_SIGNAL_MATCH_DATA),
920
G_CALLBACK (callback),
923
gdk_window_set_events (widget->window, old_events);
623
927
stop_overlay (void)
625
g_assert (tv_info.main_window != NULL);
628
z_video_set_max_size (Z_VIDEO (tv_info.video_window), 16384, 16384);
630
g_signal_handlers_disconnect_matched
631
(G_OBJECT (tv_info.main_window),
632
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
633
0, 0, NULL, G_CALLBACK (on_main_window_delete_event), NULL);
635
g_signal_handlers_disconnect_matched
636
(G_OBJECT (tv_info.video_window),
637
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
638
0, 0, NULL, G_CALLBACK (on_video_window_event), NULL);
640
if (tv_info.needs_cleaning)
929
struct context *c = &tv_info;
931
g_assert (c->main_window != NULL);
933
g_signal_handlers_disconnect_matched
935
(G_SIGNAL_MATCH_FUNC |
936
G_SIGNAL_MATCH_DATA),
940
G_CALLBACK (on_main_window_delete_event),
943
switch (c->overlay_mode)
642
gdk_window_remove_filter (tv_info.root_window, root_filter, NULL);
946
gdk_window_set_events (c->root_window,
644
g_signal_handlers_disconnect_matched
645
(G_OBJECT (tv_info.main_window),
646
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
647
0, 0, NULL, G_CALLBACK (on_main_window_event), NULL);
949
gdk_window_remove_filter (c->root_window,
649
953
g_signal_handlers_disconnect_matched
650
954
(G_OBJECT (osd_model),
651
G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
652
0, 0, NULL, G_CALLBACK (on_osd_model_changed), NULL);
657
tv_clip_vector_destroy (&tv_info.set_vector);
658
tv_clip_vector_destroy (&tv_info.tmp_vector);
659
tv_clip_vector_destroy (&tv_info.cur_vector);
661
tv_set_capture_mode (tv_info.info, CAPTURE_MODE_NONE);
955
(G_SIGNAL_MATCH_FUNC |
956
G_SIGNAL_MATCH_DATA),
960
G_CALLBACK (on_osd_model_changed),
963
event_signal_disconnect (c, c->main_window,
964
on_main_window_event,
967
event_signal_disconnect (c, c->video_window,
968
on_video_window_event,
969
c->old_video_events);
973
case CHROMA_KEY_OVERLAY:
974
event_signal_disconnect (c, c->main_window,
975
on_main_window_event,
981
event_signal_disconnect (c, c->video_window,
982
on_video_window_event,
983
c->old_video_events);
985
if (0 != c->chroma_key_color_cnxn_id)
986
z_gconf_notify_remove (c->chroma_key_color_cnxn_id);
995
gdk_colormap_free_colors (c->colormap,
996
&c->chroma_key_color, 1);
998
g_object_unref (G_OBJECT (c->colormap));
1001
z_set_window_bg_black (c->video_window);
1004
tv_clip_vector_destroy (&c->tmp_vector);
1005
tv_clip_vector_destroy (&c->cur_vector);
1007
tv_set_capture_mode (c->info, CAPTURE_MODE_NONE);
1009
/* XXX no const limit please */
1010
z_video_set_max_size (Z_VIDEO (c->video_window), 16384, 16384);
1016
chroma_key_color_from_config (GdkColor * color)
1018
/* Factory default if the config is inaccessible
1019
or the string is malformed. */
1021
color->red = 0xFFFF;
1022
color->green = 0xCCCC;
1023
color->blue = 0xCCCC;
1025
/* XXX error message please. */
1026
return z_gconf_get_color (color, "/apps/zapping/window/chroma_key_color");
1030
set_window_bg_black (struct context * c)
1032
z_set_window_bg_black (c->video_window);
1034
CLEAR (c->chroma_key_color);
1036
return &c->chroma_key_color;
1040
set_window_bg_from_config (struct context * c)
1044
if (!DEVICE_SUPPORTS_CHROMA_KEYING (c))
1045
return set_window_bg_black (c);
1049
gdk_colormap_free_colors (c->colormap,
1050
&c->chroma_key_color, 1);
1054
c->colormap = gdk_colormap_get_system ();
1057
/* Error ignored, will continue with default. */
1058
chroma_key_color_from_config (&color);
1059
c->chroma_key_color = color;
1061
if (!OVERLAY_COLORMAP_FAILURE_TEST
1062
&& gdk_colormap_alloc_color (c->colormap,
1063
&c->chroma_key_color,
1064
/* writable */ FALSE,
1065
/* or_best_match */ TRUE))
1067
/* Note gdk_colormap_alloc_color() may change c->chroma_key_color. */
1069
z_set_window_bg (c->video_window, &c->chroma_key_color);
1071
return &c->chroma_key_color;
1075
g_object_unref (G_OBJECT (c->colormap));
1078
z_show_non_modal_message_dialog
1079
(GTK_WINDOW (zapping), GTK_MESSAGE_ERROR,
1080
_("No chroma-key color"),
1081
_("Color #%2X%2X%2X is not available for chroma-keying. "
1082
"Try another color.\n"),
1087
return set_window_bg_black (c);
1092
chroma_key_color_changed (GConfClient * client,
1097
struct context *c = user_data;
1102
c->chroma_key_color_cnxn_id = cnxn_id;
1104
set_window_bg_from_config (c);
1108
watch_config_chroma_key_color (struct context * c)
1110
if (!DEVICE_SUPPORTS_CHROMA_KEYING (c))
1111
return set_window_bg_black (c);
1113
/* Calls chroma_key_color_notify on success. */
1114
if (z_gconf_notify_add ("/apps/zapping/window/chroma_key_color",
1115
chroma_key_color_changed,
1117
return &c->chroma_key_color;
1119
/* Too bad. Let's the window background once and continue. */
1120
return set_window_bg_from_config (c);
1124
event_signal_connect (struct context * c,
1126
event_function * callback,
1127
GdkEventMask new_events)
1129
GdkEventMask old_events;
1131
if (NULL != callback)
1132
g_signal_connect (G_OBJECT (widget), "event",
1133
G_CALLBACK (callback),
1136
old_events = gdk_window_get_events (widget->window);
1137
gdk_window_set_events (widget->window, old_events | new_events);
1143
start_overlay (GtkWidget * main_window,
1144
GtkWidget * video_window)
671
tv_info.main_window = GTK_WIDGET (zapping);
672
tv_info.video_window = GTK_WIDGET (zapping->video);
674
/* XXX no const limit please */
675
z_video_set_max_size (zapping->video, 768, 576);
677
tv_info.info = zapping->info;
679
gdk_window_get_origin (GTK_WIDGET (zapping)->window,
680
&tv_info.mw_x, &tv_info.mw_y);
682
gdk_window_get_geometry (GTK_WIDGET (zapping->video)->window,
683
&tv_info.vw_x, &tv_info.vw_y,
684
&tv_info.vw_width, &tv_info.vw_height,
1146
struct context *c = &tv_info;
1147
const struct tveng_caps *caps;
1154
c->info = zapping->info;
1156
c->root_window = gdk_get_default_root_window ();
1158
c->main_window = main_window;
1159
c->video_window = video_window;
1161
gdk_window_get_origin (c->main_window->window,
1162
&c->mw_x, &c->mw_y);
1164
gdk_window_get_geometry (c->video_window->window,
685
1167
/* depth */ NULL);
687
tv_info.screen = tv_screen_list_find (screens,
688
tv_info.mw_x + tv_info.vw_x,
689
tv_info.mw_y + tv_info.vw_y,
690
(guint) tv_info.vw_width,
691
(guint) tv_info.vw_height);
693
tv_info.screen = screens;
695
CLEAR (tv_info.window);
697
tv_clip_vector_init (&tv_info.cur_vector);
698
tv_clip_vector_init (&tv_info.tmp_vector);
699
tv_clip_vector_init (&tv_info.set_vector);
701
tv_info.visibility = GDK_VISIBILITY_PARTIAL; /* assume worst */
703
tv_info.clean_screen = FALSE;
704
tv_info.geometry_changed = TRUE;
706
tv_info.timeout_id = NO_SOURCE_ID;
708
/* Make sure we use an Xv adaptor which can render into da->window.
709
(Won't help with X.org but it's the right thing to do.) */
710
tveng_close_device(zapping->info);
711
if (-1 == tveng_attach_device
712
(zcg_char (NULL, "video_device"),
713
GDK_WINDOW_XWINDOW (GTK_WIDGET (zapping->video)->window),
714
TVENG_ATTACH_XV, zapping->info))
1168
c->vw_width = width;
1169
c->vw_height = height;
1171
c->visibility = GDK_VISIBILITY_PARTIAL; /* assume worst */
1173
c->geometry_changed = TRUE; /* restart overlay */
1175
c->timeout_id = NO_SOURCE_ID;
1177
/* Make sure we use an XVideo adaptor which can render into
1178
da->window. (Doesn't matter with X.org but it's the right thing
1180
xwindow = GDK_WINDOW_XWINDOW (c->video_window->window);
1182
/* Switch to overlay mode, XVideo or other. */
1183
if (-1 == tveng_attach_device (zcg_char (NULL, "video_device"),
1184
xwindow, TVENG_ATTACH_XV, c->info))
716
ShowBox("Overlay mode not available:\n%s",
717
GTK_MESSAGE_ERROR, tv_get_errstr (zapping->info));
1186
z_show_non_modal_message_dialog
1187
(GTK_WINDOW (zapping), GTK_MESSAGE_ERROR,
1188
_("Cannot switch to overlay mode"),
1189
"%s", tv_get_errstr (c->info));
721
tv_info.needs_cleaning =
722
(tv_get_controller (zapping->info) != TVENG_CONTROLLER_XV);
724
if (tv_get_controller (zapping->info) != TVENG_CONTROLLER_XV
725
&& (OVERLAY_CHROMA_TEST
726
|| (tv_get_caps (zapping->info)->flags & TVENG_CAPS_CHROMAKEY)))
732
if (OVERLAY_CHROMA_TEST)
735
chroma.blue = 0xffff;
737
if (gdk_colormap_alloc_color (gdk_colormap_get_system (),
738
&chroma, FALSE, TRUE))
740
z_set_window_bg (GTK_WIDGET (zapping->video), &chroma);
742
/* XXX safe? (we run on 15/16/24/32 yet, but 8 bit later?) */
743
gdk_colormap_free_colors (gdk_colormap_get_system(), &chroma, 1);
747
ShowBox ("Couldn't allocate chromakey, chroma won't work",
748
GTK_MESSAGE_WARNING);
751
else if (tv_get_controller (zapping->info) == TVENG_CONTROLLER_XV)
754
unsigned int chromakey;
758
tv_get_overlay_chromakey (zapping->info, &chromakey);
760
chroma.pixel = chromakey;
762
z_set_window_bg (GTK_WIDGET (zapping->video), &chroma);
765
/* Disable double buffering just in case, will help when a
766
XV driver doesn't provide XV_COLORKEY but requires the colorkey
767
not to be overwritten */
768
gtk_widget_set_double_buffered (GTK_WIDGET (zapping->video), FALSE);
770
if (TVENG_CONTROLLER_XV == tv_get_controller (zapping->info))
772
if (!tv_set_overlay_xwindow
774
GDK_WINDOW_XWINDOW (GTK_WIDGET (zapping->video)->window),
775
GDK_GC_XGC (GTK_WIDGET (zapping->video)->style->white_gc)))
778
/* Just update overlay on video_window size change. */
780
g_signal_connect (G_OBJECT (zapping->video), "event",
781
G_CALLBACK (on_video_window_event), NULL);
783
mask = gdk_window_get_events (GTK_WIDGET (zapping->video)->window);
784
mask |= GDK_CONFIGURE;
785
gdk_window_set_events (GTK_WIDGET (zapping->video)->window, mask);
1194
/* Switch to selected video input, RF channel on new device. */
1195
zconf_get_sources (c->info, /* mute */ FALSE);
1197
if (OVERLAY_CHROMA_TEST)
1199
c->overlay_mode = CHROMA_KEY_OVERLAY;
1201
else if (DEVICE_USES_XVIDEO (c))
1203
c->overlay_mode = XVIDEO_OVERLAY;
1205
else if (DEVICE_SUPPORTS_CHROMA_KEYING (c))
1207
c->overlay_mode = CHROMA_KEY_OVERLAY;
1209
else if (DEVICE_SUPPORTS_CLIPPING (c))
1211
c->overlay_mode = CLIP_OVERLAY;
789
if (!z_set_overlay_buffer (zapping->info,
791
GTK_WIDGET (zapping->video)->window))
1215
z_show_non_modal_message_dialog
1216
(GTK_WINDOW (zapping), GTK_MESSAGE_ERROR,
1217
_("Cannot overlay with this device"),
1218
"Device does not support clipping or chroma-keying.");
1220
/* XXX Perhaps the driver supports another kind of overlay? */
1225
switch (c->overlay_mode)
1231
case XVIDEO_OVERLAY:
1232
/* XXX no const limit please, ask the driver instead. */
1233
z_video_set_max_size (Z_VIDEO (video_window), 768, 576);
1235
xwindow = GDK_WINDOW_XWINDOW (c->video_window->window);
1236
xgc = GDK_GC_XGC (c->video_window->style->white_gc);
1238
color = watch_config_chroma_key_color (c);
1240
rgb = chroma_key_rgb (color);
1242
if (!tv_set_overlay_xwindow (c->info, xwindow, xgc, rgb))
1245
/* Disable double buffering just in case, will help when a
1246
XV driver doesn't provide XV_COLORKEY but requires the colorkey
1247
not to be overwritten */
1248
gtk_widget_set_double_buffered (c->video_window, FALSE);
1250
/* Update on video_window size change. */
1251
c->old_video_events =
1252
event_signal_connect (c, c->video_window,
1253
on_video_window_event,
1256
/* Start overlay, XXX error ignored. */
1261
case CHROMA_KEY_OVERLAY:
1262
if (!select_screen (c))
1265
/* After select_screen() because the limits may depend on
1266
the overlay buffer size. FIXME they may also depend on
1267
the (then) current video standard. */
1268
caps = tv_get_caps (c->info);
1269
z_video_set_max_size (Z_VIDEO (video_window),
1273
watch_config_chroma_key_color (c);
1275
/* Update overlay on video_window size and position change. We
1276
must connect to main_window as well because the video_window
1277
GDK_CONFIGURE event notifies only about main_window, not
1278
root_window relative position changes. */
1280
c->old_video_events =
1281
event_signal_connect (c, c->video_window,
1282
on_video_window_event,
1285
c->old_main_events =
1286
event_signal_connect (c, c->main_window,
1287
on_main_window_event,
1290
/* Start overlay, XXX error ignored. */
1296
if (!select_screen (c))
1299
caps = tv_get_caps (c->info);
1300
z_video_set_max_size (Z_VIDEO (video_window),
794
1304
g_signal_connect (G_OBJECT (osd_model), "changed",
795
G_CALLBACK (on_osd_model_changed), NULL);
797
g_signal_connect (G_OBJECT (zapping->video), "event",
798
G_CALLBACK (on_video_window_event), NULL);
800
mask = gdk_window_get_events (GTK_WIDGET (zapping->video)->window);
801
mask |= GDK_VISIBILITY_NOTIFY_MASK | GDK_CONFIGURE | GDK_EXPOSE;
802
gdk_window_set_events (GTK_WIDGET (zapping->video)->window, mask);
804
/* We must connect to main_window because the video_window
805
GDK_CONFIGURE event notifies only about main_window relative,
806
not absolute i.e. root window relative position changes.
807
GDK_UNMAP, but no visibility event, is sent after the window
808
was rolled up or minimized. */
810
g_signal_connect (G_OBJECT (zapping), "event",
811
G_CALLBACK (on_main_window_event), NULL);
813
mask = gdk_window_get_events (GTK_WIDGET (zapping)->window);
814
mask |= GDK_UNMAP | GDK_CONFIGURE;
815
gdk_window_set_events (GTK_WIDGET (zapping)->window, mask);
1305
G_CALLBACK (on_osd_model_changed),
1308
c->old_video_events =
1309
event_signal_connect (c, c->video_window,
1310
on_video_window_event,
1311
(GDK_VISIBILITY_NOTIFY_MASK |
1315
/* We must connect to main_window as well because the
1316
video_window GDK_CONFIGURE event notifies only about
1317
main_window, not root_window relative position
1318
changes. GDK_UNMAP, but no visibility event, is sent
1319
after the window was rolled up or minimized. */
1321
c->old_main_events =
1322
event_signal_connect (c, c->main_window,
1323
on_main_window_event,
817
1327
/* There is no GDK_OBSCURED event, we must monitor all child
818
1328
windows of the root window. E.g. drop-down menus. */
820
tv_info.root_window = gdk_get_default_root_window ();
822
gdk_window_add_filter (tv_info.root_window, root_filter, NULL);
824
mask = GDK_STRUCTURE_MASK | GDK_SUBSTRUCTURE_MASK;
825
gdk_window_set_events (tv_info.root_window, mask);
1330
gdk_window_add_filter (c->root_window,
1334
c->old_root_events = gdk_window_get_events (c->root_window);
1335
gdk_window_set_events (c->root_window,
1336
(c->old_root_events |
1337
GDK_STRUCTURE_MASK |
1338
GDK_SUBSTRUCTURE_MASK));
1340
/* Start overlay. */
1342
restart_timeout (c);
828
1347
g_signal_connect (G_OBJECT (zapping), "delete-event",
829
G_CALLBACK (on_main_window_delete_event), NULL);
833
if (tv_info.needs_cleaning)
839
/* XXX tveng_set_preview_window (currently default is
842
if (!OVERLAY_CHROMA_TEST)
844
/* XXX error ignored */
845
tv_enable_overlay (tv_info.info, TRUE);
1348
G_CALLBACK (on_main_window_delete_event),
849
1351
zapping->display_mode = DISPLAY_MODE_WINDOW;
850
zapping->display_window = GTK_WIDGET (zapping->video);
851
tv_set_capture_mode (zapping->info, CAPTURE_MODE_OVERLAY);
1352
zapping->display_window = video_window;
1353
tv_set_capture_mode (c->info, CAPTURE_MODE_OVERLAY);