~ubuntu-branches/ubuntu/utopic/gxine/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/debian-changes/src/ui.c

  • Committer: Package Import Robot
  • Author(s): Steve Langasek
  • Date: 2014-05-07 21:34:55 UTC
  • mfrom: (2.1.17 sid)
  • Revision ID: package-import@ubuntu.com-20140507213455-qnu5diwyyj8bkaap
Tags: 0.5.907-3ubuntu1
* Merge from Debian unstable, remaining changes:
  - debian/rules, debian/control: use dh-autoreconf at build time.
  - debian/control: Add Xb-Npp-xxx, Xb-Npp-Description and Xb-Npp-File
    fields.
  - src/script_engine.c: fix a remaining memory leak issue associated with
    using JS_EncodeString(), which somehow didn't get fixed upstream
  - debian/gxineplugin.links: Add a link to xulrunner-addons/plugins
    directory.
  - mime.default: Add dvd, vcd, svcd tags.
* Dropped changes, no longer needed:
  - debian/gxine.install: no need to diverge from Debian since we no longer
    ship a wrapper
* All other changes dropped, as they have been included upstream or in
  Debian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2004-2007 the xine-project
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU General Public License as
6
 
 * published by the Free Software Foundation; either version 2 of the
7
 
 * License, or (at your option) any later version.
8
 
 *
9
 
 * This program is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 * GNU General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU General Public License
15
 
 * along with this program; if not, write to the Free Software
16
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
17
 
 * USA
18
 
 *
19
 
 * various UI bits:
20
 
 * - button registry and update (state display etc.)
21
 
 * - slider/spinner adjustment creation and update
22
 
 */
23
 
 
24
 
#include "globals.h"
25
 
 
26
 
#include <stdio.h>
27
 
#include <stdlib.h>
28
 
#include <string.h>
29
 
#include <gtk/gtk.h>
30
 
#include <gdk/gdkkeysyms.h>
31
 
#include <pthread.h>
32
 
/* for VO_CAP_HUE etc. (where available) */
33
 
#include <xine/video_out.h>
34
 
 
35
 
#include "ui.h"
36
 
#include "utils.h"
37
 
#include "engine.h"
38
 
#include "player.h"
39
 
#include "playlist.h"
40
 
#include "preferences.h"
41
 
#include "gtkvideo.h"
42
 
 
43
 
/*
44
 
 * Playback status
45
 
 * UI button & adjustment handling
46
 
 */
47
 
 
48
 
gboolean have_config = FALSE;
49
 
int config_version = 0;
50
 
 
51
 
gboolean no_recursion = FALSE;
52
 
 
53
 
gboolean fs_toolbar_at_top = FALSE;
54
 
gboolean fs_toolbar_visible = FALSE;
55
 
gboolean wm_toolbar_visible = TRUE;
56
 
gboolean wm_toolbar_snap = TRUE;
57
 
 
58
 
gboolean fs_always_sticky = FALSE;
59
 
gboolean fs_is_sticky = FALSE;
60
 
 
61
 
GtkIconSize icon_size_logo;
62
 
 
63
 
static ui_status_t status = UI_CURRENT_STATE;
64
 
pthread_mutex_t status_lock = PTHREAD_MUTEX_INITIALIZER;
65
 
 
66
 
static GSList *c_buttons[Control_Buttons] = { NULL };
67
 
static GtkObject *c_adjustments[Control_Adjustments] = { NULL };
68
 
static GSList *c_adj_widgets[Control_Adjustments] = { NULL };
69
 
 
70
 
/* (Internal) Reflect play/pause/stop status in control buttons */
71
 
 
72
 
static void ui_set_list (GSList **list, int index, const char *property, gboolean state)
73
 
{
74
 
  GSList *btn;
75
 
  foreach_glist (btn, list[index])
76
 
    if (g_object_class_find_property (G_OBJECT_GET_CLASS (btn->data), property))
77
 
      g_object_set (G_OBJECT (btn->data), property, state, NULL);
78
 
}
79
 
 
80
 
static void ui_int_set_status (ui_status_t status)
81
 
{
82
 
  char states[Control_PlayerButtons] = { 0 };
83
 
  int live = player_live_stream () || playlist_showing_logo ();
84
 
  int i;
85
 
 
86
 
  switch (status)
87
 
  {
88
 
  case UI_STOP:         states[Control_STOP]    = 1; break;
89
 
  case UI_PAUSE:        states[Control_PAUSE]   = 1; break;
90
 
  case UI_PLAY_SLOW:    states[Control_PLAY]    = 1;
91
 
                        states[Control_PAUSE]   = 1; break;
92
 
  case UI_PLAY:         states[Control_PLAY]    = 1; break;
93
 
  case UI_FAST_FORWARD: states[Control_FASTFWD] = 1; break;
94
 
  default:;
95
 
  }
96
 
 
97
 
  no_recursion = TRUE;
98
 
  for (i = 0; i < Control_PlayerButtons; ++i)
99
 
  {
100
 
    ui_set_list (c_buttons, i, "active", states[i]);
101
 
    if (i == Control_PLAY)
102
 
      ui_set_list (c_buttons, i, "sensitive", !!playlist_size ());
103
 
    else if (i == Control_PAUSE || i == Control_REWIND || i == Control_FASTFWD)
104
 
      ui_set_list (c_buttons, i, "sensitive", !live);
105
 
  }
106
 
  no_recursion = FALSE;
107
 
}
108
 
 
109
 
/* (Internal) Reflect mute status in control button */
110
 
 
111
 
static void ui_int_set_mute (int mute)
112
 
{
113
 
  GSList *btn;
114
 
  no_recursion = TRUE;
115
 
  foreach_glist (btn, c_buttons[Control_MUTE])
116
 
    g_object_set (G_OBJECT(btn->data), "active", !mute, NULL);
117
 
  no_recursion = FALSE;
118
 
}
119
 
 
120
 
/* Set/show play/pause/stop/mute status in control buttons */
121
 
 
122
 
void ui_set_status (ui_status_t newstatus)
123
 
{
124
 
  pthread_mutex_lock (&status_lock);
125
 
 
126
 
 
127
 
  switch (newstatus)
128
 
  {
129
 
  case UI_CURRENT_STATE:
130
 
    ui_int_set_status (status);
131
 
    break;
132
 
  case UI_STOP:
133
 
  case UI_PAUSE:
134
 
  case UI_PLAY_SLOW:
135
 
  case UI_PLAY:
136
 
  case UI_FAST_FORWARD:
137
 
    if (playlist_showing_logo ())
138
 
      newstatus = UI_STOP;
139
 
    ui_int_set_status (status = newstatus);
140
 
    break;
141
 
  case UI_AUDIO_UNMUTE: ui_int_set_mute (FALSE); break;
142
 
  case UI_AUDIO_MUTE:   ui_int_set_mute (TRUE); break;
143
 
  case UI_FS_TOOLBAR:   /* nothing to do */; break;
144
 
  case UI_FS_TOOLBAR_POS:/* nothing to do */; break;
145
 
  case UI_WM_TOOLBAR:   /* nothing to do */; break;
146
 
  case UI_WM_TOOLBAR_SNAP:/* nothing to do */; break;
147
 
  default:;
148
 
  }
149
 
 
150
 
  pthread_mutex_unlock (&status_lock);
151
 
}
152
 
 
153
 
/* Register a button for the above status functions */
154
 
 
155
 
void ui_register_control_button (control_button_t item, GtkWidget *widget)
156
 
{
157
 
  g_return_if_fail (item < Control_Buttons);
158
 
  c_buttons[item] = g_slist_append (c_buttons[item], widget);
159
 
}
160
 
 
161
 
/* Adjustment object <=> adjustment type <=> JS object */
162
 
 
163
 
typedef struct {
164
 
  gdouble start, min, max, step, page, pagesize;
165
 
  const char *setting, *jspref;
166
 
  int param;
167
 
#ifdef VO_CAP_HUE
168
 
  enum { CAP_NONE, CAP_AUDIO, CAP_VIDEO } type;
169
 
  int cap;
170
 
#endif
171
 
} ui_adjustable_t;
172
 
 
173
 
#ifdef VO_CAP_HUE
174
 
# define XINE_PARAM_VO(X) XINE_PARAM_VO_##X, CAP_VIDEO, VO_CAP_##X
175
 
#else
176
 
# define XINE_PARAM_VO(X) XINE_PARAM_VO_##X
177
 
#endif
178
 
 
179
 
static const ui_adjustable_t ranges[] = {
180
 
  [Control_SEEKER]              = {     0,       0,  65535,    1,    10, 0, NULL },
181
 
  [Control_AUDIO_CHANNEL]       = {    -1,      -1,     32,    1,     1, 0, NULL,                        "ao_channel",    XINE_PARAM_AUDIO_CHANNEL_LOGICAL },
182
 
  [Control_VOLUME]              = {    50,       0,    100,    1,    10, 0, "audio.volume.mixer_volume", "ao_volume",     XINE_PARAM_AUDIO_VOLUME },
183
 
  [Control_COMPRESSOR]          = {   100,     100,   1000,   10,   100, 0, "gui.ao_compressor",         "ao_compressor", XINE_PARAM_AUDIO_COMPR_LEVEL },
184
 
  [Control_AMPLIFIER]           = {   100,       0,    200,    1,    10, 0, "gui.ao_amplifier",          "ao_amplifier",  XINE_PARAM_AUDIO_AMP_LEVEL },
185
 
  [Control_AV_SYNC]             = {     0, -180000, 180000, 1000, 10000, 0, "gui.av_sync",               "av_sync",       XINE_PARAM_AV_OFFSET },
186
 
  [Control_SPU_SYNC]            = {     0, -180000, 180000, 1000, 10000, 0, "gui.spu_sync",              "spu_sync",      XINE_PARAM_SPU_OFFSET },
187
 
  [Control_HUE]                 = { 32768,       0,  65535,  100,  1000, 0, "gui.vo_hue",                "vo_hue",        XINE_PARAM_VO(HUE) },
188
 
  [Control_SATURATION]          = { 32768,       0,  65535,  100,  1000, 0, "gui.vo_saturation",         "vo_saturation", XINE_PARAM_VO(SATURATION) },
189
 
  [Control_CONTRAST]            = { 32768,       0,  65535,  100,  1000, 0, "gui.vo_contrast",           "vo_contrast",   XINE_PARAM_VO(CONTRAST) },
190
 
  [Control_BRIGHTNESS]          = { 32768,       0,  65535,  100,  1000, 0, "gui.vo_brightness",         "vo_brightness", XINE_PARAM_VO(BRIGHTNESS) },
191
 
  [Control_EQ_30]               = {   100,       0,    100,    1,    10, 0, "gui.eq_30",                 "eq_30",         XINE_PARAM_EQ_30HZ },
192
 
  [Control_EQ_60]               = {   100,       0,    100,    1,    10, 0, "gui.eq_60",                 "eq_60",         XINE_PARAM_EQ_60HZ },
193
 
  [Control_EQ_125]              = {   100,       0,    100,    1,    10, 0, "gui.eq_125",                "eq_125",        XINE_PARAM_EQ_125HZ },
194
 
  [Control_EQ_250]              = {   100,       0,    100,    1,    10, 0, "gui.eq_250",                "eq_250",        XINE_PARAM_EQ_250HZ },
195
 
  [Control_EQ_500]              = {   100,       0,    100,    1,    10, 0, "gui.eq_500",                "eq_500",        XINE_PARAM_EQ_500HZ },
196
 
  [Control_EQ_1K]               = {   100,       0,    100,    1,    10, 0, "gui.eq_1K",                 "eq_1K",         XINE_PARAM_EQ_1000HZ },
197
 
  [Control_EQ_2K]               = {   100,       0,    100,    1,    10, 0, "gui.eq_2K",                 "eq_2K",         XINE_PARAM_EQ_2000HZ },
198
 
  [Control_EQ_4K]               = {   100,       0,    100,    1,    10, 0, "gui.eq_4K",                 "eq_4K",         XINE_PARAM_EQ_4000HZ },
199
 
  [Control_EQ_8K]               = {   100,       0,    100,    1,    10, 0, "gui.eq_8K",                 "eq_8K",         XINE_PARAM_EQ_8000HZ },
200
 
  [Control_EQ_16K]              = {   100,       0,    100,    1,    10, 0, "gui.eq_16K",                "eq_16K",        XINE_PARAM_EQ_16000HZ },
201
 
};
202
 
static gdouble starts[G_N_ELEMENTS (ranges)];
203
 
static gdouble inits[G_N_ELEMENTS (ranges)];
204
 
static se_o_t *jsobjs[G_N_ELEMENTS (ranges)];
205
 
 
206
 
/* true if not volume setting or audio.remember_volume is set */
207
 
static int check_remember_volume (const ui_adjustable_t *info)
208
 
{
209
 
  xine_cfg_entry_t entry;
210
 
  return info->param != XINE_PARAM_AUDIO_VOLUME ||
211
 
         !xine_config_lookup_entry (xine, "audio.volume.remember_volume", &entry) ||
212
 
         entry.num_value;
213
 
}
214
 
 
215
 
static void ui_adjustment_value_changed_cb (GtkAdjustment *adj,
216
 
                                            const ui_adjustable_t *info)
217
 
{
218
 
  xine_cfg_entry_t entry;
219
 
 
220
 
  if (no_recursion)
221
 
    return;
222
 
 
223
 
  if (info->param)
224
 
    xine_set_param (stream, info->param, adj->value);
225
 
 
226
 
  if (info->param == XINE_PARAM_AUDIO_VOLUME)
227
 
    return;
228
 
  if (info->setting &&
229
 
      xine_config_lookup_entry (xine, info->setting, &entry))
230
 
  {
231
 
    entry.num_value = adj->value;
232
 
    preferences_update_entry (&entry);
233
 
  }
234
 
}
235
 
 
236
 
static void
237
 
ui_seeker_value_changed_cb (GtkAdjustment *seeker, gpointer data)
238
 
{
239
 
  if (!no_recursion &&
240
 
      xine_get_stream_info (stream, XINE_STREAM_INFO_SEEKABLE))
241
 
  {
242
 
    int speed;
243
 
    ++no_recursion;
244
 
    speed = xine_get_param (stream, XINE_PARAM_SPEED);
245
 
    xine_play (stream, (gint) seeker->value, 0);
246
 
    xine_set_param (stream, XINE_PARAM_SPEED, speed);
247
 
    --no_recursion;
248
 
  }
249
 
}
250
 
 
251
 
GtkObject *ui_register_control_adjustment (control_adjustment_t item)
252
 
{
253
 
  g_return_val_if_fail (item < Control_Adjustments, NULL);
254
 
 
255
 
  if (!c_adjustments[item])
256
 
  {
257
 
    xine_cfg_entry_t entry;
258
 
    int start = ranges[item].start;
259
 
 
260
 
    if (ranges[item].setting)
261
 
    {
262
 
      if (!check_remember_volume (&ranges[item]))
263
 
        start = xine_get_param (stream, XINE_PARAM_AUDIO_VOLUME);
264
 
      else if (xine_config_lookup_entry (xine, ranges[item].setting, &entry))
265
 
        start = entry.num_value;
266
 
    }
267
 
 
268
 
    starts[item] = start;
269
 
 
270
 
    if (ranges[item].param)
271
 
      inits[item] = start = xine_get_param (stream, ranges[item].param);
272
 
 
273
 
    c_adjustments[item] =
274
 
      gtk_adjustment_new (start, ranges[item].min, ranges[item].max,
275
 
                          ranges[item].step, ranges[item].page,
276
 
                          ranges[item].pagesize);
277
 
    if (ranges[item].param || ranges[item].setting)
278
 
      g_signal_connect (c_adjustments[item], "value-changed",
279
 
                        G_CALLBACK(ui_adjustment_value_changed_cb),
280
 
                        (gpointer) &ranges[item]);
281
 
    else if (item == Control_SEEKER) /* special case */
282
 
      g_signal_connect (c_adjustments[item], "value-changed",
283
 
                        G_CALLBACK (ui_seeker_value_changed_cb), NULL);
284
 
  }
285
 
  return c_adjustments[item];
286
 
}
287
 
 
288
 
/* Register a widget for the above status functions */
289
 
 
290
 
void ui_register_adjustment_widget (control_adjustment_t item, GtkWidget *widget)
291
 
{
292
 
  g_return_if_fail (item < Control_Adjustments);
293
 
  c_adj_widgets[item] = g_slist_append (c_adj_widgets[item], widget);
294
 
}
295
 
 
296
 
/* Set the state of every button in a class, e.g. every play button */
297
 
 
298
 
void ui_set_control_button (control_button_t item, gboolean state)
299
 
{
300
 
  GSList *btn;
301
 
  g_return_if_fail (item >= Control_PlayerButtons && item < Control_Buttons);
302
 
  no_recursion = TRUE;
303
 
  if (c_buttons[item] &&
304
 
      (GTK_TOGGLE_BUTTON(c_buttons[item]->data))->active != state)
305
 
    foreach_glist (btn, c_buttons[item])
306
 
      g_object_set (G_OBJECT(btn->data), "active", state, NULL);
307
 
  no_recursion = FALSE;
308
 
}
309
 
 
310
 
/* Set the value of an adjustment */
311
 
 
312
 
void ui_set_control_adjustment (control_adjustment_t item, gdouble value)
313
 
{
314
 
  g_return_if_fail (item < Control_Adjustments);
315
 
  no_recursion = TRUE;
316
 
  if ((GTK_ADJUSTMENT(c_adjustments[item]))->value != value)
317
 
    g_object_set (G_OBJECT(c_adjustments[item]), "value", value, NULL);
318
 
  no_recursion = FALSE;
319
 
}
320
 
 
321
 
void ui_reset_control_adjustment (control_adjustment_t item)
322
 
{
323
 
  g_return_if_fail (item < Control_Adjustments);
324
 
  g_object_set (G_OBJECT(c_adjustments[item]), "value",
325
 
                ranges[item].start, NULL);
326
 
}
327
 
 
328
 
void ui_revert_control_adjustment (control_adjustment_t item)
329
 
{
330
 
  g_return_if_fail (item < Control_Adjustments);
331
 
  g_object_set (G_OBJECT(c_adjustments[item]), "value", starts[item], NULL);
332
 
}
333
 
 
334
 
void ui_clear_control_adjustment (control_adjustment_t item)
335
 
{
336
 
  g_return_if_fail (item < Control_Adjustments);
337
 
  if (check_remember_volume (&ranges[item]))
338
 
    xine_set_param (stream, ranges[item].param, inits[item]);
339
 
}
340
 
 
341
 
/* Update all sliders & spinners which use this adjustment */
342
 
 
343
 
void ui_xine_set_param_from_adjustment (control_adjustment_t item)
344
 
{
345
 
  g_return_if_fail (item < Control_Adjustments);
346
 
  gtk_adjustment_value_changed (GTK_ADJUSTMENT(c_adjustments[item]));
347
 
}
348
 
 
349
 
/* Button creation */
350
 
 
351
 
static GtkWidget *ui_container_new_stock (GtkWidget *box, const char *stock)
352
 
{
353
 
  GtkWidget *img = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON);
354
 
  gtk_misc_set_padding (GTK_MISC(img), 0, 0);
355
 
  if (box)
356
 
    gtk_container_add (GTK_CONTAINER(box), img);
357
 
  return box ? box : img;
358
 
}
359
 
 
360
 
GtkWidget *ui_button_new_stock (const char *stock)
361
 
{
362
 
  return ui_container_new_stock (gtk_button_new (), stock);
363
 
}
364
 
 
365
 
GtkWidget *ui_toggle_button_new_stock (const char *stock)
366
 
{
367
 
  return ui_container_new_stock (gtk_toggle_button_new (), stock);
368
 
}
369
 
 
370
 
GtkWidget *ui_button_new_stock_mnemonic (const char *stock,
371
 
                                         const char *mnemonic)
372
 
{
373
 
  GtkWidget *button = gtk_button_new ();
374
 
  GtkWidget *align = gtk_alignment_new (0.5, 0.5, 0, 0);
375
 
  GtkWidget *hbox = gtk_hbox_new (FALSE, 2);
376
 
  /* hbox in alignment in button => hbox is not expanded to fill the button */
377
 
  gtk_container_add (GTK_CONTAINER(align), hbox);
378
 
  gtk_container_add (GTK_CONTAINER(button), align);
379
 
  gtk_box_pack_start (GTK_BOX(hbox), ui_container_new_stock (NULL, stock),
380
 
                      FALSE, FALSE, 0);
381
 
  gtk_box_pack_start (GTK_BOX(hbox), gtk_label_new_with_mnemonic (mnemonic),
382
 
                      FALSE, FALSE, 0);
383
 
  return button;
384
 
}
385
 
 
386
 
static GtkWidget *ui_container_new_icon_name (GtkWidget *box, const char *name)
387
 
{
388
 
  GtkWidget *img = gtk_image_new_from_icon_name (name, GTK_ICON_SIZE_BUTTON);
389
 
  gtk_misc_set_padding (GTK_MISC(img), 0, 0);
390
 
  if (box)
391
 
    gtk_container_add (GTK_CONTAINER(box), img);
392
 
  return box ? box : img;
393
 
}
394
 
 
395
 
GtkWidget *ui_button_new_icon_name (const char *name)
396
 
{
397
 
  return ui_container_new_icon_name (gtk_button_new (), name);
398
 
}
399
 
 
400
 
GtkWidget *ui_toggle_button_new_icon_name (const char *name)
401
 
{
402
 
  return ui_container_new_icon_name (gtk_toggle_button_new (), name);
403
 
}
404
 
 
405
 
GtkWidget *ui_button_new_icon_name_mnemonic (const char *name,
406
 
                                             const char *mnemonic)
407
 
{
408
 
  GtkWidget *button = gtk_button_new ();
409
 
  GtkWidget *align = gtk_alignment_new (0.5, 0.5, 0, 0);
410
 
  GtkWidget *hbox = gtk_hbox_new (FALSE, 2);
411
 
  /* hbox in alignment in button => hbox is not expanded to fill the button */
412
 
  gtk_container_add (GTK_CONTAINER(align), hbox);
413
 
  gtk_container_add (GTK_CONTAINER(button), align);
414
 
  gtk_box_pack_start (GTK_BOX(hbox), ui_container_new_icon_name (NULL, name),
415
 
                      FALSE, FALSE, 0);
416
 
  gtk_box_pack_start (GTK_BOX(hbox), gtk_label_new_with_mnemonic (mnemonic),
417
 
                      FALSE, FALSE, 0);
418
 
  return button;
419
 
}
420
 
 
421
 
/* Misc widgets with common properties */
422
 
 
423
 
GtkWidget *ui_spin_button_new (GtkObject *adj)
424
 
{
425
 
  return g_object_new (GTK_TYPE_SPIN_BUTTON, "adjustment", adj, "digits", 0,
426
 
                       "update-policy", GTK_UPDATE_ALWAYS, "climb-rate", 1.0,
427
 
                       "numeric", TRUE, NULL);
428
 
}
429
 
 
430
 
GtkWidget *ui_hscale_new (GtkObject *adj, GtkPositionType pos, int digits)
431
 
{
432
 
  return g_object_new (GTK_TYPE_HSCALE, "adjustment", adj, "value-pos", pos,
433
 
                       "digits", digits, NULL);
434
 
}
435
 
 
436
 
GtkWidget *ui_label_new_with_xalign (const char *label, gfloat x)
437
 
{
438
 
  return g_object_new (GTK_TYPE_LABEL, "label", label, "xalign", x, NULL);
439
 
}
440
 
 
441
 
GtkWidget *ui_label_new_with_markup (const char *label)
442
 
{
443
 
  return g_object_new (GTK_TYPE_LABEL, "label", label, "use-markup", TRUE, NULL);
444
 
}
445
 
 
446
 
/* Menu/toolbar basics */
447
 
 
448
 
GtkUIManager *ui_create_manager (const char *label, GtkWidget *window)
449
 
{
450
 
  GtkUIManager *ui = gtk_ui_manager_new ();
451
 
  GtkActionGroup *action = gtk_action_group_new (label);
452
 
#ifdef ENABLE_NLS
453
 
  gtk_action_group_set_translation_domain (action, PACKAGE);
454
 
#endif
455
 
  gtk_ui_manager_insert_action_group (ui, action, 0);
456
 
  if (window)
457
 
    gtk_window_add_accel_group (GTK_WINDOW(window),
458
 
                                gtk_ui_manager_get_accel_group (ui));
459
 
  return ui;
460
 
}
461
 
 
462
 
void ui_mark_active (GtkUIManager *ui, const char *const items[],
463
 
                     gboolean active)
464
 
{
465
 
  GtkActionGroup *actions = ui_get_action_group (ui);
466
 
  int i;
467
 
  for (i = 0; items[i]; ++i)
468
 
  {
469
 
    gtk_action_set_sensitive (gtk_action_group_get_action (actions, items[i]),
470
 
                              active);
471
 
  }
472
 
}
473
 
 
474
 
void gtk_action_group_connect_accelerators (GtkActionGroup *actions)
475
 
{
476
 
  GList *list = gtk_action_group_list_actions (actions);
477
 
  g_list_foreach (list, (GFunc) gtk_action_connect_accelerator, NULL);
478
 
  g_list_free (list);
479
 
}
480
 
 
481
 
/* Toolbar control and JS functions */
482
 
 
483
 
static void set_fs_toolbar_top (int v)
484
 
{
485
 
  if (v)
486
 
    gtk_action_activate (action_items.fs_toolbar_pos->next->data); /* top */
487
 
  else
488
 
    gtk_action_activate (action_items.fs_toolbar_pos->data); /* bottom */
489
 
}
490
 
 
491
 
#ifdef WITH_DEPRECATED
492
 
 
493
 
static JSBool js_fs_toolbar_show (JSContext *cx, JSObject *obj, uintN argc,
494
 
                                  jsval *argv, jsval *rval)
495
 
{
496
 
  JSBool show;
497
 
 
498
 
  se_log_fncall_deprecated ("toolbar_show");
499
 
  se_argc_check_max (1, "toolbar_show");
500
 
 
501
 
  if (argc == 1)
502
 
  {
503
 
    se_arg_is_int_or_bool (0, "toolbar_show");
504
 
    JS_ValueToBoolean (cx, argv[0], &show);
505
 
  }
506
 
  else
507
 
    show = !fs_toolbar_visible;
508
 
 
509
 
  window_fs_toolbar_show (show);
510
 
 
511
 
  return JS_TRUE;
512
 
}
513
 
 
514
 
#ifdef WITH_OBSOLETE
515
 
 
516
 
static JSBool js_fs_toolbar_position (JSContext *cx, JSObject *obj, uintN argc,
517
 
                                      jsval *argv, jsval *rval)
518
 
{
519
 
  JSBool top;
520
 
 
521
 
  se_log_fncall_obsolete ("set_toolbar_position");
522
 
  se_argc_check_max (1, "set_toolbar_position");
523
 
 
524
 
  if (argc == 1)
525
 
  {
526
 
    se_arg_is_int_or_bool (0, "set_toolbar_position");
527
 
    JS_ValueToBoolean (cx, argv[0], &top);
528
 
  }
529
 
  else
530
 
    top = !fs_toolbar_at_top;
531
 
 
532
 
  set_fs_toolbar_top
533
 
    (gtk_radio_action_get_current_value (action_items.fs_toolbar_pos->data));
534
 
 
535
 
  return JS_TRUE;
536
 
}
537
 
 
538
 
#endif /* WITH_OBSOLETE */
539
 
#endif /* WITH_DEPRECATED */
540
 
 
541
 
/* A/V settings JS methods */
542
 
 
543
 
static int ui_lookup_js_obj (const JSObject *obj)
544
 
{
545
 
  int i;
546
 
  for (i = 0; i < (int) G_N_ELEMENTS (ranges); ++i)
547
 
    if (jsobjs[i] && jsobjs[i]->obj == obj)
548
 
      return i;
549
 
  abort (); /* can't happen */
550
 
}
551
 
 
552
 
static JSBool js_control_revert (JSContext *cx, JSObject *obj, uintN argc,
553
 
                                 jsval *argv, jsval *rval)
554
 
{
555
 
  se_log_fncall ("<control>.revert");
556
 
  se_argc_check (0, "<control>.revert");
557
 
  ui_revert_control_adjustment (ui_lookup_js_obj (obj));
558
 
  *rval = JSVAL_VOID;
559
 
  return JS_TRUE;
560
 
}
561
 
 
562
 
static JSBool js_control_reset (JSContext *cx, JSObject *obj, uintN argc,
563
 
                                jsval *argv, jsval *rval)
564
 
{
565
 
  se_log_fncall ("<control>.reset");
566
 
  se_argc_check (0, "<control>.reset");
567
 
  ui_clear_control_adjustment (ui_lookup_js_obj (obj));
568
 
  *rval = JSVAL_VOID;
569
 
  return JS_TRUE;
570
 
}
571
 
 
572
 
/* Integer or boolean properties */
573
 
 
574
 
static void ui_prop_get (const se_prop_t *prop, se_prop_read_t *value)
575
 
{
576
 
  const ui_property_t *ui = (void *)prop->data;
577
 
  switch (ui->type)
578
 
  {
579
 
  case UI_PROP_BOOL:
580
 
    value->i = *ui->ui.flag.flag;
581
 
    break;
582
 
  case UI_PROP_XINE_PARAM:
583
 
    value->i = xine_get_param (stream, ui->ui.xine.param);
584
 
    break;
585
 
  case UI_PROP_GTK_WIDGET:
586
 
    value->i = ui->ui.widget.get (*ui->ui.widget.widget);
587
 
    break;
588
 
  case UI_PROP_GTK_VIDEO:
589
 
    value->i = ui->ui.video.get (GTK_VIDEO (gtv));
590
 
    break;
591
 
  case UI_PROP_CUSTOM:
592
 
    ui->ui.custom.get (ui, value);
593
 
    break;
594
 
  }
595
 
}
596
 
 
597
 
int ui_property_clip_int (const ui_property_t *prop, int value)
598
 
{
599
 
  if (prop->loop)
600
 
  {
601
 
    while (value < prop->min)
602
 
      value += prop->max - prop->min + 1;
603
 
    while (value > prop->max)
604
 
      value -= prop->max - prop->min + 1;
605
 
  }
606
 
  else if (value < prop->min)
607
 
    value = prop->min;
608
 
  else if (value > prop->max)
609
 
    value = prop->max;
610
 
 
611
 
  return value;
612
 
}
613
 
 
614
 
static int ui_prop_set_internal (ui_property_t *prop, int data)
615
 
{
616
 
  switch (prop->type)
617
 
  {
618
 
  case UI_PROP_BOOL:
619
 
    if (prop->ui.flag.set)
620
 
      prop->ui.flag.set (data);
621
 
    else if (gtk_toggle_action_get_active (*prop->ui.flag.action) != data)
622
 
      gtk_action_activate (&(*prop->ui.flag.action)->parent);
623
 
    break;
624
 
  case UI_PROP_XINE_PARAM:
625
 
    if (prop->ui.xine.set)
626
 
      prop->ui.xine.set (data);
627
 
    else
628
 
      xine_set_param (stream, prop->ui.xine.param, data);
629
 
    break;
630
 
  case UI_PROP_GTK_WIDGET:
631
 
    prop->ui.widget.set (*prop->ui.widget.widget, data);
632
 
    break;
633
 
  case UI_PROP_GTK_VIDEO:
634
 
    if (gtk_toggle_action_get_active (*prop->ui.video.action) != data)
635
 
      gtk_action_activate (&(*prop->ui.video.action)->parent);
636
 
    break;
637
 
  case UI_PROP_CUSTOM:
638
 
    prop->ui.custom.set (data);
639
 
    break;
640
 
  }
641
 
  return 0;
642
 
}
643
 
 
644
 
static int ui_prop_set_int (void *data, se_t *se, se_o_t *o,
645
 
                            se_prop_t *se_prop, se_prop_read_t value)
646
 
{
647
 
  value.i = ui_property_clip_int (data, value.i);
648
 
  return ui_prop_set_internal (data, value.i);
649
 
}
650
 
 
651
 
static int ui_prop_set_bool (void *data, se_t *se, se_o_t *o,
652
 
                             se_prop_t *se_prop, se_prop_read_t value)
653
 
{
654
 
  return ui_prop_set_internal (data, !!value.i);
655
 
}
656
 
 
657
 
static JSBool ui_prop_toggle_bool (JSContext *cx, JSObject *obj,
658
 
                                   uintN argc, jsval *argv, jsval *rval)
659
 
{
660
 
  se_t *se = (se_t *) JS_GetContextPrivate(cx);
661
 
  se_o_t *o = JS_GetPrivate (cx, obj);
662
 
  JSBool v = !se_prop_get_bool (se, o, "v");
663
 
  *rval = BOOLEAN_TO_JSVAL (v);
664
 
  se_prop_set_bool (se, o, "v", v);
665
 
  return JS_TRUE;
666
 
}
667
 
 
668
 
void ui_create_properties (const ui_property_t *prop, se_o_t *parent,
669
 
                           se_prop_type_t type)
670
 
{
671
 
  int i;
672
 
  se_prop_cb_t cb = NULL;
673
 
 
674
 
  switch (type)
675
 
  {
676
 
  case SE_TYPE_INT: cb = ui_prop_set_int; break;
677
 
  case SE_TYPE_BOOL: cb = ui_prop_set_bool; break;
678
 
  default:;
679
 
  }
680
 
 
681
 
  for (i = 0; prop[i].name; ++i)
682
 
  {
683
 
    se_o_t *obj =
684
 
      se_create_object (gse, parent, prop[i].name, NULL, SE_GROUP_PROPERTIES,
685
 
                        gettext (prop[i].help));
686
 
    se_prop_create_with_reader (gse, obj, "v", "", type, (intptr_t) &prop[i],
687
 
                                FALSE, ui_prop_get);
688
 
 
689
 
    if (prop[i].listen.cb)
690
 
      se_prop_add_listener (gse, obj, "v", prop[i].listen.cb,
691
 
                            prop[i].listen.user_data);
692
 
    else
693
 
      se_prop_add_listener (gse, obj, "v", cb, (void *)&prop[i]);
694
 
 
695
 
    switch (type)
696
 
    {
697
 
    case SE_TYPE_INT:
698
 
      se_prop_create_int (gse, obj, "min", prop[i].min, TRUE);
699
 
      se_prop_create_int (gse, obj, "max", prop[i].max, TRUE);
700
 
      break;
701
 
    case SE_TYPE_BOOL:
702
 
      se_defun (gse, obj, "toggle", ui_prop_toggle_bool, 0, 0,
703
 
                SE_GROUP_HIDDEN, NULL, NULL);
704
 
      break;
705
 
    default:; /* we don't handle string and float */
706
 
    }
707
 
  }
708
 
}
709
 
 
710
 
/* Post-plugin config item callbacks */
711
 
 
712
 
static void post_deinterlace_plugin_cb (void *data, xine_cfg_entry_t *cfg)
713
 
{
714
 
  if (gtv)
715
 
    gtk_video_set_post_plugins_deinterlace ((GtkVideo *)gtv, cfg->str_value);
716
 
}
717
 
 
718
 
static void post_plugins_video_cb (void *data, xine_cfg_entry_t *cfg)
719
 
{
720
 
  if (gtv)
721
 
    gtk_video_set_post_plugins_video ((GtkVideo *)gtv, cfg->str_value);
722
 
}
723
 
 
724
 
static void post_plugins_audio_cb (void *data, xine_cfg_entry_t *cfg)
725
 
{
726
 
  if (gtv)
727
 
    gtk_video_set_post_plugins_audio ((GtkVideo *)gtv, cfg->str_value,
728
 
                                      audio_port);
729
 
}
730
 
 
731
 
/* Initialisation */
732
 
 
733
 
void ui_preferences_register (xine_t *this)
734
 
{
735
 
  static const char *experience_labels[] = {
736
 
    N_("Beginner"), N_("Advanced"), N_("Expert"),
737
 
    N_("Master of the known universe"), NULL
738
 
  };
739
 
  static const char *tbar_pos_labels[] = {
740
 
    N_("Top, hidden"), N_("Bottom, hidden"),
741
 
    N_("Top, visible"), N_("Bottom, visible"),
742
 
    NULL
743
 
  };
744
 
  const char **vis_labels, *const *vis_src;
745
 
  unsigned int i;
746
 
 
747
 
  config_version = xine_config_register_num
748
 
    (this, "misc.gxine_config", 0, "gxine internal", NULL, 32767, NULL, NULL);
749
 
  xine_cfg_entry_t entry;
750
 
  if (xine_config_lookup_entry (xine, "misc.gxine_config", &entry))
751
 
  {
752
 
    entry.num_value = CONFIG_VERSION_CURRENT;
753
 
    xine_config_update_entry (xine, &entry);
754
 
  }
755
 
 
756
 
  /* Register the experience level setting */
757
 
  xine_config_register_enum
758
 
    (this, "gui.experience_level", 0, experience_labels,
759
 
     _("Display of configuration settings"),
760
 
     _("Controls whether more advanced configuration settings are shown."),
761
 
     0, GXINE_TRUE, NULL);
762
 
 
763
 
  /* Register a few audio/video config items */
764
 
  for (i = 0; i < G_N_ELEMENTS (ranges); ++i)
765
 
  {
766
 
    if (ranges[i].setting && !strncmp (ranges[i].setting, "gui.", 4))
767
 
      xine_config_register_range (this, ranges[i].setting, ranges[i].start,
768
 
                                  ranges[i].min, ranges[i].max, NULL, NULL,
769
 
                                  40, NULL, NULL);
770
 
    starts[i] = inits[i] = ranges[i].param;
771
 
  }
772
 
 
773
 
  /* Register some front-end widget options */
774
 
  xine_config_register_string
775
 
    (this, "gui.post_plugins.deinterlace",
776
 
     "tvtime:method=LinearBlend,cheap_mode=1,pulldown=none,use_progressive_frame_flag=1",
777
 
     _("Deinterlace plugins' names and parameters"),
778
 
     _("Format: plugin:arg=value,arg=value,...;plugin:..."),
779
 
     40, post_deinterlace_plugin_cb, CONFIG_DATA_NONE);
780
 
 
781
 
  xine_config_register_bool
782
 
    (this, "gui.post_plugins.deinterlace_enable", 1,
783
 
     _("Enable deinterlacing at startup"), NULL,
784
 
     30, NULL, NULL);
785
 
 
786
 
  xine_config_register_string
787
 
    (this, "gui.post_plugins.video", "",
788
 
     _("Video post-processing plugins' names and parameters"),
789
 
     _("Format: plugin:arg=value,arg=value,...;plugin:..."),
790
 
     40, post_plugins_video_cb, CONFIG_DATA_NONE);
791
 
 
792
 
  xine_config_register_bool
793
 
    (this, "gui.post_plugins.video_enable", CONFIG_VERSION_ATLEAST (0, 6, 0),
794
 
     _("Enable video post-processing at startup"), NULL,
795
 
     30, NULL, NULL);
796
 
  config_update_default ("gui.post_plugins.video_enable", 1);
797
 
 
798
 
  xine_config_register_string
799
 
    (this, "gui.post_plugins.audio", "",
800
 
     _("Audio post-processing plugins' names and parameters"),
801
 
     _("Format: plugin:arg=value,arg=value,...;plugin:..."),
802
 
     40, post_plugins_audio_cb, CONFIG_DATA_NONE);
803
 
 
804
 
  xine_config_register_bool
805
 
    (this, "gui.post_plugins.audio_enable", CONFIG_VERSION_ATLEAST (0, 6, 0),
806
 
     _("Enable audio post-processing at startup"), NULL,
807
 
     30, NULL, NULL);
808
 
  config_update_default ("gui.post_plugins.audio_enable", 1);
809
 
 
810
 
  vis_src = xine_list_post_plugins_typed
811
 
              (xine, XINE_POST_TYPE_AUDIO_VISUALIZATION);
812
 
  int goom = 0;
813
 
  for (i = 0; vis_src[i]; ++i)
814
 
    if (!strcmp (vis_src[i], "goom"))
815
 
      goom = i + 1;
816
 
  vis_labels = calloc (i + 2, sizeof (char *));
817
 
  vis_labels[0] = N_("None"); /* translate for display, not for config file */
818
 
  memcpy (vis_labels + 1, vis_src, (i + 1) * sizeof (char *));
819
 
 
820
 
  xine_config_register_enum
821
 
    (this, "gui.post_plugins.audio_visualisation", goom, vis_labels,
822
 
     _("Default audio visualisation plugin"),
823
 
     _("Post-plugin to be used when playing streams without video"),
824
 
     10, NULL, NULL);
825
 
 
826
 
  xine_config_register_bool
827
 
    (this, "gui.post_plugins.always_show_logo", 1,
828
 
     _("In windowed mode, whether the logo is shown after playing an audio-only stream if no audio visualisation was active."), NULL,
829
 
     0, GXINE_TRUE, NULL);
830
 
 
831
 
  fs_is_sticky = fs_always_sticky = xine_config_register_bool
832
 
    (this, "gui.fullscreen_mode.always_sticky", 1,
833
 
     _("In full-screen mode, whether the video always appears on all desktops & viewports"),
834
 
     NULL, 0, NULL, NULL);
835
 
 
836
 
  xine_config_register_enum
837
 
    (this, "gui.fullscreen_mode.toolbar", 1, tbar_pos_labels,
838
 
     _("Default position & visibility of the full-screen toolbar"),
839
 
     NULL, 0, NULL, NULL);
840
 
 
841
 
  xine_config_register_bool
842
 
    (this, "gui.windowed_mode.separate_toolbar", CONFIG_VERSION_ATLEAST (0, 6, 0),
843
 
     _("In windowed mode, whether the toolbar is in a separate window"), NULL,
844
 
     0, NULL, NULL);
845
 
  config_update_default ("gui.windowed_mode.separate_toolbar", 1);
846
 
 
847
 
  xine_config_register_bool
848
 
    (this, "gui.windowed_mode.unblank", CONFIG_VERSION_ATLEAST (0, 6, 0),
849
 
     _("In windowed mode, prevent blanking when playing video"), NULL,
850
 
     0, NULL, NULL);
851
 
  config_update_default ("gui.windowed_mode.unblank", 1);
852
 
 
853
 
  xine_config_register_bool
854
 
    (this, "gui.show_splash", 1,
855
 
     _("Display splash screen"),
856
 
     _("If enabled, gxine will display its splash screen"),
857
 
     0, NULL, NULL);
858
 
}
859
 
 
860
 
static int ui_listener (void *data, se_t *se, se_o_t *o, se_prop_t *prop,
861
 
                        se_prop_read_t value)
862
 
{
863
 
  int i = (ui_adjustable_t *)data - ranges;
864
 
  if (value.i < ranges[i].min)
865
 
    value.i = ranges[i].min;
866
 
  else if (value.i > ranges[i].max)
867
 
    value.i = ranges[i].max;
868
 
  ui_set_control_adjustment (i, value.i);
869
 
  ui_xine_set_param_from_adjustment (i);
870
 
  return 0;
871
 
}
872
 
 
873
 
static GtkIconSource *make_icon_source (const char *name, GtkStateType state,
874
 
                                        GtkIconSize size)
875
 
{
876
 
  GtkIconSource *isrc = gtk_icon_source_new ();
877
 
  char *filename = *name == '/'
878
 
                   ? g_build_filename (icondir, name, NULL)
879
 
                   : g_build_filename (pixmapdir, name, NULL);
880
 
  gtk_icon_source_set_filename (isrc, filename);
881
 
  free (filename);
882
 
  gtk_icon_source_set_direction_wildcarded (isrc, TRUE);
883
 
  gtk_icon_source_set_size_wildcarded (isrc, (int) size == -1);
884
 
  if ((int) size != -1)
885
 
    gtk_icon_source_set_size (isrc, size);
886
 
  gtk_icon_source_set_state_wildcarded (isrc, (int) state == -1);
887
 
  if ((int) state != -1)
888
 
    gtk_icon_source_set_state (isrc, state);
889
 
  return isrc;
890
 
}
891
 
 
892
 
static GtkIconSet *ui_std_icon (GtkIconFactory *ifactory, const char *name,
893
 
                                const char *file)
894
 
{
895
 
  GtkStockItem stock;
896
 
  if (!gtk_stock_lookup (name, &stock))
897
 
  {
898
 
    GtkIconSet *iset = gtk_icon_set_new ();
899
 
    gtk_icon_set_add_source (iset, make_icon_source (file, -1, -1));
900
 
    gtk_icon_factory_add (ifactory, name, iset);
901
 
    return iset;
902
 
  }
903
 
  return NULL;
904
 
}
905
 
 
906
 
static void ui_load_icons (void)
907
 
{
908
 
  GtkIconFactory *ifactory = gtk_icon_factory_new ();
909
 
 
910
 
  ui_std_icon (ifactory, GXINE_MEDIA_SPEAKER, "speaker.png");
911
 
  ui_std_icon (ifactory, GXINE_MEDIA_SPEAKER_MUTE, "nospeaker.png");
912
 
  ui_std_icon (ifactory, GXINE_MEDIA_MARK, "/gxine.png");
913
 
  ui_std_icon (ifactory, GXINE_LOGO, "/gxine.png");
914
 
 
915
 
  static const char *const icons[][2] = {
916
 
    { "gxine-settings-av-sync", "set-sync" },
917
 
    { "gxine-settings-spu", "subtitle" },
918
 
    { "gxine-settings-hue", "set-hue" },
919
 
    { "gxine-settings-saturation", "set-saturation" },
920
 
    { "gxine-settings-contrast", "set-contrast" },
921
 
    { "gxine-settings-brightness", "set-brightness" },
922
 
    { "gxine-settings-volume", "set-volume" },
923
 
//  { "gxine-settings-compressor", "set-compressor" },
924
 
//  { "gxine-settings-amplifier", "set-amplifier" },
925
 
    { "gxine-settings-audio-channel", "set-channel" },
926
 
  };
927
 
 
928
 
  /* Do we have an SVG loader? If so, use SVG, else use PNG */
929
 
  GSList *fmt, *fmts = gdk_pixbuf_get_formats ();
930
 
  char *name = NULL;
931
 
  foreach_glist (fmt, fmts)
932
 
  {
933
 
    free (name);
934
 
    name = gdk_pixbuf_format_get_name (fmt->data);
935
 
    if (!strcmp (name, "svg"))
936
 
      break;
937
 
  }
938
 
  free (name);
939
 
  g_slist_free (fmts);
940
 
  int i;
941
 
  for (i = 0; i < G_N_ELEMENTS (icons); ++i)
942
 
  {
943
 
        char name[128];
944
 
    snprintf (name, sizeof(name), "%s.%s", icons[i][1], fmt ? "svg" : "png");
945
 
    ui_std_icon (ifactory, icons[i][0], name);
946
 
  }
947
 
 
948
 
#ifdef WITH_OBSOLETE
949
 
  ui_std_icon (ifactory, "gxine-logo", "/gxine.png");
950
 
#endif
951
 
 
952
 
  icon_size_logo = gtk_icon_size_register ("gxine-logo-size", 64, 48);
953
 
 
954
 
  gtk_icon_factory_add_default (ifactory);
955
 
}
956
 
 
957
 
/* GtkEntry clipboard paste and button press overrides */
958
 
 
959
 
static void (*old_gtk_entry_paste) (GtkEntry *, gpointer);
960
 
static gint (*old_gtk_entry_click) (GtkWidget *, GdkEventButton *, gpointer);
961
 
 
962
 
static void ui_paste_clipboard_cb (GtkEntry *entry, gpointer data)
963
 
{
964
 
  if (entry->editable)
965
 
  {
966
 
    GtkEditable *edit = GTK_EDITABLE (entry);
967
 
    play_item_t *item = clip_get_play_item ();
968
 
    if (item)
969
 
    {
970
 
      gint pos = gtk_editable_get_position (edit);
971
 
      char *text = g_object_get_data (G_OBJECT (entry), "mrl_component");
972
 
      switch (text ? *text : 0)
973
 
      {
974
 
      default:
975
 
        text = item->mrl;
976
 
        break;
977
 
      case 'N':
978
 
        text = item->title;
979
 
        break;
980
 
      case 'T':
981
 
        text = alloca (16);
982
 
        int_to_timestring (item->start_time, text, 16);
983
 
        gtk_editable_delete_text (edit, 0, -1);
984
 
        break;
985
 
      }
986
 
      gtk_editable_insert_text (edit, text, strlen (text), &pos);
987
 
      play_item_dispose (item);
988
 
    }
989
 
    else
990
 
      old_gtk_entry_paste (entry, data);
991
 
  }
992
 
}
993
 
 
994
 
static gint ui_click_clipboard_cb (GtkWidget *widget, GdkEventButton *event,
995
 
                                   gpointer data)
996
 
{
997
 
  GtkEntry *entry = (GtkEntry *) widget;
998
 
 
999
 
  /* we need the same checks as GtkEntry's own button-press code */
1000
 
  if (event->window != entry->text_area ||
1001
 
      (entry->button && event->button != entry->button))
1002
 
    return FALSE;
1003
 
 
1004
 
  /* do our own handling of middle-button clicks */
1005
 
  if (event->button == 2 && event->type == GDK_BUTTON_PRESS && entry->editable)
1006
 
  {
1007
 
    GtkEditable *edit = GTK_EDITABLE (entry);
1008
 
    play_item_t *item = clip_get_play_item ();
1009
 
    if (item)
1010
 
    {
1011
 
      gint pos = gtk_editable_get_position (edit);
1012
 
      gtk_editable_insert_text (edit, item->mrl, strlen (item->mrl), &pos);
1013
 
      play_item_dispose (item);
1014
 
      entry->button = event->button; /* GtkEntry does this, so we do too */
1015
 
      return TRUE;
1016
 
    }
1017
 
    /* if we reach here, nothing has been pasted... */
1018
 
  }
1019
 
 
1020
 
  return old_gtk_entry_click (widget, event, data);
1021
 
}
1022
 
 
1023
 
/* UI code init */
1024
 
 
1025
 
void ui_init (void)
1026
 
{
1027
 
  xine_cfg_entry_t entry;
1028
 
  unsigned int i;
1029
 
  se_o_t *toolbars;
1030
 
 
1031
 
  static const ui_property_t tb_props[] = {
1032
 
    { "fs", N_("v=bool, toggle(): full-screen toolbar visibility"), UI_BOOL (fs_toolbar, fs_toolbar_visible, NULL) },
1033
 
    { "wm", N_("v=bool, toggle(): windowed-mode toolbar visibility"), UI_BOOL (wm_toolbar, wm_toolbar_visible, NULL) },
1034
 
    { NULL }
1035
 
  };
1036
 
  static const ui_property_t tb_fs_props[] = {
1037
 
    { "at_top", N_("v=bool, toggle(): full-screen toolbar position"), UI_BOOL (fs_toolbar_pos, fs_toolbar_at_top, set_fs_toolbar_top) },
1038
 
    { NULL }
1039
 
  };
1040
 
  static const ui_property_t tb_wm_props[] = {
1041
 
    { "snap", N_("v=bool, toggle(): windowed-mode toolbar attachment"), UI_BOOL (wm_toolbar_snap, wm_toolbar_snap, NULL) },
1042
 
    { NULL }
1043
 
  };
1044
 
 
1045
 
#ifdef WITH_DEPRECATED
1046
 
  static const se_f_def_t defs[] = {
1047
 
    { "toolbar_show", js_fs_toolbar_show, 0, 0,
1048
 
      SE_GROUP_HIDDEN, N_("[bool]"), NULL },
1049
 
#ifdef WITH_OBSOLETE
1050
 
    { "set_toolbar_position", js_fs_toolbar_position, 0, 0,
1051
 
      SE_GROUP_HIDDEN, N_("bool"), N_("at top if true") },
1052
 
#endif
1053
 
    { NULL }
1054
 
  };
1055
 
 
1056
 
  se_defuns (gse, NULL, defs);
1057
 
#endif
1058
 
 
1059
 
  /* Intercept GtkEntry's clipboard paste and button press code.
1060
 
   * This should be done via events, but the paste event handler can't return a
1061
 
   * value and both are useful for all GtkEntry widgets (but are only needed
1062
 
   * for a couple of them).
1063
 
   */
1064
 
  {
1065
 
    GtkEntryClass *klass = GTK_ENTRY_CLASS (g_type_class_peek (GTK_TYPE_ENTRY));
1066
 
    GtkWidgetClass *wclass = (GtkWidgetClass *) klass;
1067
 
    old_gtk_entry_paste = klass->paste_clipboard;
1068
 
    klass->paste_clipboard = ui_paste_clipboard_cb;
1069
 
    old_gtk_entry_click = wclass->button_press_event;
1070
 
    wclass->button_press_event = ui_click_clipboard_cb;
1071
 
  }
1072
 
 
1073
 
  toolbars = se_create_object (gse, NULL, "toolbar", NULL,
1074
 
                               SE_GROUP_PROPERTIES, NULL);
1075
 
 
1076
 
  ui_create_properties (tb_props, toolbars, SE_TYPE_BOOL);
1077
 
  ui_create_properties (tb_fs_props, se_find_object (gse, toolbars, "fs"),
1078
 
                        SE_TYPE_BOOL);
1079
 
  ui_create_properties (tb_wm_props, se_find_object (gse, toolbars, "wm"),
1080
 
                        SE_TYPE_BOOL);
1081
 
  ui_load_icons ();
1082
 
 
1083
 
  if (xine_config_lookup_entry (xine, "gui.fullscreen_mode.toolbar", &entry))
1084
 
  {
1085
 
    fs_toolbar_at_top = !(entry.num_value & 1);
1086
 
    fs_toolbar_visible = (entry.num_value >> 1) & 1;
1087
 
  }
1088
 
 
1089
 
  for (i = 0; i < G_N_ELEMENTS (ranges); ++i)
1090
 
  {
1091
 
    if (ranges[i].setting)
1092
 
    {
1093
 
      static const se_f_def_t defs[] = {
1094
 
        { "revert", js_control_revert, 0, 0, SE_GROUP_HIDDEN, NULL, NULL },
1095
 
        { "reset", js_control_reset, 0, 0, SE_GROUP_HIDDEN, NULL, NULL },
1096
 
        { NULL }
1097
 
      };
1098
 
      jsobjs[i] =
1099
 
        se_create_object (gse, NULL, ranges[i].jspref,
1100
 
                          NULL, SE_GROUP_PROPERTIES,
1101
 
                          "v=int, min, max; revert(), reset()");
1102
 
      se_defuns (gse, jsobjs[i], defs);
1103
 
      se_prop_create_xine_param (gse, jsobjs[i], "v",
1104
 
                                 ranges[i].param, SE_TYPE_INT);
1105
 
      se_prop_add_listener (gse, jsobjs[i], "v", ui_listener, (void *)&ranges[i]);
1106
 
      se_prop_create_int (gse, jsobjs[i], "min", ranges[i].min, TRUE);
1107
 
      se_prop_create_int (gse, jsobjs[i], "max", ranges[i].max, TRUE);
1108
 
    }
1109
 
  }
1110
 
}
1111
 
 
1112
 
gboolean ui_post_init (void)
1113
 
{
1114
 
  unsigned int i;
1115
 
  uint32_t cap = gtk_video_get_capabilities ((GtkVideo *)gtv);
1116
 
  gdk_threads_enter ();
1117
 
  for (i = 0; i < G_N_ELEMENTS (ranges); ++i)
1118
 
  {
1119
 
    if (ranges[i].param && i != Control_VOLUME)
1120
 
      xine_set_param (stream, ranges[i].param, starts[i]);
1121
 
#ifdef VO_CAP_HUE
1122
 
    switch (ranges[i].type)
1123
 
    {
1124
 
    case CAP_VIDEO:
1125
 
      if (ranges[i].cap && !(cap & ranges[i].cap))
1126
 
        ui_set_list (c_adj_widgets, i, "sensitive", 0);
1127
 
      break;
1128
 
    default:;
1129
 
    }
1130
 
#endif
1131
 
  }
1132
 
  gdk_threads_leave ();
1133
 
 
1134
 
  gxine_init_done ();
1135
 
  return FALSE;
1136
 
}
1137
 
 
1138
 
/* Undo button */
1139
 
 
1140
 
static void key_undo_cb (GtkAccelGroup *accel, GObject *obj, guint keyval,
1141
 
                         GdkModifierType state)
1142
 
{
1143
 
  gtk_dialog_response (GTK_DIALOG (obj), GTK_RESPONSE_REJECT);
1144
 
}
1145
 
 
1146
 
GtkAccelGroup *ui_add_undo_response (GtkWidget *window, GtkAccelGroup *accel)
1147
 
{
1148
 
  if (!accel)
1149
 
  {
1150
 
    accel = gtk_accel_group_new ();
1151
 
    gtk_window_add_accel_group (GTK_WINDOW (window), accel);
1152
 
  }
1153
 
  gtk_accel_group_connect (accel, GDK_Undo, 0, 1,
1154
 
                           g_cclosure_new_object (G_CALLBACK (key_undo_cb),
1155
 
                                                  G_OBJECT (window)));
1156
 
  return accel;
1157
 
}