~ubuntu-branches/ubuntu/karmic/zapping/karmic

« back to all changes in this revision

Viewing changes to src/overlay.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Luberda
  • Date: 2008-02-14 12:56:23 UTC
  • mfrom: (2.1.3 lenny)
  • Revision ID: james.westby@ubuntu.com-20080214125623-975n25ve2dat7jen
Tags: 0.10~cvs6-2
05_ftbfs_powerpc_libtv.patch: Try to fix FTBFS on powerpc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include "osd.h"
38
38
#include "globals.h"
39
39
#include "zvideo.h"
40
 
 
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"
 
41
#include "zgconf.h"
 
42
 
 
43
/* This code implements video overlay. It supports three methods:
 
44
 
 
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.
 
54
 
 
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
 
59
   changes.
 
60
 
 
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.
 
64
*/
46
65
 
47
66
/* TODO:
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.
51
72
 */
52
73
 
53
74
#ifndef OVERLAY_LOG_FP
54
 
#define OVERLAY_LOG_FP 0
 
75
#  define OVERLAY_LOG_FP 0
55
76
#endif
56
 
 
57
77
#ifndef OVERLAY_EVENT_LOG_FP
58
 
#define OVERLAY_EVENT_LOG_FP 0
 
78
#  define OVERLAY_EVENT_LOG_FP 0
59
79
#endif
60
 
 
61
80
#ifndef OVERLAY_DUMP_CLIPS
62
 
#define OVERLAY_DUMP_CLIPS 0
 
81
#  define OVERLAY_DUMP_CLIPS 0
63
82
#endif
64
 
 
65
83
#ifndef OVERLAY_CHROMA_TEST
66
 
#define OVERLAY_CHROMA_TEST 0
 
84
#  define OVERLAY_CHROMA_TEST 0
 
85
#endif
 
86
#ifndef OVERLAY_METHOD_FAILURE_TEST
 
87
#  define OVERLAY_METHOD_FAILURE_TEST 0
 
88
#endif
 
89
#ifndef OVERLAY_COLORMAP_FAILURE_TEST
 
90
#  define OVERLAY_COLORMAP_FAILURE_TEST 0
67
91
#endif
68
92
 
69
93
#define CLEAR_TIMEOUT 50 /* ms for the clear window timeout */
70
94
 
71
 
static struct {
 
95
enum overlay_mode {
 
96
  XVIDEO_OVERLAY = 1,
 
97
  CHROMA_KEY_OVERLAY,
 
98
  CLIP_OVERLAY,
 
99
};
 
100
 
 
101
struct context {
 
102
  /** XVideo or kernel device. */
 
103
  tveng_device_info *   info;
 
104
 
 
105
  /** The screen containing video_window (Xinerama). */
 
106
  const tv_screen *     screen;
 
107
 
 
108
  /** The root window on the current display. */
72
109
  GdkWindow *           root_window;
73
110
 
74
 
  GtkWidget *           main_window;    /* top level parent of video_window */
75
 
  GtkWidget *           video_window;   /* displays the overlay */
76
 
 
77
 
  const tv_screen *     screen;         /* screen containing video_window
78
 
                                           (Xinerama) */
79
 
 
80
 
  gint                  mw_x;           /* last known main_window position */
81
 
  gint                  mw_y;           /* (root relative) */
82
 
 
83
 
  gint                  vw_x;           /* last known video_window position */
84
 
  gint                  vw_y;           /* (main_window relative) */
85
 
 
86
 
  guint                 vw_width;       /* last known video_window size */
 
111
  /** The Zapping main window, top level parent of video_window. */
 
112
  GtkWidget *           main_window;
 
113
 
 
114
  /** The child window which actually displays the overlay. */
 
115
  GtkWidget *           video_window;
 
116
 
 
117
  /** Last known position of the main_window, relative to root_window. */ 
 
118
  gint                  mw_x;
 
119
  gint                  mw_y;
 
120
 
 
121
  /** Last known position of the video_window, relative to main_window. */ 
 
122
  gint                  vw_x;
 
123
  gint                  vw_y;
 
124
 
 
125
  /** Last known size of the video_window. */
 
126
  guint                 vw_width;
87
127
  guint                 vw_height;
88
128
 
89
 
  gboolean              needs_cleaning; /* FALSE for XVideo and chromakey */
90
 
 
91
 
  tveng_device_info *   info;           /* V4L device */
92
 
 
93
 
  /* DMA overlay */
94
 
 
95
 
  GdkVisibilityState    visibility;     /* of video_window */
96
 
 
97
 
  tv_window             window;         /* overlay rectangle */
98
 
 
 
129
  /** The overlay rectangle, relative to root_window. */
 
130
  tv_window             overlay_rect;
 
131
 
 
132
  GdkColormap *         colormap;
 
133
  GdkColor              chroma_key_color;
 
134
  guint                 chroma_key_color_cnxn_id;
 
135
 
 
136
  GdkEventMask          old_root_events;
 
137
  GdkEventMask          old_main_events;
 
138
  GdkEventMask          old_video_events;
 
139
 
 
140
  /** See above. */
 
141
  enum overlay_mode     overlay_mode;
 
142
 
 
143
  /** Additional data for overlay_mode CLIP_OVERLAY. */
 
144
 
 
145
  /** Last known visibility of the video_window. */ 
 
146
  GdkVisibilityState    visibility;
 
147
 
 
148
  /**
 
149
   * Regions obscuring the overlay_rect,
 
150
   * relative to overlay_rect position.
 
151
   */
99
152
  tv_clip_vector        cur_vector;
100
153
  tv_clip_vector        tmp_vector;
101
 
  tv_clip_vector        set_vector;
102
154
 
103
155
  gboolean              clean_screen;
104
156
  gboolean              geometry_changed;
105
157
 
106
158
  guint                 timeout_id;
107
 
} tv_info;
 
159
};
 
160
 
 
161
static struct context tv_info;
 
162
 
 
163
#define DEVICE_USES_XVIDEO(c)                                           \
 
164
  (!OVERLAY_METHOD_FAILURE_TEST                                         \
 
165
   && (0 != (tv_get_caps ((c)->info)->flags & TVENG_CAPS_XVIDEO)))
 
166
 
 
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))))
 
171
 
 
172
#define DEVICE_SUPPORTS_CLIPPING(c)                                     \
 
173
  (!OVERLAY_METHOD_FAILURE_TEST                                         \
 
174
   && (0 != (tv_get_caps ((c)->info)->flags & TVENG_CAPS_CLIPPING)))
108
175
 
109
176
static __inline__ tv_bool
110
177
tv_window_equal                 (const tv_window *      window1,
117
184
}
118
185
 
119
186
static void
120
 
get_clips                       (tv_clip_vector *       vector)
 
187
get_clips                       (const struct context * c,
 
188
                                 tv_clip_vector *       vector)
121
189
{
122
190
  if (!x11_window_clip_vector
123
191
      (vector,
124
 
       GDK_WINDOW_XDISPLAY (tv_info.video_window->window),
125
 
       GDK_WINDOW_XID (tv_info.video_window->window),
126
 
       tv_info.window.x,
127
 
       tv_info.window.y,
128
 
       tv_info.window.width,
129
 
       tv_info.window.height))
130
 
    g_assert_not_reached ();
 
192
       GDK_WINDOW_XDISPLAY (c->video_window->window),
 
193
       GDK_WINDOW_XID (c->video_window->window),
 
194
       c->overlay_rect.x,
 
195
       c->overlay_rect.y,
 
196
       c->overlay_rect.width,
 
197
       c->overlay_rect.height))
 
198
    g_assert_not_reached (); /* XXX */
131
199
 
132
200
  if (OVERLAY_DUMP_CLIPS)
133
201
    {
165
233
}
166
234
 
167
235
static void
168
 
expose_screen                   (void)
 
236
expose_screen                   (struct context *       c)
169
237
{
170
 
  tv_info.clean_screen = FALSE;
171
 
 
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);
 
238
  const tv_screen *s;
 
239
 
 
240
  c->clean_screen = FALSE;
 
241
 
 
242
  s = c->screen;
 
243
 
 
244
  x11_force_expose ((gint) s->x,
 
245
                    (gint) s->y,
 
246
                    s->width,
 
247
                    s->height);
176
248
}
177
249
 
178
250
static gboolean
179
 
set_window                      (void)
 
251
select_screen                   (struct context *       c)
180
252
{
181
 
  if (tv_set_overlay_window_clipvec (tv_info.info,
182
 
                                     &tv_info.window,
183
 
                                     &tv_info.cur_vector))
 
253
  const tv_screen *s;
 
254
 
 
255
  s = tv_screen_list_find (screens,
 
256
                           c->mw_x + c->vw_x,
 
257
                           c->mw_y + c->vw_y,
 
258
                           (guint) c->vw_width,
 
259
                           (guint) c->vw_height);
 
260
  if (NULL == s)
184
261
    {
185
 
      tv_clip_vector_set (&tv_info.set_vector, &tv_info.cur_vector);
 
262
      /* No pixel of the video_window on any screen. */
 
263
 
 
264
      c->screen = NULL;
 
265
      c->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
 
266
 
186
267
      return TRUE;
187
268
    }
188
269
 
189
 
  return FALSE;
 
270
  if (c->screen == s)
 
271
    return TRUE;
 
272
 
 
273
  /* Moved to another Xinerama screen. */
 
274
 
 
275
  c->screen = s;
 
276
 
 
277
  return tv_set_overlay_buffer (c->info,
 
278
                                x11_display_name (),
 
279
                                s->screen_number,
 
280
                                &s->target);
190
281
}
191
282
 
192
283
static gboolean
193
 
obscured_timeout                (gpointer               user_data _unused_)
 
284
obscured_timeout                (gpointer               user_data)
194
285
{
 
286
  struct context *c = user_data;
195
287
  const tv_window *window;
196
288
 
 
289
  /* The window changed from fully or partially visible
 
290
     to fully obscured. */
 
291
 
 
292
  g_assert (CLIP_OVERLAY == c->overlay_mode);
 
293
 
197
294
  if (OVERLAY_LOG_FP)
198
295
    fprintf (OVERLAY_LOG_FP, "obscured_timeout\n");
199
296
 
200
 
  /* Changed from partially visible or unobscured to fully obscured. */
201
 
 
202
 
  window = tv_cur_overlay_window (tv_info.info);
203
 
 
204
 
  if (tv_info.clean_screen)
205
 
    expose_screen ();
 
297
  window = tv_cur_overlay_window (c->info);
 
298
 
 
299
  if (c->clean_screen)
 
300
    {
 
301
      expose_screen (c);
 
302
    }
206
303
  else
207
 
    x11_force_expose (window->x,
208
 
                      window->y,
209
 
                      window->width,
210
 
                      window->height);
211
 
 
212
 
  tv_clip_vector_clear (&tv_info.cur_vector);
 
304
    {
 
305
      x11_force_expose (window->x,
 
306
                        window->y,
 
307
                        window->width,
 
308
                        window->height);
 
309
    }
 
310
 
 
311
  tv_clip_vector_clear (&c->cur_vector);
 
312
 
213
313
  /* XXX error ignored */
214
 
  tv_clip_vector_add_clip_xy (&tv_info.cur_vector,
215
 
                              0, 0, window->width, window->height);
216
 
 
217
 
  tv_info.geometry_changed = TRUE;
218
 
 
219
 
  tv_info.timeout_id = NO_SOURCE_ID;
 
314
  tv_clip_vector_add_clip_xy (&c->cur_vector,
 
315
                              /* x, y */ 0, 0,
 
316
                              window->width, window->height);
 
317
 
 
318
  c->geometry_changed = TRUE;
 
319
 
 
320
  c->timeout_id = NO_SOURCE_ID;
 
321
 
220
322
  return FALSE; /* remove timeout */
221
323
}
222
324
 
223
325
static gboolean
224
 
visible_timeout                 (gpointer               user_data _unused_)
 
326
visible_timeout                 (gpointer               user_data)
225
327
{
 
328
  struct context *c = user_data;
 
329
 
 
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).
 
333
 
 
334
     Or from fully obscured or unobscured to partially obscured.
 
335
 
 
336
     Or the clip vector may have changed while the window is
 
337
     partially obscured. */
 
338
 
 
339
  g_assert (CLIP_OVERLAY == c->overlay_mode);
 
340
 
226
341
  if (OVERLAY_LOG_FP)
227
342
    fprintf (OVERLAY_LOG_FP, "visible_timeout\n");
228
343
 
229
 
  /* Changed from
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
235
 
  */
236
 
 
237
 
  /* XXX error */
238
 
  get_clips (&tv_info.tmp_vector);
239
 
 
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);
 
346
 
 
347
  if (!tv_clip_vector_equal (&c->cur_vector, &c->tmp_vector))
242
348
    {
243
349
      /* Delay until the situation stabilizes. */
244
350
 
245
351
      if (OVERLAY_LOG_FP)
246
352
        fprintf (OVERLAY_LOG_FP, "visible_timeout: delay\n");
247
353
 
248
 
      SWAP (tv_info.cur_vector, tv_info.tmp_vector);
 
354
      SWAP (c->cur_vector, c->tmp_vector);
249
355
 
250
 
      tv_info.geometry_changed = TRUE;
 
356
      c->geometry_changed = TRUE;
251
357
 
252
358
      return TRUE; /* call again */
253
359
    }
254
360
 
 
361
  SWAP (c->cur_vector, c->tmp_vector);
 
362
 
255
363
  /* Resume overlay. */
256
364
 
257
 
  if (tv_info.geometry_changed)
 
365
  if (c->geometry_changed)
258
366
    {
259
 
      const tv_screen *xs;
260
367
      guint retry_count;
261
368
 
262
 
      tv_info.geometry_changed = FALSE;
 
369
      c->geometry_changed = FALSE;
263
370
 
264
371
      if (OVERLAY_LOG_FP)
265
372
        fprintf (OVERLAY_LOG_FP, "visible_timeout: geometry change\n");
266
373
 
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);
272
 
      if (!xs)
273
 
        xs = screens;
274
 
 
275
 
      if (tv_info.screen != xs)
276
 
        {
277
 
          /* Moved to other screen (Xinerama). */
278
 
 
279
 
          tv_info.screen = xs;
280
 
          if (!z_set_overlay_buffer (tv_info.info,
281
 
                                     tv_info.screen,
282
 
                                     tv_info.video_window->window))
283
 
            goto finish; /* XXX */
284
 
        }
285
 
 
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)
290
 
        expose_screen ();
 
377
      if (c->clean_screen)
 
378
        expose_screen (c);
291
379
      else
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));
 
382
 
 
383
      if (!select_screen (c))
 
384
        goto finish; /* XXX */
294
385
 
295
386
      /* Desired overlay bounds */
296
387
 
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;
 
392
 
 
393
      if (NULL == c->screen)
 
394
        {
 
395
          /* video_window is outside all screens. */
 
396
          goto finish;
 
397
        }
301
398
 
302
399
      retry_count = 5;
303
400
 
304
401
      for (;;)
305
402
        {
 
403
          tv_window swin;
 
404
          const tv_screen *s;
306
405
          const tv_window *w;
307
 
 
308
 
          if (retry_count-- == 0)
309
 
            goto finish; /* XXX */
310
 
 
311
 
          /* XXX error */
312
 
          set_window ();
313
 
 
314
 
          w = tv_cur_overlay_window (tv_info.info);
315
 
 
316
 
          if (tv_window_equal (&tv_info.window, w))
 
406
          unsigned int old_size;
 
407
 
 
408
          if (0 == retry_count--)
 
409
            goto finish; /* XXX */
 
410
 
 
411
          s = c->screen;
 
412
 
 
413
          swin = c->overlay_rect;
 
414
          swin.x -= s->x;
 
415
          swin.y -= s->y;
 
416
 
 
417
          w = tv_set_overlay_window_clipvec (c->info, &swin, &c->cur_vector);
 
418
          if (NULL == w)
 
419
            goto finish; /* XXX */
 
420
 
 
421
          if (tv_window_equal (&swin, w))
317
422
            break;
318
423
 
319
424
          /* The driver modified the overlay bounds (alignment, limits),
320
425
             we must update the clips. */
321
426
 
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;
326
 
 
327
 
          /* XXX error */
328
 
          get_clips (&tv_info.tmp_vector);
 
427
          old_size = c->cur_vector.size;
 
428
 
 
429
          c->overlay_rect = *w;
 
430
          c->overlay_rect.x += s->x;
 
431
          c->overlay_rect.y += s->y;
 
432
 
 
433
          /* XXX error ignored */
 
434
          get_clips (c, &c->cur_vector);
 
435
 
 
436
          if (0 == (old_size | c->cur_vector.size))
 
437
            break;
329
438
        }
330
439
    }
331
 
  else if (tv_info.clean_screen)
 
440
  else if (c->clean_screen)
332
441
    {
333
 
      expose_screen ();
 
442
      expose_screen (c);
334
443
    }
335
444
 
336
 
  if (!OVERLAY_CHROMA_TEST)
337
 
    {
338
 
      /* XXX error ignored */
339
 
      tv_enable_overlay (tv_info.info, TRUE);
340
 
    }
 
445
  /* XXX error ignored */
 
446
  tv_enable_overlay (c->info, TRUE);
341
447
 
342
448
 finish:
343
 
  tv_info.timeout_id = NO_SOURCE_ID;
 
449
  c->timeout_id = NO_SOURCE_ID;
 
450
 
344
451
  return FALSE; /* remove timeout */
345
452
}
346
453
 
347
454
static void
348
 
stop_timeout                    (void)
 
455
stop_timeout                    (struct context *       c)
349
456
{
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);
352
459
 
353
 
  tv_info.timeout_id = NO_SOURCE_ID;
 
460
  c->timeout_id = NO_SOURCE_ID;
354
461
}
355
462
 
356
463
static void
357
 
restart_timeout                 (void)
 
464
restart_timeout                 (struct context *       c)
358
465
{
 
466
  g_assert (CLIP_OVERLAY == c->overlay_mode);
 
467
 
359
468
  if (OVERLAY_LOG_FP)
360
469
    fprintf (OVERLAY_LOG_FP, "restart_timeout\n");
361
470
 
362
 
  tv_enable_overlay (tv_info.info, FALSE);
363
 
 
364
 
  stop_timeout ();
365
 
 
366
 
  if (tv_info.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
367
 
    tv_info.timeout_id =
368
 
      g_timeout_add (CLEAR_TIMEOUT,
369
 
                     (GSourceFunc) obscured_timeout, &tv_info);
 
471
  tv_enable_overlay (c->info, FALSE);
 
472
 
 
473
  stop_timeout (c);
 
474
 
 
475
  if (GDK_VISIBILITY_FULLY_OBSCURED == c->visibility)
 
476
    {
 
477
      c->timeout_id = g_timeout_add (CLEAR_TIMEOUT,
 
478
                                     (GSourceFunc) obscured_timeout,
 
479
                                     c);
 
480
    }
370
481
  else
371
 
    tv_info.timeout_id =
372
 
      g_timeout_add (CLEAR_TIMEOUT,
373
 
                     (GSourceFunc) visible_timeout, &tv_info);
374
 
}
375
 
 
376
 
static __inline__ void
377
 
reconfigure                     (void)
378
 
{
379
 
  tv_info.geometry_changed = TRUE;
380
 
  tv_info.clean_screen = TRUE; /* see root_filter() below */
381
 
 
382
 
  if (tv_info.visibility != GDK_VISIBILITY_FULLY_OBSCURED)
383
 
    restart_timeout ();
384
 
}
385
 
 
386
 
static gboolean
387
 
on_video_window_event           (GtkWidget *            widget _unused_,
 
482
    {
 
483
      c->timeout_id = g_timeout_add (CLEAR_TIMEOUT,
 
484
                                     (GSourceFunc) visible_timeout,
 
485
                                     c);
 
486
    }
 
487
}
 
488
 
 
489
static unsigned int
 
490
chroma_key_rgb                  (GdkColor *             color)
 
491
{
 
492
  return ((color->red >> 8) |
 
493
          (color->green & 0xFF00) |
 
494
          ((color->blue & 0xFF00) << 8));
 
495
}
 
496
 
 
497
static gboolean
 
498
reconfigure                     (struct context *       c)
 
499
{
 
500
  switch (c->overlay_mode)
 
501
    {
 
502
      unsigned int rgb;
 
503
      tv_window swin;
 
504
 
 
505
    case CLIP_OVERLAY:
 
506
      c->geometry_changed = TRUE;
 
507
      c->clean_screen = TRUE; /* see root_filter() */
 
508
 
 
509
      if (GDK_VISIBILITY_FULLY_OBSCURED != c->visibility)
 
510
        restart_timeout (c);
 
511
 
 
512
      break;
 
513
 
 
514
    case CHROMA_KEY_OVERLAY:
 
515
      /* Implied by tv_set_overlay_window_chromakey():
 
516
         tv_enable_overlay (c->info, FALSE); */
 
517
 
 
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,
 
522
                             /* x, y */ 0, 0,
 
523
                             c->vw_width,
 
524
                             c->vw_height);
 
525
 
 
526
      if (!select_screen (c))
 
527
        return FALSE;
 
528
 
 
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;
 
533
 
 
534
      if (0)
 
535
        fprintf (stderr, "reconfigure overlay_rect: %ux%u%+d%+d\n",
 
536
                 c->overlay_rect.width,
 
537
                 c->overlay_rect.height,
 
538
                 c->overlay_rect.x,
 
539
                 c->overlay_rect.y);
 
540
 
 
541
      if (NULL == c->screen)
 
542
        {
 
543
          /* video_window is outside all screens. */
 
544
 
 
545
          tv_enable_overlay (c->info, FALSE);
 
546
 
 
547
          return TRUE;
 
548
        }
 
549
 
 
550
      c->visibility = GDK_VISIBILITY_PARTIAL; /* or full */
 
551
 
 
552
      if (OVERLAY_CHROMA_TEST)
 
553
        {
 
554
          /* Show me the chroma key color. */
 
555
          c->overlay_rect.width /= 2;
 
556
        }
 
557
 
 
558
      swin = c->overlay_rect;
 
559
      swin.x -= c->screen->x;
 
560
      swin.y -= c->screen->y;
 
561
 
 
562
      rgb = chroma_key_rgb (&c->chroma_key_color);
 
563
 
 
564
      if (NULL == tv_set_overlay_window_chromakey (c->info, &swin, rgb))
 
565
        return FALSE;
 
566
 
 
567
      if (!tv_enable_overlay (c->info, TRUE))
 
568
        return FALSE;
 
569
 
 
570
      break;
 
571
 
 
572
    case XVIDEO_OVERLAY:
 
573
      /* XVideo overlay is automatically positioned relative to
 
574
         the video_window origin, we only have to adjust the
 
575
         overlay size. */
 
576
 
 
577
      tv_enable_overlay (c->info, FALSE);
 
578
 
 
579
      if (c->colormap)
 
580
        {
 
581
          /* Restore background color (chroma key). */
 
582
          gdk_window_clear_area (c->video_window->window,
 
583
                                 /* x, y */ 0, 0,
 
584
                                 c->vw_width,
 
585
                                 c->vw_height);
 
586
        }
 
587
 
 
588
      /* XXX set overlay rectangle here, currently the XVideo
 
589
         interface fills the entire window when overlay is enabled. */
 
590
 
 
591
      /* XXX off/on is inefficient, XVideo drivers
 
592
         do that automatically. */
 
593
      if (!tv_enable_overlay (c->info, TRUE))
 
594
        return FALSE;
 
595
 
 
596
      break;
 
597
    }
 
598
 
 
599
  return TRUE;
 
600
}
 
601
 
 
602
static gboolean
 
603
on_video_window_event           (GtkWidget *            widget,
388
604
                                 GdkEvent *             event,
389
 
                                 gpointer               user_data _unused_)
 
605
                                 gpointer               user_data)
390
606
{
 
607
  struct context *c = user_data;
 
608
 
 
609
  g_assert (widget == c->video_window);
 
610
 
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));
394
615
 
395
616
  switch (event->type)
398
619
      /* Size, position, stacking order changed. Note position
399
620
         is relative to the parent window. */
400
621
 
401
 
      if (tv_info.needs_cleaning)
 
622
      if (c->vw_width != (guint) event->configure.width
 
623
          || c->vw_height != (guint) event->configure.height
 
624
          || c->vw_x != (gint) event->configure.x
 
625
          || c->vw_y != (gint) event->configure.y)
402
626
        {
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)
407
 
            {
408
 
              tv_info.vw_x = event->configure.x; /* XXX really mw relative? */
409
 
              tv_info.vw_y = event->configure.y;
 
627
          /* XXX really mw relative? */
 
628
          c->vw_x = event->configure.x; 
 
629
          c->vw_y = event->configure.y;
410
630
              
411
 
              tv_info.vw_width = event->configure.width;
412
 
              tv_info.vw_height = event->configure.height;
413
 
 
414
 
              reconfigure ();
415
 
            }
416
 
        }
417
 
      else
418
 
        {
419
 
          /* XVideo overlay is automatically positioned relative to
420
 
             the video_window origin, only have to adjust size. */
421
 
 
422
 
          tv_enable_overlay (tv_info.info, FALSE);
423
 
 
424
 
          /* XXX tveng_set_preview_window (currently default is
425
 
             fill window size) */
426
 
 
427
 
          if (!OVERLAY_CHROMA_TEST)
428
 
            {
429
 
              /* XXX error
430
 
                 XXX off/on is inefficient, XVideo does this automatically. */
431
 
              tv_enable_overlay (tv_info.info, TRUE);
432
 
            }
 
631
          c->vw_width = event->configure.width;
 
632
          c->vw_height = event->configure.height;
 
633
 
 
634
          /* XXX error ignored. */
 
635
          reconfigure (c);
433
636
        }
434
637
 
435
638
      break;
437
640
    case GDK_VISIBILITY_NOTIFY:
438
641
      /* Visibility state changed: obscured, partially or fully visible. */
439
642
 
440
 
      if (!tv_info.needs_cleaning)
441
 
        break;
 
643
      if (CLIP_OVERLAY == c->overlay_mode)
 
644
        {
 
645
          c->visibility = event->visibility.state;
 
646
          restart_timeout (c);
 
647
        }
442
648
 
443
 
      tv_info.visibility = event->visibility.state;
444
 
      restart_timeout ();
445
649
      break;
446
650
 
447
651
    case GDK_EXPOSE:
455
659
                 event->expose.area.x + event->expose.area.width - 1,
456
660
                 event->expose.area.y + event->expose.area.height - 1);
457
661
 
458
 
      if (tv_info.needs_cleaning)
 
662
      if (CLIP_OVERLAY == c->overlay_mode)
459
663
        {
460
 
          tv_info.geometry_changed = TRUE;
461
 
          restart_timeout ();
 
664
          c->geometry_changed = TRUE;
 
665
          restart_timeout (c);
462
666
        }
463
667
 
464
668
      break;
471
675
}
472
676
 
473
677
static gboolean
474
 
on_main_window_event            (GtkWidget *            widget _unused_,
 
678
on_main_window_event            (GtkWidget *            widget,
475
679
                                 GdkEvent *             event,
476
 
                                 gpointer               user_data _unused_)
 
680
                                 gpointer               user_data)
477
681
{
 
682
  struct context *c = user_data;
 
683
 
 
684
  g_assert (widget == c->main_window);
 
685
 
478
686
  if (OVERLAY_EVENT_LOG_FP)
479
 
    fprintf (OVERLAY_EVENT_LOG_FP, "on_main_window_event: GDK_%s\n",
 
687
    fprintf (OVERLAY_EVENT_LOG_FP,
 
688
             "on_main_window_event: GDK_%s\n",
480
689
             z_gdk_event_name (event));
481
690
 
482
691
  switch (event->type)
485
694
      /* Size, position, stacking order changed. Note position
486
695
         is relative to the parent window. */
487
696
 
488
 
      if (tv_info.mw_x != event->configure.x
489
 
          || tv_info.mw_y != event->configure.y)
 
697
      switch (c->overlay_mode)
490
698
        {
491
 
          tv_info.mw_x = event->configure.x; /* XXX really root relative? */
492
 
          tv_info.mw_y = event->configure.y;
493
 
 
494
 
          reconfigure ();
 
699
        case CLIP_OVERLAY:
 
700
        case CHROMA_KEY_OVERLAY:
 
701
          if (c->mw_x != event->configure.x
 
702
              || c->mw_y != event->configure.y)
 
703
            {
 
704
              /* XXX really root relative? */
 
705
              c->mw_x = event->configure.x;
 
706
              c->mw_y = event->configure.y;
 
707
 
 
708
              /* XXX error ignored. */
 
709
              reconfigure (c);
 
710
            }
 
711
 
 
712
          break;
 
713
 
 
714
        case XVIDEO_OVERLAY:
 
715
          g_assert_not_reached ();
495
716
        }
496
717
 
497
718
      break;
498
719
 
499
720
    case GDK_UNMAP:
500
 
      /* Window was rolled up or minimized. No visibility events are
501
 
         sent in this case. */
502
 
 
503
 
      tv_info.visibility = GDK_VISIBILITY_FULLY_OBSCURED;
504
 
      restart_timeout ();
 
721
      /* Window was rolled up or minimized. No
 
722
         visibility events are sent in this case. */
 
723
 
 
724
      if (CLIP_OVERLAY == c->overlay_mode)
 
725
        {
 
726
          c->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
 
727
          restart_timeout (c);
 
728
        }
 
729
 
505
730
      break;
506
731
 
507
732
    default:
513
738
 
514
739
static GdkFilterReturn
515
740
root_filter                     (GdkXEvent *            gdkxevent,
516
 
                                 GdkEvent *             unused _unused_,
517
 
                                 gpointer               data _unused_)
 
741
                                 GdkEvent *             gdkevent,
 
742
                                 gpointer               user_data)
518
743
{
 
744
  struct context *c = user_data;
519
745
  XEvent *event = (XEvent *) gdkxevent;
520
746
 
 
747
  gdkevent = gdkevent;
 
748
 
521
749
  if (OVERLAY_EVENT_LOG_FP)
522
750
    {
523
 
      fprintf (OVERLAY_EVENT_LOG_FP, "root_filter: ");
 
751
      const gchar *s;
524
752
 
525
753
      switch (event->type)
526
754
        {
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;
 
755
#define CASE(event) case event: s = #event; break;
 
756
        CASE (KeyPress)
 
757
        CASE (KeyRelease)
 
758
        CASE (ButtonPress)
 
759
        CASE (ButtonRelease)
 
760
        CASE (MotionNotify)
 
761
        CASE (EnterNotify)
 
762
        CASE (LeaveNotify)
 
763
        CASE (FocusIn)
 
764
        CASE (FocusOut)
 
765
        CASE (KeymapNotify)
 
766
        CASE (Expose)
 
767
        CASE (GraphicsExpose)
 
768
        CASE (NoExpose)
 
769
        CASE (VisibilityNotify)
 
770
        CASE (CreateNotify)
 
771
        CASE (DestroyNotify)
 
772
        CASE (UnmapNotify)
 
773
        CASE (MapNotify)
 
774
        CASE (MapRequest)
 
775
        CASE (ReparentNotify)
 
776
        CASE (ConfigureNotify)
 
777
        CASE (ConfigureRequest)
 
778
        CASE (GravityNotify)
 
779
        CASE (ResizeRequest)
 
780
        CASE (CirculateNotify)
 
781
        CASE (CirculateRequest)
 
782
        CASE (PropertyNotify)
 
783
        CASE (SelectionClear)
 
784
        CASE (SelectionRequest)
 
785
        CASE (SelectionNotify)
 
786
        CASE (ColormapNotify)
 
787
        CASE (ClientMessage)
 
788
        CASE (MappingNotify)
 
789
#undef CASE
 
790
        default: s = "Unknown"; break;
537
791
        }
 
792
 
 
793
      fprintf (OVERLAY_EVENT_LOG_FP, "root_filter: %s\n", s);
538
794
    }
539
795
 
540
 
  if (tv_info.visibility != GDK_VISIBILITY_PARTIAL)
 
796
  if (c->visibility != GDK_VISIBILITY_PARTIAL)
541
797
    return GDK_FILTER_CONTINUE;
542
798
 
543
799
  switch (event->type)
544
800
    {
545
801
    case ConfigureNotify:
546
802
      {
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
550
 
           screen? */
 
803
        /* We could just refresh regions we previously DMAed, but
 
804
           unfortunately it's possible to move a destroyed window
 
805
           away before we did. What's worse, imperfect refresh or
 
806
           unconditionally refreshing the entire screen? */
551
807
 
552
 
        if (1)
 
808
        if (TRUE)
553
809
          {
554
 
            tv_info.clean_screen = TRUE;
 
810
            c->clean_screen = TRUE;
555
811
          }
556
812
        else
557
813
          {
558
 
            XConfigureEvent *ev = &event->xconfigure;
559
 
            const tv_window *win = tv_cur_overlay_window (tv_info.info);
560
 
 
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;
 
814
            XConfigureEvent *ev;
 
815
            const tv_window *win;
 
816
            int evx2, evy2;
 
817
            int wx2, wy2;
 
818
 
 
819
            ev = &event->xconfigure;
 
820
 
 
821
            win = tv_cur_overlay_window (c->info);
 
822
 
 
823
            evx2 = ev->x + ev->width;
 
824
            evy2 = ev->y + ev->height;
 
825
 
 
826
            wx2 = win->x + win->width;
 
827
            wy2 = win->y + win->height;
 
828
 
 
829
            if ((int)(ev->x - ev->border_width) >= wx2
 
830
                || (int)(evx2 + ev->border_width) <= (int) win->x
 
831
                || (int)(ev->y - ev->border_width) >= wy2
 
832
                || (int)(evy2 + ev->border_width) <= (int) win->y)
 
833
              {
 
834
                /* Windows do not overlap. */
 
835
                break;
 
836
              }
567
837
          }
568
838
 
569
 
        restart_timeout ();
 
839
        restart_timeout (c);
570
840
 
571
841
        break;
572
842
      }
580
850
 
581
851
/* The osd pieces have changed, avoid flicker if not needed. */
582
852
static void
583
 
on_osd_model_changed            (ZModel *               osd_model _unused_,
584
 
                                 gpointer               ignored _unused_)
 
853
on_osd_model_changed            (ZModel *               osd_model,
 
854
                                 gpointer               user_data)
585
855
{
586
 
  if (tv_info.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
587
 
    return;
588
 
 
589
 
  tv_info.visibility = GDK_VISIBILITY_PARTIAL;
590
 
  restart_timeout ();
 
856
  struct context *c = user_data;
 
857
 
 
858
  osd_model = osd_model;
 
859
 
 
860
  if (CLIP_OVERLAY == c->overlay_mode
 
861
      && GDK_VISIBILITY_FULLY_OBSCURED != c->visibility)
 
862
    {
 
863
      c->visibility = GDK_VISIBILITY_PARTIAL;
 
864
      restart_timeout (c);
 
865
    }
591
866
}
592
867
 
593
868
static void
594
 
terminate                       (void)
 
869
terminate                       (struct context *       c)
595
870
{
596
 
  stop_timeout ();
597
 
 
598
 
  tv_enable_overlay (tv_info.info, FALSE);
599
 
 
600
 
  if (tv_info.needs_cleaning)
 
871
  stop_timeout (c);
 
872
 
 
873
  tv_enable_overlay (c->info, FALSE);
 
874
 
 
875
  if (CLIP_OVERLAY == c->overlay_mode)
601
876
    {
602
877
      usleep (CLEAR_TIMEOUT * 1000);
603
878
 
604
 
      if (tv_info.clean_screen)
605
 
        expose_screen ();
 
879
      if (c->clean_screen)
 
880
        expose_screen (c);
606
881
      else
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));
609
884
    }
610
885
}
611
886
 
612
887
static gboolean
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,
 
889
                                 GdkEvent *             event,
 
890
                                 gpointer               user_data)
616
891
{
617
 
  terminate ();
 
892
  struct context *c = user_data;
 
893
 
 
894
  widget = widget;
 
895
  event = event;
 
896
 
 
897
  terminate (c);
618
898
 
619
899
  return FALSE; /* pass on */
620
900
}
621
901
 
 
902
typedef gboolean
 
903
event_function                  (GtkWidget *            widget,
 
904
                                 GdkEvent  *            event,
 
905
                                 gpointer               user_data);
 
906
 
 
907
static void
 
908
event_signal_disconnect         (struct context *       c,
 
909
                                 GtkWidget *            widget,
 
910
                                 event_function *       callback,
 
911
                                 GdkEventMask           old_events)
 
912
{
 
913
  if (NULL != callback)
 
914
    g_signal_handlers_disconnect_matched (G_OBJECT (widget),
 
915
                                          (G_SIGNAL_MATCH_FUNC |
 
916
                                           G_SIGNAL_MATCH_DATA),
 
917
                                          /* signal_id */ 0,
 
918
                                          /* detail */ 0,
 
919
                                          /* closure */ NULL,
 
920
                                          G_CALLBACK (callback),
 
921
                                          /* user_data */ c);
 
922
 
 
923
  gdk_window_set_events (widget->window, old_events);
 
924
}
 
925
 
622
926
void
623
927
stop_overlay                    (void)
624
928
{
625
 
  g_assert (tv_info.main_window != NULL);
626
 
 
627
 
  /* XXX see below */
628
 
  z_video_set_max_size (Z_VIDEO (tv_info.video_window), 16384, 16384);
629
 
 
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);
634
 
 
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);
639
 
 
640
 
  if (tv_info.needs_cleaning)
 
929
  struct context *c = &tv_info;
 
930
 
 
931
  g_assert (c->main_window != NULL);
 
932
 
 
933
  g_signal_handlers_disconnect_matched
 
934
          (G_OBJECT (zapping),
 
935
           (G_SIGNAL_MATCH_FUNC |
 
936
            G_SIGNAL_MATCH_DATA),
 
937
           /* signal_id */ 0,
 
938
           /* detail */ 0,
 
939
           /* closure */ NULL,
 
940
           G_CALLBACK (on_main_window_delete_event),
 
941
           /* user_data */ c);
 
942
 
 
943
  switch (c->overlay_mode)
641
944
    {
642
 
      gdk_window_remove_filter (tv_info.root_window, root_filter, NULL);
 
945
    case CLIP_OVERLAY:
 
946
      gdk_window_set_events (c->root_window,
 
947
                             c->old_root_events);
643
948
 
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,
 
950
                                root_filter,
 
951
                                /* user_data */ c);
648
952
 
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);
653
 
    }
654
 
 
655
 
  terminate ();
656
 
 
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);
660
 
 
661
 
  tv_set_capture_mode (tv_info.info, CAPTURE_MODE_NONE);
662
 
 
663
 
  CLEAR (tv_info);
 
955
         (G_SIGNAL_MATCH_FUNC |
 
956
          G_SIGNAL_MATCH_DATA),
 
957
         /* signal_id */ 0,
 
958
         /* detail */ 0,
 
959
         /* closure */ NULL,
 
960
         G_CALLBACK (on_osd_model_changed),
 
961
         /* user_data */ c);
 
962
 
 
963
      event_signal_disconnect (c, c->main_window,
 
964
                               on_main_window_event,
 
965
                               c->old_main_events);
 
966
 
 
967
      event_signal_disconnect (c, c->video_window,
 
968
                               on_video_window_event,
 
969
                               c->old_video_events);
 
970
 
 
971
      break;
 
972
 
 
973
    case CHROMA_KEY_OVERLAY:
 
974
      event_signal_disconnect (c, c->main_window,
 
975
                               on_main_window_event,
 
976
                               c->old_main_events);
 
977
 
 
978
      /* fall through */
 
979
 
 
980
    case XVIDEO_OVERLAY:
 
981
      event_signal_disconnect (c, c->video_window,
 
982
                               on_video_window_event,
 
983
                               c->old_video_events);
 
984
 
 
985
      if (0 != c->chroma_key_color_cnxn_id)
 
986
        z_gconf_notify_remove (c->chroma_key_color_cnxn_id);
 
987
 
 
988
      break;
 
989
    }
 
990
 
 
991
  terminate (c);
 
992
 
 
993
  if (c->colormap)
 
994
    {
 
995
      gdk_colormap_free_colors (c->colormap,
 
996
                                &c->chroma_key_color, 1);
 
997
 
 
998
      g_object_unref (G_OBJECT (c->colormap));
 
999
      c->colormap = NULL;
 
1000
 
 
1001
      z_set_window_bg_black (c->video_window);
 
1002
    }
 
1003
 
 
1004
  tv_clip_vector_destroy (&c->tmp_vector);
 
1005
  tv_clip_vector_destroy (&c->cur_vector);
 
1006
 
 
1007
  tv_set_capture_mode (c->info, CAPTURE_MODE_NONE);
 
1008
 
 
1009
  /* XXX no const limit please */
 
1010
  z_video_set_max_size (Z_VIDEO (c->video_window), 16384, 16384);
 
1011
 
 
1012
  CLEAR (*c);
 
1013
}
 
1014
 
 
1015
static gboolean
 
1016
chroma_key_color_from_config    (GdkColor *             color)
 
1017
{
 
1018
  /* Factory default if the config is inaccessible
 
1019
     or the string is malformed. */
 
1020
  color->pixel = 0;
 
1021
  color->red = 0xFFFF;
 
1022
  color->green = 0xCCCC;
 
1023
  color->blue = 0xCCCC;
 
1024
 
 
1025
  /* XXX error message please. */
 
1026
  return z_gconf_get_color (color, "/apps/zapping/window/chroma_key_color");
 
1027
}
 
1028
 
 
1029
static GdkColor *
 
1030
set_window_bg_black             (struct context *       c)
 
1031
{
 
1032
  z_set_window_bg_black (c->video_window);
 
1033
 
 
1034
  CLEAR (c->chroma_key_color);
 
1035
 
 
1036
  return &c->chroma_key_color;
 
1037
}
 
1038
 
 
1039
static GdkColor *
 
1040
set_window_bg_from_config       (struct context *       c)
 
1041
{
 
1042
  GdkColor color;
 
1043
 
 
1044
  if (!DEVICE_SUPPORTS_CHROMA_KEYING (c))
 
1045
    return set_window_bg_black (c);
 
1046
 
 
1047
  if (c->colormap)
 
1048
    {
 
1049
      gdk_colormap_free_colors (c->colormap,
 
1050
                                &c->chroma_key_color, 1);
 
1051
    }
 
1052
  else
 
1053
    {
 
1054
      c->colormap = gdk_colormap_get_system ();
 
1055
    }
 
1056
 
 
1057
  /* Error ignored, will continue with default. */
 
1058
  chroma_key_color_from_config (&color);
 
1059
  c->chroma_key_color = color;
 
1060
 
 
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))
 
1066
    {
 
1067
      /* Note gdk_colormap_alloc_color() may change c->chroma_key_color. */
 
1068
 
 
1069
      z_set_window_bg (c->video_window, &c->chroma_key_color);
 
1070
 
 
1071
      return &c->chroma_key_color;
 
1072
    }
 
1073
  else
 
1074
    {
 
1075
      g_object_unref (G_OBJECT (c->colormap));
 
1076
      c->colormap = NULL;
 
1077
 
 
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"),
 
1083
         color.red >> 8,
 
1084
         color.green >> 8,
 
1085
         color.blue >> 8);
 
1086
 
 
1087
      return set_window_bg_black (c);
 
1088
    }
 
1089
}
 
1090
 
 
1091
static void
 
1092
chroma_key_color_changed        (GConfClient *          client,
 
1093
                                 guint                  cnxn_id,
 
1094
                                 GConfEntry *           entry,
 
1095
                                 gpointer               user_data)
 
1096
{
 
1097
  struct context *c = user_data;
 
1098
 
 
1099
  client = client;
 
1100
  entry = entry;
 
1101
 
 
1102
  c->chroma_key_color_cnxn_id = cnxn_id;
 
1103
 
 
1104
  set_window_bg_from_config (c);
 
1105
}
 
1106
 
 
1107
static GdkColor *
 
1108
watch_config_chroma_key_color   (struct context *       c)
 
1109
{
 
1110
  if (!DEVICE_SUPPORTS_CHROMA_KEYING (c))
 
1111
    return set_window_bg_black (c);
 
1112
 
 
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,
 
1116
                          /* user_data */ c))
 
1117
    return &c->chroma_key_color;
 
1118
 
 
1119
  /* Too bad. Let's the window background once and continue. */
 
1120
  return set_window_bg_from_config (c);
 
1121
}
 
1122
 
 
1123
static GdkEventMask
 
1124
event_signal_connect            (struct context *       c,
 
1125
                                 GtkWidget *            widget,
 
1126
                                 event_function *       callback,
 
1127
                                 GdkEventMask           new_events)
 
1128
{
 
1129
  GdkEventMask old_events;
 
1130
 
 
1131
  if (NULL != callback)
 
1132
    g_signal_connect (G_OBJECT (widget), "event",
 
1133
                      G_CALLBACK (callback),
 
1134
                      /* user_data */ c);
 
1135
 
 
1136
  old_events = gdk_window_get_events (widget->window);
 
1137
  gdk_window_set_events (widget->window, old_events | new_events);
 
1138
 
 
1139
  return old_events;
664
1140
}
665
1141
 
666
1142
gboolean
667
 
start_overlay                   (void)
 
1143
start_overlay                   (GtkWidget *            main_window,
 
1144
                                 GtkWidget *            video_window)
668
1145
{
669
 
  GdkEventMask mask;
670
 
 
671
 
  tv_info.main_window = GTK_WIDGET (zapping);
672
 
  tv_info.video_window = GTK_WIDGET (zapping->video);
673
 
 
674
 
  /* XXX no const limit please */
675
 
  z_video_set_max_size (zapping->video, 768, 576);
676
 
 
677
 
  tv_info.info = zapping->info;
678
 
 
679
 
  gdk_window_get_origin (GTK_WIDGET (zapping)->window,
680
 
                         &tv_info.mw_x, &tv_info.mw_y);
681
 
 
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;
 
1148
  Window xwindow;
 
1149
  gint width;
 
1150
  gint height;
 
1151
 
 
1152
  CLEAR (*c);
 
1153
 
 
1154
  c->info = zapping->info;
 
1155
 
 
1156
  c->root_window = gdk_get_default_root_window ();
 
1157
 
 
1158
  c->main_window = main_window;
 
1159
  c->video_window = video_window;
 
1160
 
 
1161
  gdk_window_get_origin (c->main_window->window,
 
1162
                         &c->mw_x, &c->mw_y);
 
1163
 
 
1164
  gdk_window_get_geometry (c->video_window->window,
 
1165
                           &c->vw_x, &c->vw_y,
 
1166
                           &width, &height,
685
1167
                           /* depth */ NULL);
686
 
 
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);
692
 
  if (!tv_info.screen)
693
 
    tv_info.screen = screens;
694
 
 
695
 
  CLEAR (tv_info.window);
696
 
 
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);
700
 
 
701
 
  tv_info.visibility            = GDK_VISIBILITY_PARTIAL; /* assume worst */
702
 
 
703
 
  tv_info.clean_screen          = FALSE;
704
 
  tv_info.geometry_changed      = TRUE;
705
 
 
706
 
  tv_info.timeout_id            = NO_SOURCE_ID;
707
 
 
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;
 
1170
 
 
1171
  c->visibility = GDK_VISIBILITY_PARTIAL; /* assume worst */
 
1172
 
 
1173
  c->geometry_changed = TRUE; /* restart overlay */
 
1174
 
 
1175
  c->timeout_id = NO_SOURCE_ID;
 
1176
 
 
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
 
1179
     to do.) */
 
1180
  xwindow = GDK_WINDOW_XWINDOW (c->video_window->window);
 
1181
 
 
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))
715
1185
    {
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));
 
1190
 
718
1191
      goto failure;
719
1192
    }
720
1193
 
721
 
  tv_info.needs_cleaning =
722
 
    (tv_get_controller (zapping->info) != TVENG_CONTROLLER_XV);
723
 
 
724
 
  if (tv_get_controller (zapping->info) != TVENG_CONTROLLER_XV
725
 
      && (OVERLAY_CHROMA_TEST
726
 
          || (tv_get_caps (zapping->info)->flags & TVENG_CAPS_CHROMAKEY)))
727
 
    {
728
 
      GdkColor chroma;
729
 
 
730
 
      CLEAR (chroma);
731
 
 
732
 
      if (OVERLAY_CHROMA_TEST)
733
 
        chroma.red = 0xffff;
734
 
      else
735
 
        chroma.blue = 0xffff;
736
 
 
737
 
      if (gdk_colormap_alloc_color (gdk_colormap_get_system (),
738
 
                                    &chroma, FALSE, TRUE))
739
 
        {
740
 
          z_set_window_bg (GTK_WIDGET (zapping->video), &chroma);
741
 
 
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);
744
 
        }
745
 
      else
746
 
        {
747
 
          ShowBox ("Couldn't allocate chromakey, chroma won't work",
748
 
                   GTK_MESSAGE_WARNING);
749
 
        }
750
 
    }
751
 
  else if (tv_get_controller (zapping->info) == TVENG_CONTROLLER_XV)
752
 
    {
753
 
      GdkColor chroma;
754
 
      unsigned int chromakey;
755
 
      CLEAR (chroma);
756
 
 
757
 
      /* Error ignored */
758
 
      tv_get_overlay_chromakey (zapping->info, &chromakey);
759
 
 
760
 
      chroma.pixel = chromakey;
761
 
 
762
 
      z_set_window_bg (GTK_WIDGET (zapping->video), &chroma);
763
 
    }
764
 
 
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);
769
 
 
770
 
  if (TVENG_CONTROLLER_XV == tv_get_controller (zapping->info))
771
 
    {
772
 
      if (!tv_set_overlay_xwindow
773
 
          (tv_info.info,
774
 
           GDK_WINDOW_XWINDOW (GTK_WIDGET (zapping->video)->window),
775
 
           GDK_GC_XGC (GTK_WIDGET (zapping->video)->style->white_gc)))
776
 
        goto failure;
777
 
 
778
 
      /* Just update overlay on video_window size change. */
779
 
 
780
 
      g_signal_connect (G_OBJECT (zapping->video), "event",
781
 
                        G_CALLBACK (on_video_window_event), NULL);
782
 
 
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);
 
1196
 
 
1197
  if (OVERLAY_CHROMA_TEST)
 
1198
    {
 
1199
      c->overlay_mode = CHROMA_KEY_OVERLAY;
 
1200
    }
 
1201
  else if (DEVICE_USES_XVIDEO (c))
 
1202
    {
 
1203
      c->overlay_mode = XVIDEO_OVERLAY;
 
1204
    }
 
1205
  else if (DEVICE_SUPPORTS_CHROMA_KEYING (c))
 
1206
    {
 
1207
      c->overlay_mode = CHROMA_KEY_OVERLAY;
 
1208
    }
 
1209
  else if (DEVICE_SUPPORTS_CLIPPING (c))
 
1210
    {
 
1211
      c->overlay_mode = CLIP_OVERLAY;
786
1212
    }
787
1213
  else
788
1214
    {
789
 
      if (!z_set_overlay_buffer (zapping->info,
790
 
                                 tv_info.screen,
791
 
                                 GTK_WIDGET (zapping->video)->window))
792
 
        goto failure;
 
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.");
 
1219
 
 
1220
      /* XXX Perhaps the driver supports another kind of overlay? */
 
1221
 
 
1222
      goto failure;
 
1223
    }
 
1224
 
 
1225
  switch (c->overlay_mode)
 
1226
    {
 
1227
      GC xgc;
 
1228
      GdkColor *color;
 
1229
      unsigned int rgb;
 
1230
 
 
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);
 
1234
 
 
1235
      xwindow = GDK_WINDOW_XWINDOW (c->video_window->window);
 
1236
      xgc = GDK_GC_XGC (c->video_window->style->white_gc);
 
1237
 
 
1238
      color = watch_config_chroma_key_color (c);
 
1239
 
 
1240
      rgb = chroma_key_rgb (color);
 
1241
 
 
1242
      if (!tv_set_overlay_xwindow (c->info, xwindow, xgc, rgb))
 
1243
        goto failure;
 
1244
 
 
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);
 
1249
 
 
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,
 
1254
                              GDK_CONFIGURE);
 
1255
 
 
1256
      /* Start overlay, XXX error ignored. */
 
1257
      reconfigure (c);
 
1258
    
 
1259
      break;
 
1260
 
 
1261
    case CHROMA_KEY_OVERLAY:
 
1262
      if (!select_screen (c))
 
1263
        goto failure;
 
1264
 
 
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),
 
1270
                            caps->maxwidth,
 
1271
                            caps->maxheight);
 
1272
 
 
1273
      watch_config_chroma_key_color (c);
 
1274
 
 
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. */
 
1279
 
 
1280
      c->old_video_events =
 
1281
        event_signal_connect (c, c->video_window,
 
1282
                              on_video_window_event,
 
1283
                              GDK_CONFIGURE);
 
1284
 
 
1285
      c->old_main_events =
 
1286
        event_signal_connect (c, c->main_window,
 
1287
                              on_main_window_event,
 
1288
                              GDK_CONFIGURE);
 
1289
 
 
1290
      /* Start overlay, XXX error ignored. */
 
1291
      reconfigure (c);
 
1292
 
 
1293
      break;
 
1294
 
 
1295
    case CLIP_OVERLAY:
 
1296
      if (!select_screen (c))
 
1297
        goto failure;
 
1298
 
 
1299
      caps = tv_get_caps (c->info);
 
1300
      z_video_set_max_size (Z_VIDEO (video_window),
 
1301
                            caps->maxwidth,
 
1302
                            caps->maxheight);
793
1303
 
794
1304
      g_signal_connect (G_OBJECT (osd_model), "changed",
795
 
                        G_CALLBACK (on_osd_model_changed), NULL);
796
 
 
797
 
      g_signal_connect (G_OBJECT (zapping->video), "event",
798
 
                        G_CALLBACK (on_video_window_event), NULL);
799
 
 
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);
803
 
 
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. */
809
 
 
810
 
      g_signal_connect (G_OBJECT (zapping), "event",
811
 
                        G_CALLBACK (on_main_window_event), NULL);
812
 
 
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),
 
1306
                        /* user_data */ c);
 
1307
 
 
1308
      c->old_video_events =
 
1309
        event_signal_connect (c, c->video_window,
 
1310
                              on_video_window_event,
 
1311
                              (GDK_VISIBILITY_NOTIFY_MASK |
 
1312
                               GDK_CONFIGURE |
 
1313
                               GDK_EXPOSE));
 
1314
 
 
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. */
 
1320
 
 
1321
      c->old_main_events =
 
1322
        event_signal_connect (c, c->main_window,
 
1323
                              on_main_window_event,
 
1324
                              (GDK_UNMAP |
 
1325
                               GDK_CONFIGURE));
816
1326
 
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. */
819
1329
 
820
 
      tv_info.root_window = gdk_get_default_root_window ();
821
 
 
822
 
      gdk_window_add_filter (tv_info.root_window, root_filter, NULL);
823
 
 
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,
 
1331
                             root_filter,
 
1332
                             /* user_data */ c);
 
1333
 
 
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));
 
1339
 
 
1340
      /* Start overlay. */
 
1341
 
 
1342
      restart_timeout (c);
 
1343
 
 
1344
      break;
826
1345
    }
827
1346
 
828
1347
  g_signal_connect (G_OBJECT (zapping), "delete-event",
829
 
                    G_CALLBACK (on_main_window_delete_event), NULL);
830
 
 
831
 
  /* Start overlay */
832
 
 
833
 
  if (tv_info.needs_cleaning)
834
 
    {
835
 
      restart_timeout ();
836
 
    }
837
 
  else
838
 
    {
839
 
      /* XXX tveng_set_preview_window (currently default is
840
 
         fill window size) */
841
 
 
842
 
      if (!OVERLAY_CHROMA_TEST)
843
 
        {
844
 
          /* XXX error ignored */
845
 
          tv_enable_overlay (tv_info.info, TRUE);
846
 
        }
847
 
    }
 
1348
                    G_CALLBACK (on_main_window_delete_event),
 
1349
                    /* user_data */ c);
848
1350
 
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);
852
1354
 
853
1355
  return TRUE;
854
1356