16
19
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
24
#ifdef HAVE_CONFIG_H
23
28
#include <gtk/gtk.h>
24
29
#include <gdk/gdkx.h>
32
#define ZCONF_DOMAIN "/zapping/options/main/"
27
34
#include "x11stuff.h"
30
36
#include "overlay.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. */
48
+ Special mode for devices without clipping. Hint: think twice.
49
+ Matte option (clip out WSS, GCR).
50
+ Source rectangle, if supported by hardware (e.g. zoom function).
53
#ifndef OVERLAY_LOG_FP
54
#define OVERLAY_LOG_FP 0
57
#ifndef OVERLAY_EVENT_LOG_FP
58
#define OVERLAY_EVENT_LOG_FP 0
61
#ifndef OVERLAY_DUMP_CLIPS
62
#define OVERLAY_DUMP_CLIPS 0
65
#ifndef OVERLAY_CHROMA_TEST
66
#define OVERLAY_CHROMA_TEST 0
33
69
#define CLEAR_TIMEOUT 50 /* ms for the clear window timeout */
35
/* event names for debugging. event_str = events[event->type+1] */
36
#if 0 /* just for debugging */
37
static gchar * events[] =
56
"GDK_PROPERTY_NOTIFY",
57
"GDK_SELECTION_CLEAR",
58
"GDK_SELECTION_REQUEST",
59
"GDK_SELECTION_NOTIFY",
69
"GDK_VISIBILITY_NOTIFY",
74
/* Saves some info about the tv_screen */
76
gint x, y, w, h; /* geometry */
77
gboolean visible; /* If it is visible */
78
GtkWidget * window; /* The window we will be overlaying to */
79
GtkWidget * main_window; /* The toplevel window .window is in */
80
tveng_device_info * info; /* The overlaying V4L device */
81
struct tveng_clip * clips; /* Clip rectangles */
82
gint clipcount; /* Number of clips in clips */
83
gboolean clean_screen; /* TRUE if the whole screen will be cleared */
84
gint clear_timeout_id; /* timeout for redrawing */
85
gboolean needs_cleaning; /* FALSE for XVideo and chromakey */
72
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 */
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 */
99
tv_clip_vector cur_vector;
100
tv_clip_vector tmp_vector;
101
tv_clip_vector set_vector;
103
gboolean clean_screen;
104
gboolean geometry_changed;
88
/* Pointer to a gdk wrapper for the root window */
89
static GdkWindow *root_window = NULL;
92
* Just like x11_get_clips, but fixes the dword-align ugliness
94
static struct tveng_clip *
95
overlay_get_clips(GdkWindow * window, gint * clipcount)
97
struct tveng_clip * clips;
99
g_assert(clipcount != NULL);
101
if (!window || !tv_info.needs_cleaning)
107
clips = x11_get_clips(window,
108
tv_info.info->window.x,
109
tv_info.info->window.y,
110
tv_info.info->window.width,
111
tv_info.info->window.height,
118
* Checks whether two clipping structs look the same.
121
compare_clips(struct tveng_clip *a, gint na, struct tveng_clip* b,
129
for (i = 0; i < na; i++)
130
if ((a[i].x != b[i].x) || (a[i].y != b[i].y) ||
131
(a[i].width != b[i].width) || (a[i].height != b[i].height))
138
* Clearing needed callback
141
overlay_clearing_timeout(gpointer data)
143
struct tveng_clip * clips;
146
clips = overlay_get_clips(tv_info.window->window, &clipcount);
148
if (!compare_clips(clips, clipcount, tv_info.clips,
150
{ /* delay the update till the situation stabilizes */
152
g_free(tv_info.clips);
154
tv_info.clips = clips;
155
tv_info.clipcount = clipcount;
156
tv_info.clean_screen = TRUE;
158
return TRUE; /* call me again */
164
if ((tv_info.info->current_mode == TVENG_CAPTURE_WINDOW) &&
165
(tv_info.needs_cleaning) && (tv_info.visible))
109
static __inline__ tv_bool
110
tv_window_equal (const tv_window * window1,
111
const tv_window * window2)
113
return (0 == ((window1->x ^ window2->x) |
114
(window1->y ^ window2->y) |
115
(window1->width ^ window2->width) |
116
(window1->height ^ window2->height)));
120
get_clips (tv_clip_vector * vector)
122
if (!x11_window_clip_vector
124
GDK_WINDOW_XDISPLAY (tv_info.video_window->window),
125
GDK_WINDOW_XID (tv_info.video_window->window),
128
tv_info.window.width,
129
tv_info.window.height))
130
g_assert_not_reached ();
132
if (OVERLAY_DUMP_CLIPS)
137
clip = vector->vector;
139
fprintf (stderr, "get_clips %u:\n", vector->size);
141
for (i = 0; i < vector->size; ++i, ++clip)
142
fprintf (stderr, "%3u: %3u, %3u - %3u, %3u\n",
143
i, clip->x1, clip->y1, clip->x2, clip->y2);
148
expose_window_clip_vector (const tv_window * window,
149
const tv_clip_vector * clip_vector)
154
clip = clip_vector->vector;
155
count = clip_vector->size;
159
x11_force_expose (window->x + clip->x1,
160
window->y + clip->y1,
161
(guint)(clip->x2 - clip->x1),
162
(guint)(clip->y2 - clip->y1));
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);
181
if (tv_set_overlay_window_clipvec (tv_info.info,
183
&tv_info.cur_vector))
185
tv_clip_vector_set (&tv_info.set_vector, &tv_info.cur_vector);
193
obscured_timeout (gpointer user_data _unused_)
195
const tv_window *window;
198
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)
207
x11_force_expose (window->x,
212
tv_clip_vector_clear (&tv_info.cur_vector);
213
/* 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;
220
return FALSE; /* remove timeout */
224
visible_timeout (gpointer user_data _unused_)
227
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))
243
/* Delay until the situation stabilizes. */
246
fprintf (OVERLAY_LOG_FP, "visible_timeout: delay\n");
248
SWAP (tv_info.cur_vector, tv_info.tmp_vector);
250
tv_info.geometry_changed = TRUE;
252
return TRUE; /* call again */
255
/* Resume overlay. */
257
if (tv_info.geometry_changed)
262
tv_info.geometry_changed = FALSE;
265
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
/* Other windows may have received expose events before we
287
were able to turn off the overlay. Resend expose
288
events for those regions which should be clean now. */
167
289
if (tv_info.clean_screen)
168
x11_force_expose(0, 0, gdk_screen_width(), gdk_screen_height());
170
x11_force_expose(tv_info.info->window.x-40,
171
tv_info.info->window.y-40,
172
tv_info.info->window.width+80,
173
tv_info.info->window.height+80);
175
tv_info.clean_screen = FALSE;
178
/* Setup the overlay and start it again if needed */
179
if (tv_info.info->current_mode == TVENG_CAPTURE_WINDOW)
182
if (tv_info.needs_cleaning)
185
tveng_set_preview_on(tv_info.info);
187
tveng_set_preview_off(tv_info.info);
191
*((gint*)data) = -1; /* set timeout_id to destroyed */
193
return FALSE; /* the timeout will be destroyed */
197
* Something has changed, schedule a redraw in TIMEOUT ms
198
* clean_screen: the whole screen needs updating
201
overlay_status_changed(gboolean clean_screen)
203
if (tv_info.clear_timeout_id >= 0)
204
gtk_timeout_remove(tv_info.clear_timeout_id);
206
tv_info.clear_timeout_id =
207
gtk_timeout_add(CLEAR_TIMEOUT, overlay_clearing_timeout,
208
&(tv_info.clear_timeout_id));
210
if ((tv_info.info->current_mode == TVENG_CAPTURE_WINDOW) &&
211
(tv_info.needs_cleaning))
212
tveng_set_preview_off(tv_info.info);
214
if (!tv_info.clean_screen)
215
tv_info.clean_screen = clean_screen;
219
* event handler for the toplevel overlay window
222
on_main_overlay_event (GtkWidget *widget,
292
expose_window_clip_vector (tv_cur_overlay_window (tv_info.info),
293
&tv_info.set_vector);
295
/* 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;
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))
319
/* The driver modified the overlay bounds (alignment, limits),
320
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);
331
else if (tv_info.clean_screen)
336
if (!OVERLAY_CHROMA_TEST)
338
/* XXX error ignored */
339
tv_enable_overlay (tv_info.info, TRUE);
343
tv_info.timeout_id = NO_SOURCE_ID;
344
return FALSE; /* remove timeout */
350
if (tv_info.timeout_id > 0)
351
g_source_remove (tv_info.timeout_id);
353
tv_info.timeout_id = NO_SOURCE_ID;
357
restart_timeout (void)
360
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);
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_,
389
gpointer user_data _unused_)
391
if (OVERLAY_EVENT_LOG_FP)
392
fprintf (OVERLAY_EVENT_LOG_FP, "on_video_window_event: GDK_%s\n",
393
z_gdk_event_name (event));
398
/* Size, position, stacking order changed. Note position
399
is relative to the parent window. */
401
if (tv_info.needs_cleaning)
403
if (tv_info.vw_width != (guint) event->configure.width
404
|| tv_info.vw_height != (guint) event->configure.height
405
|| tv_info.vw_x != (gint) event->configure.x
406
|| tv_info.vw_y != (gint) event->configure.y)
408
tv_info.vw_x = event->configure.x; /* XXX really mw relative? */
409
tv_info.vw_y = event->configure.y;
411
tv_info.vw_width = event->configure.width;
412
tv_info.vw_height = event->configure.height;
419
/* XVideo overlay is automatically positioned relative to
420
the video_window origin, only have to adjust size. */
422
tv_enable_overlay (tv_info.info, FALSE);
424
/* XXX tveng_set_preview_window (currently default is
427
if (!OVERLAY_CHROMA_TEST)
430
XXX off/on is inefficient, XVideo does this automatically. */
431
tv_enable_overlay (tv_info.info, TRUE);
437
case GDK_VISIBILITY_NOTIFY:
438
/* Visibility state changed: obscured, partially or fully visible. */
440
if (!tv_info.needs_cleaning)
443
tv_info.visibility = event->visibility.state;
448
/* Parts of the video window have been exposed, e.g. menu window has
449
been closed. Remove those clips. */
451
if (OVERLAY_EVENT_LOG_FP)
452
fprintf (OVERLAY_EVENT_LOG_FP, "Expose rect %d,%d - %d,%d\n",
453
event->expose.area.x,
454
event->expose.area.y,
455
event->expose.area.x + event->expose.area.width - 1,
456
event->expose.area.y + event->expose.area.height - 1);
458
if (tv_info.needs_cleaning)
460
tv_info.geometry_changed = TRUE;
470
return FALSE; /* pass on */
474
on_main_window_event (GtkWidget * widget _unused_,
476
gpointer user_data _unused_)
478
if (OVERLAY_EVENT_LOG_FP)
479
fprintf (OVERLAY_EVENT_LOG_FP, "on_main_window_event: GDK_%s\n",
480
z_gdk_event_name (event));
485
/* Size, position, stacking order changed. Note position
486
is relative to the parent window. */
488
if (tv_info.mw_x != event->configure.x
489
|| tv_info.mw_y != event->configure.y)
491
tv_info.mw_x = event->configure.x; /* XXX really root relative? */
492
tv_info.mw_y = event->configure.y;
229
tv_info.visible = FALSE;
231
overlay_status_changed(TRUE);
234
tv_info.visible = TRUE;
235
overlay_status_changed(FALSE);
238
overlay_status_changed(TRUE);
500
/* Window was rolled up or minimized. No visibility events are
501
sent in this case. */
503
tv_info.visibility = GDK_VISIBILITY_FULLY_OBSCURED;
511
return FALSE; /* pass on */
248
* Event handler for the root window.
250
514
static GdkFilterReturn
251
x_root_filter (GdkXEvent *xev,
515
root_filter (GdkXEvent * gdkxevent,
516
GdkEvent * unused _unused_,
517
gpointer data _unused_)
255
struct tveng_clip * clips;
258
if (tv_info.clear_timeout_id >= 0 || !tv_info.needs_cleaning ||
260
return GDK_FILTER_CONTINUE; /* no need for this */
262
clips = overlay_get_clips(tv_info.window->window, &clipcount);
264
if (!compare_clips(clips, clipcount, tv_info.clips,
266
overlay_status_changed(TRUE);
519
XEvent *event = (XEvent *) gdkxevent;
521
if (OVERLAY_EVENT_LOG_FP)
523
fprintf (OVERLAY_EVENT_LOG_FP, "root_filter: ");
527
case MotionNotify: fprintf (OVERLAY_EVENT_LOG_FP, "MotionNotify\n"); break;
528
case Expose: fprintf (OVERLAY_EVENT_LOG_FP, "Expose\n"); break;
529
case VisibilityNotify: fprintf (OVERLAY_EVENT_LOG_FP, "VisibilityNotify\n"); break;
530
case CreateNotify: fprintf (OVERLAY_EVENT_LOG_FP, "CreateNotify\n"); break;
531
case DestroyNotify: fprintf (OVERLAY_EVENT_LOG_FP, "DestroyNotify\n"); break;
532
case UnmapNotify: fprintf (OVERLAY_EVENT_LOG_FP, "UnmapNotify\n"); break;
533
case MapNotify: fprintf (OVERLAY_EVENT_LOG_FP, "MapNotify\n"); break;
534
case ConfigureNotify: fprintf (OVERLAY_EVENT_LOG_FP, "ConfigureNotify\n"); break;
535
case GravityNotify: fprintf (OVERLAY_EVENT_LOG_FP, "GravityNotify\n"); break;
536
default: fprintf (OVERLAY_EVENT_LOG_FP, "Unknown\n"); break;
540
if (tv_info.visibility != GDK_VISIBILITY_PARTIAL)
541
return GDK_FILTER_CONTINUE;
545
case ConfigureNotify:
547
/* We could just refresh regions we previously DMAed, but unfortunately
548
it's possible to move a destroyed window away before we did. What's
549
worse, imperfect refresh or unconditionally refreshing the entire
554
tv_info.clean_screen = TRUE;
558
XConfigureEvent *ev = &event->xconfigure;
559
const tv_window *win = tv_cur_overlay_window (tv_info.info);
561
if ((int)(ev->x - ev->border_width) >= (int)(win->x + win->width)
562
|| (int)(ev->x + ev->width + ev->border_width) <= (int) win->x
563
|| (int)(ev->y - ev->border_width) >= (int)(win->y + win->height)
564
|| (int)(ev->y + ev->height + ev->border_width) <= (int) win->y)
565
/* Windows do not overlap. */
566
return GDK_FILTER_CONTINUE;
270
578
return GDK_FILTER_CONTINUE;
274
* Called when the tv_screen geometry changes
581
/* The osd pieces have changed, avoid flicker if not needed. */
277
on_tv_screen_size_allocate (GtkWidget *widget,
278
GtkAllocation *allocation,
583
on_osd_model_changed (ZModel * osd_model _unused_,
584
gpointer ignored _unused_)
281
static gint old_w=-1, old_h;
284
* GtkFixed sends allocation events when removing
285
* children from it, even when no resize is involved. Ignore these.
287
if (old_w == allocation->width &&
288
old_h == allocation->height)
586
if (tv_info.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
291
old_w = allocation->width;
292
old_h = allocation->height;
294
overlay_status_changed(FALSE);
298
* Called when the main overlay window is destroyed (shuts down the
589
tv_info.visibility = GDK_VISIBILITY_PARTIAL;
598
tv_enable_overlay (tv_info.info, FALSE);
600
if (tv_info.needs_cleaning)
602
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);
302
on_main_overlay_delete_event (GtkWidget *widget,
306
if (tv_info.clear_timeout_id >= 0)
308
gtk_timeout_remove(tv_info.clear_timeout_id);
309
tv_info.clear_timeout_id = -1;
312
return FALSE; /* go on with the callbacks */
316
* The osd pieces have changed, avoid flicker if not needed.
319
on_osd_model_changed (ZModel *osd_model,
322
struct tveng_window window;
324
if (tv_info.clear_timeout_id >= 0 || !tv_info.needs_cleaning ||
326
return; /* no need for this */
329
g_free(tv_info.clips);
332
overlay_get_clips(tv_info.window->window, &tv_info.clipcount);
334
memcpy(&window, &tv_info.info->window, sizeof(struct tveng_window));
335
tveng_set_preview_off(tv_info.info);
336
memcpy(&tv_info.info->window, &window, sizeof(struct tveng_window));
337
tv_info.info->window.clips = tv_info.clips;
338
tv_info.info->window.clipcount = tv_info.clipcount;
339
tveng_set_preview_window(tv_info.info);
340
tveng_set_preview_on(tv_info.info);
344
* Inits the overlay engine.
345
* window: The window we will be overlaying to.
346
* main_window: The toplevel window window belongs to. They can be the
350
startup_overlay(GtkWidget * window, GtkWidget * main_window,
351
tveng_device_info * info)
353
GdkEventMask mask; /* The GDK events we want to see */
354
GdkColor chroma = {0, 0, 0, 0};
356
gtk_signal_connect(GTK_OBJECT(main_window), "event",
357
GTK_SIGNAL_FUNC(on_main_overlay_event),
360
gtk_signal_connect(GTK_OBJECT(main_window), "delete-event",
361
GTK_SIGNAL_FUNC(on_main_overlay_delete_event),
364
gtk_signal_connect(GTK_OBJECT(window), "size-allocate",
365
GTK_SIGNAL_FUNC(on_tv_screen_size_allocate),
369
gdk has no [Sub]structureNotify wrapper, but a timer will
372
mask = gdk_window_get_events(window->window);
373
mask |= (GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK);
374
gdk_window_set_events(window->window, mask);
376
mask = gdk_window_get_events(main_window->window);
377
mask |= (GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK);
378
gdk_window_set_events(main_window->window, mask);
380
tv_info.window = window;
381
tv_info.main_window = main_window;
383
tv_info.visible = x11_window_viewable(window->window);
385
tv_info.clear_timeout_id = -1;
386
tv_info.clean_screen = FALSE;
387
tv_info.clips = NULL;
388
tv_info.clipcount = 0;
389
if (info->current_controller == TVENG_CONTROLLER_XV)
390
tv_info.needs_cleaning = FALSE;
392
tv_info.needs_cleaning = TRUE;
393
gdk_window_get_size(window->window, &tv_info.w, &tv_info.h);
394
gdk_window_get_origin(window->window, &tv_info.x, &tv_info.y);
396
if (info->current_controller != TVENG_CONTROLLER_XV)
398
if (info->caps.flags & TVENG_CAPS_CHROMAKEY)
400
chroma.red = chroma.green = 0;
401
chroma.blue = 0xffff;
403
if (gdk_colormap_alloc_color(gdk_colormap_get_system(), &chroma,
405
tveng_set_chromakey(chroma.red >> 8, chroma.green >> 8,
406
chroma.blue >> 8, info);
408
ShowBox("Couldn't allocate chromakey, chroma won't work",
409
GNOME_MESSAGE_BOX_WARNING);
412
gdk_window_set_background(window->window, &chroma);
414
if (chroma.pixel != 0)
415
gdk_colormap_free_colors(gdk_colormap_get_system(), &chroma,
420
gdk_window_set_background(window->window, &chroma);
424
if (tv_info.needs_cleaning)
428
root_window = gdk_window_foreign_new(GDK_ROOT_WINDOW());
429
gdk_window_set_events(root_window,
431
GDK_SUBSTRUCTURE_MASK);
433
gdk_window_add_filter(root_window, x_root_filter, NULL);
435
gtk_signal_connect(GTK_OBJECT(osd_model), "changed",
436
GTK_SIGNAL_FUNC(on_osd_model_changed),
438
/* Update the cliplist now */
439
on_osd_model_changed(osd_model, NULL);
441
#endif /* HAVE_LIBZVBI */
445
* Stops the overlay engine.
448
overlay_stop(tveng_device_info *info)
450
gtk_signal_disconnect_by_func(GTK_OBJECT(tv_info.main_window),
451
GTK_SIGNAL_FUNC(on_main_overlay_event),
454
gtk_signal_disconnect_by_func(GTK_OBJECT(tv_info.main_window),
455
GTK_SIGNAL_FUNC(on_main_overlay_delete_event),
458
gtk_signal_disconnect_by_func(GTK_OBJECT(tv_info.window),
459
GTK_SIGNAL_FUNC(on_tv_screen_size_allocate),
462
if (tv_info.needs_cleaning)
463
gtk_signal_disconnect_by_func(GTK_OBJECT(osd_model),
464
GTK_SIGNAL_FUNC(on_osd_model_changed),
468
if (tv_info.needs_cleaning)
469
gdk_window_remove_filter(root_window, x_root_filter, NULL);
471
if (tv_info.clear_timeout_id >= 0)
473
gtk_timeout_remove(tv_info.clear_timeout_id);
474
tv_info.clear_timeout_id = -1;
477
if (tv_info.needs_cleaning)
478
x11_force_expose(0, 0, gdk_screen_width(), gdk_screen_height());
482
* Shuts down the overlay engine
485
shutdown_overlay(void )
487
/* Nothing to be done */
491
* Tells the overlay engine to sync the overlay with the window.
492
* clean_screen: TRUE means that we should refresh the whole screeen.
495
overlay_sync(gboolean clean_screen)
497
extern tveng_device_info *main_info;
499
if (main_info->current_mode != TVENG_CAPTURE_WINDOW)
502
gdk_window_get_size(tv_info.window->window, &tv_info.w, &tv_info.h);
503
gdk_window_get_origin(tv_info.window->window, &tv_info.x,
507
g_free(tv_info.clips);
509
tv_info.info->window.x = tv_info.x;
510
tv_info.info->window.y = tv_info.y;
511
tv_info.info->window.width = tv_info.w;
512
tv_info.info->window.height = tv_info.h;
513
tv_info.info->window.clips = tv_info.clips =
514
overlay_get_clips(tv_info.window->window,
515
&(tv_info.info->window.clipcount));
516
tv_info.clipcount = tv_info.info->window.clipcount;
517
tv_info.info->window.win = GDK_WINDOW_XWINDOW(tv_info.window->window);
518
tv_info.info->window.gc = GDK_GC_XGC(tv_info.window->style->white_gc);
520
tveng_set_preview_window(tv_info.info);
523
g_free(tv_info.clips);
524
tv_info.clips = NULL;
527
/* The requested overlay coords might not be the definitive ones,
529
if (tv_info.needs_cleaning)
531
tv_info.clips = tv_info.info->window.clips =
532
overlay_get_clips(tv_info.window->window, &(tv_info.clipcount));
533
tv_info.info->window.clipcount = tv_info.clipcount;
535
tveng_set_preview_window(tv_info.info);
538
x11_force_expose(0, 0, gdk_screen_width(), gdk_screen_height());
613
on_main_window_delete_event (GtkWidget * widget _unused_,
614
GdkEvent * event _unused_,
615
gpointer user_data _unused_)
619
return FALSE; /* pass on */
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)
642
gdk_window_remove_filter (tv_info.root_window, root_filter, NULL);
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);
649
g_signal_handlers_disconnect_matched
650
(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);
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,
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))
716
ShowBox("Overlay mode not available:\n%s",
717
GTK_MESSAGE_ERROR, tv_get_errstr (zapping->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);
789
if (!z_set_overlay_buffer (zapping->info,
791
GTK_WIDGET (zapping->video)->window))
794
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);
817
/* There is no GDK_OBSCURED event, we must monitor all child
818
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);
828
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);
849
zapping->display_mode = DISPLAY_MODE_WINDOW;
850
tv_set_capture_mode (zapping->info, CAPTURE_MODE_OVERLAY);