/*
 * Copyright (C) 2000-2004 the xine project
 * 
 * This file is part of xine, a unix video player.
 * 
 * xine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * xine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: panel.c,v 1.226 2005/07/24 02:40:37 fsck-p Exp $
 *
 * xine panel related stuff
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <pthread.h>

#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif

#include "common.h"

extern gGui_t     *gGui;

_panel_t          *panel = NULL;

void panel_update_nextprev_tips(void) {

  if(gGui->skip_by_chapter) { 
    xitk_set_widget_tips(panel->playback_widgets.prev, _("Play previous chapter or mrl")); 
    xitk_set_widget_tips(panel->playback_widgets.next, _("Play next chapter or mrl")); 
  }
  else {
    xitk_set_widget_tips(panel->playback_widgets.prev, _("Play previous entry from playlist"));
    xitk_set_widget_tips(panel->playback_widgets.next, _("Play next entry from playlist")); 
  }
}

int is_playback_widgets_enabled(void) {
  return (panel->playback_widgets.enabled == 1);
}

void enable_playback_controls(int enable) {
  void (*enability)(xitk_widget_t *) = NULL;
  
  panel->playback_widgets.enabled = enable;
  
  if(enable)
    enability = xitk_enable_widget;
  else
    enability = xitk_disable_widget;
  
  enability(panel->playback_widgets.prev);
  enability(panel->playback_widgets.stop);
  enability(panel->playback_widgets.play);
  enability(panel->playback_widgets.pause);
  enability(panel->playback_widgets.next);
  enability(panel->playback_widgets.slider_play);
}

/*
 *
 */
void panel_show_tips(void) {
  
  if(panel->tips.enable)
    xitk_set_widgets_tips_timeout(panel->widget_list, panel->tips.timeout);
  else
    xitk_disable_widgets_tips(panel->widget_list);

  playlist_show_tips(panel->tips.enable, panel->tips.timeout);
  control_show_tips(panel->tips.enable, panel->tips.timeout);
  mrl_browser_show_tips(panel->tips.enable, panel->tips.timeout);
  event_sender_show_tips(panel->tips.enable, panel->tips.timeout);
  mmk_editor_show_tips(panel->tips.enable, panel->tips.timeout);
  setup_show_tips(panel->tips.enable, panel->tips.timeout);
}

/* Somewhat paranoia conditionals (Hans, YOU're paranoid ;-) )*/
int panel_get_tips_enable(void) {
  return (panel) ? panel->tips.enable : 0;
}
unsigned long panel_get_tips_timeout(void) {
  return (panel) ? panel->tips.timeout : 0;
}

/*
 * Config callbacks.
 */
static void panel_enable_tips_cb(void *data, xine_cfg_entry_t *cfg) {
  panel->tips.enable = cfg->num_value;
  panel_show_tips();
}
static void panel_timeout_tips_cb(void *data, xine_cfg_entry_t *cfg) {
  panel->tips.timeout = (unsigned long) cfg->num_value;

  panel_show_tips();
}

/*
 * Toolkit event handler will call this function with new
 * coords of panel window.
 */
static void panel_store_new_position(int x, int y, int w, int h) {

  if(panel->skin_on_change == 0) {
    
    panel->x = x;
    panel->y = y;
    
    config_update_num ("gui.panel_x", x); 
    config_update_num ("gui.panel_y", y);
    
    if(event_sender_is_running())
      event_sender_move(x+w, y);

  }
  else
    panel->skin_on_change--;

}

static void panel_exit(xitk_widget_t *w, void *data) {

  if(panel) {
    window_info_t wi;
    
    panel->visible = 0;

    if((xitk_get_window_info(panel->widget_key, &wi))) {
      config_update_num ("gui.panel_x", wi.x);
      config_update_num ("gui.panel_y", wi.y);
      WINDOW_INFO_ZERO(&wi);
    }

    xitk_unregister_event_handler(&panel->widget_key);

    XLockDisplay(gGui->display);
    XUnmapWindow(gGui->display, gGui->panel_window);
    XUnlockDisplay(gGui->display);

    panel->title_label = 0;
    xitk_destroy_widgets(panel->widget_list);

    XLockDisplay(gGui->display);
    XDestroyWindow(gGui->display, gGui->panel_window);
    Imlib_destroy_image(gGui->imlib_data, panel->bg_image);
    XUnlockDisplay(gGui->display);

    gGui->panel_window = None;
    xitk_list_free((XITK_WIDGET_LIST_LIST(panel->widget_list)));

    XLockDisplay(gGui->display);
    XFreeGC(gGui->display, (XITK_WIDGET_LIST_GC(panel->widget_list)));
    XUnlockDisplay(gGui->display);

    free(panel->widget_list);
    
    free(panel);
    panel = NULL;  
  }
}

/*
 * Change the current skin.
 */
void panel_change_skins(int synthetic) {
  ImlibImage   *new_img, *old_img;
  XSizeHints    hint;
  
  panel->skin_on_change++;

  xitk_skin_lock(gGui->skin_config);
  xitk_hide_widgets(panel->widget_list);

  XLockDisplay(gGui->display);
  
  if(!(new_img = Imlib_load_image(gGui->imlib_data,
				  xitk_skin_get_skin_filename(gGui->skin_config, "BackGround")))) {
    xine_error(_("%s(): couldn't find image for background\n"), __XINE_FUNCTION__);
    exit(-1);
  }
  
  hint.width  = new_img->rgb_width;
  hint.height = new_img->rgb_height;
  hint.flags  = PPosition | PSize;
  XSetWMNormalHints(gGui->display, gGui->panel_window, &hint);
  
  XResizeWindow (gGui->display, gGui->panel_window,
		 (unsigned int)new_img->rgb_width,
		 (unsigned int)new_img->rgb_height);
  
  XUnlockDisplay(gGui->display);

  while(!xitk_is_window_size(gGui->display, gGui->panel_window, 
			     new_img->rgb_width, new_img->rgb_height)) {
    xine_usec_sleep(10000);
  }
  
  old_img = panel->bg_image;
  panel->bg_image = new_img;

  XLockDisplay(gGui->display);

  if(!gGui->use_root_window && gGui->video_display == gGui->display)
    XSetTransientForHint(gGui->display, gGui->panel_window, gGui->video_window);

  Imlib_destroy_image(gGui->imlib_data, old_img);
  Imlib_apply_image(gGui->imlib_data, new_img, gGui->panel_window);
  
  XUnlockDisplay(gGui->display);

  if(panel_is_visible())
    raise_window(gGui->panel_window, 1, 1);

  xitk_skin_unlock(gGui->skin_config);
  
  xitk_change_skins_widget_list(panel->widget_list, gGui->skin_config);

  /*
   * Update position of dynamic buttons.
   */
  {
    int i = 0, x, y, dir, max;
    
    x   = xitk_skin_get_coord_x(gGui->skin_config, "AutoPlayGUI");
    y   = xitk_skin_get_coord_y(gGui->skin_config, "AutoPlayGUI");
    dir = xitk_skin_get_direction(gGui->skin_config, "AutoPlayGUI");
    max = xitk_skin_get_max_buttons(gGui->skin_config, "AutoPlayGUI");

    switch(dir) {
    case DIRECTION_UP:
    case DIRECTION_DOWN:
      while((max && ((i < max) && (panel->autoplay_plugins[i] != NULL))) || (!max && panel->autoplay_plugins[i] != NULL)) {
	
	(void) xitk_set_widget_pos(panel->autoplay_plugins[i], x, y);
	
	if(dir == DIRECTION_DOWN)
	  y += xitk_get_widget_height(panel->autoplay_plugins[i]) + 1;
	else
	  y -= (xitk_get_widget_height(panel->autoplay_plugins[i]) + 1);
	
	i++;
      }
      break;
    case DIRECTION_LEFT:
    case DIRECTION_RIGHT:
      while((max && ((i < max) && (panel->autoplay_plugins[i] != NULL))) || (!max && panel->autoplay_plugins[i] != NULL)) {
	
	(void) xitk_set_widget_pos(panel->autoplay_plugins[i], x, y);
	
	if(dir == DIRECTION_RIGHT)
	  x += xitk_get_widget_width(panel->autoplay_plugins[i]) + 1;
	else
	  x -= (xitk_get_widget_width(panel->autoplay_plugins[i]) + 1);
	
	i++;
      }
      break;
    }

    if(max) {
      while(panel->autoplay_plugins[i] != NULL) {
	xitk_disable_and_hide_widget(panel->autoplay_plugins[i]);
	i++;
      }
    }
  }
  
  enable_playback_controls(panel->playback_widgets.enabled);
  xitk_paint_widget_list(panel->widget_list);

  event_sender_move(panel->x + hint.width, panel->y);
}

/*
 * Update runtime displayed informations.
 */
void panel_update_runtime_display(void) {
  int seconds, pos, length, remain;
  char timestr[10], buffer[256];

  if(!panel_is_visible())
    return;

  if(!gui_xine_get_pos_length(gGui->stream, &pos, &seconds, &length)) {

    if((gGui->stream_length.pos || gGui->stream_length.time) && gGui->stream_length.length) {
      pos     = gGui->stream_length.pos;
      seconds = gGui->stream_length.time;
      length  = gGui->stream_length.length;
    }
    else
      return;

  }

  if(pos || seconds) {
    int days, rdays;
    
    remain  = (length - seconds) / 1000;
    seconds /= 1000;
    days    = seconds / (60*60*24);
    rdays   = remain / (60*60*24);

    if(panel->runtime_mode == 0) {
      if(days > 0)
	snprintf(timestr, sizeof(timestr), "% 4d::%02d", days, seconds / (60*60));
      else
	snprintf(timestr, sizeof(timestr), "%02d:%02d:%02d", seconds / (60*60), (seconds / 60) % 60, seconds % 60);
    }
    else
      if(remain < 0)
	snprintf(timestr, sizeof(timestr), "%s", "  :  :  ");
      else {
	if(rdays > 0)
	  snprintf(timestr, sizeof(timestr), "% 4d::%02d", rdays, remain / (60*60));
	else
	  snprintf(timestr, sizeof(timestr), "%02d:%02d:%02d", remain / (60*60), (remain / 60) % 60, remain % 60);
      }
    
  }
  else
    snprintf(timestr, sizeof(timestr), "%s", "--:--:--");
  
  if(length > 0) {
    int days;

    length /= 1000;
    days = length / (60*60*24);
    
    if(days > 0)
      snprintf(buffer, sizeof(buffer), "%s% 4d::%02d", _("Total time: "), days, length / (60*60));
    else
      snprintf(buffer, sizeof(buffer), "%s%02d:%02d:%02d", _("Total time: "), length / (60*60), (length / 60) % 60, length % 60);
  }
  else
    snprintf(buffer, sizeof(buffer), "%s%s", _("Total time: "), "??:??:??");
  
  xitk_set_widget_tips(panel->runtime_label, buffer);
  
  xitk_label_change_label(panel->runtime_label, timestr); 
}

/*
 * Update slider thread.
 */
static void *slider_loop(void *dummy) {
  int screensaver_timer = 0;
  int status, speed;
  int pos, secs;
  int i = 0;
  
  pthread_detach(pthread_self());

  while(gGui->on_quit == 0) {

    if(gGui->stream) {
      
      status = xine_get_status(gGui->stream);
      speed = xine_get_param(gGui->stream, XINE_PARAM_SPEED);
      
      pos = 0;

      if(status == XINE_STATUS_PLAY) {
	if(gui_xine_get_pos_length(gGui->stream, &pos, &secs, NULL)) {
	  secs /= 1000;

	  pthread_mutex_lock(&gGui->xe_mutex);

	  if(gGui->playlist.num && gGui->playlist.cur >= 0 && gGui->playlist.mmk &&
	     gGui->playlist.mmk[gGui->playlist.cur] && gGui->mmk.end != -1) {
	    if(secs >= gGui->playlist.mmk[gGui->playlist.cur]->end) {
	      gGui->ignore_next = 0;
	      gui_playlist_start_next();
	      pthread_mutex_unlock(&gGui->xe_mutex);
	      goto __next_iteration;
	    }
	  }
	  
	  if(gGui->playlist.num) {
	    if((xine_get_stream_info(gGui->stream, XINE_STREAM_INFO_SEEKABLE))) {
	      if(!xitk_is_widget_enabled(panel->playback_widgets.slider_play))
		xitk_enable_widget(panel->playback_widgets.slider_play);
	    }
	    else {
	      if(xitk_is_widget_enabled(panel->playback_widgets.slider_play)) {
		xitk_slider_reset(panel->playback_widgets.slider_play);
		xitk_disable_widget(panel->playback_widgets.slider_play);
	      }
	    }
	  }

	  pthread_mutex_unlock(&gGui->xe_mutex);
	}
	else
	  pos = -1;
	
      }
      
      if(!(i % 2)) {
	osd_update();
	
	if(gGui->mrl_overrided) {
	  gGui->mrl_overrided--;
	  if(gGui->mrl_overrided == 0)
	    panel_update_mrl_display();
	}
      }
      
      if((status == XINE_STATUS_PLAY) && (speed != XINE_SPEED_PAUSE)) {
	char *ident = stream_infos_get_ident_from_stream(gGui->stream);
	
	if(ident) {
	  if(gGui->playlist.num && gGui->playlist.cur >= 0 && gGui->playlist.mmk &&
	     gGui->playlist.mmk[gGui->playlist.cur]) {
	    if(strcmp(gGui->mmk.ident, ident)) {
	      if(gGui->mmk.ident)
		free(gGui->mmk.ident);
	      if(gGui->playlist.mmk[gGui->playlist.cur]->ident)
		free(gGui->playlist.mmk[gGui->playlist.cur]->ident);
	      
	      gGui->mmk.ident = strdup(ident);
	      gGui->playlist.mmk[gGui->playlist.cur]->ident = strdup(ident);
	      
	      video_window_set_mrl(gGui->mmk.ident);
	      playlist_mrlident_toggle();
	      panel_update_mrl_display();
	    }
	  }
	  free(ident);
	}
	else
	  video_window_set_mrl((char *)gGui->mmk.mrl);
	
	if(!xitk_is_window_iconified(gGui->video_display, gGui->video_window)) {
	  
	  if(gGui->ssaver_timeout) {
	    
	    if(!(i % 2))
	      screensaver_timer++;
	    
	    if(screensaver_timer >= gGui->ssaver_timeout) {
	      screensaver_timer = 0;
	      video_window_reset_ssaver();
	      
	    }
	  }  
	}

	if(gGui->logo_mode == 0) {
	  
	  if(panel_is_visible()) {

	    panel_update_runtime_display();
	    
	    if(xitk_is_widget_enabled(panel->playback_widgets.slider_play)) {
	      if(pos >= 0)
		xitk_slider_set_pos(panel->playback_widgets.slider_play, pos);
	    }
	    
	    if(!(i % 20)) {
	      int level = 0;
	      
	      panel_update_channel_display();
	      
	      if((gGui->mixer.method == SOUND_CARD_MIXER) &&
		 (gGui->mixer.caps & MIXER_CAP_VOL)) {
		level = gGui->mixer.volume_level = 
		  xine_get_param(gGui->stream, XINE_PARAM_AUDIO_VOLUME);
	      }
	      else if(gGui->mixer.method == SOFTWARE_MIXER) {
		level = gGui->mixer.amp_level = 
		  xine_get_param(gGui->stream, XINE_PARAM_AUDIO_AMP_LEVEL);
	      }
	      
	      xitk_slider_set_pos(panel->mixer.slider, level);
	      panel_check_mute();
	      
	      i = 0;
	    }
	    
	  }
	  
	  if(stream_infos_is_visible() && gGui->stream_info_auto_update)
	    stream_infos_update_infos();

	}
      }
    }
    
    if(gGui->cursor_visible) {
      if(!(i % 2))
	video_window_set_cursor_timer(video_window_get_cursor_timer() + 1);
      
      if(video_window_get_cursor_timer() >= 5) {
	gGui->cursor_visible = !gGui->cursor_visible;
	video_window_set_cursor_visibility(gGui->cursor_visible);
      }
    }
    
    if(gGui->logo_has_changed)
      video_window_update_logo();
    
  __next_iteration:
    xine_usec_sleep(500000.0);
    i++;
  }

  pthread_exit(NULL);
  return NULL;
}

/*
 * Boolean about panel visibility.
 */
int panel_is_visible(void) {

  if(panel) {
    if(gGui->use_root_window)
      return xitk_is_window_visible(gGui->display, gGui->panel_window);
    else
      return panel->visible && xitk_is_window_visible(gGui->display, gGui->panel_window);
  }

  return 0;
}

/*
 * Show/Hide panel window.
 */
static void _panel_toggle_visibility (xitk_widget_t *w, void *data) {
  int visible = xitk_is_window_visible(gGui->display, gGui->panel_window);

  if(((!panel->visible || !visible) && !playlist_is_visible()) || (visible && playlist_is_visible()))
    playlist_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !control_is_visible()) || (visible && control_is_visible()))
    control_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !mrl_browser_is_visible()) || (visible && mrl_browser_is_visible()))
    mrl_browser_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !setup_is_visible()) || (visible && setup_is_visible()))
    setup_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !viewlog_is_visible()) || (visible && viewlog_is_visible()))
    viewlog_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !kbedit_is_visible()) || (visible && kbedit_is_visible()))
    kbedit_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !event_sender_is_visible()) || (visible && event_sender_is_visible()))
    event_sender_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !stream_infos_is_visible()) || (visible && stream_infos_is_visible()))
    stream_infos_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !tvset_is_visible()) || (visible && tvset_is_visible()))
    tvset_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !vpplugin_is_visible()) || (visible && vpplugin_is_visible()))
    vpplugin_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !applugin_is_visible()) || (visible && applugin_is_visible()))
    applugin_toggle_visibility(NULL, NULL);

  if(((!panel->visible || !visible) && !help_is_visible()) || (visible && help_is_visible()))
    help_toggle_visibility(NULL, NULL);

  if (panel->visible && gGui->video_display == gGui->display) {
    
    XLockDisplay(gGui->display);
    
    if (video_window_is_visible ()) {
      if(gGui->use_root_window) { /* Using root window */
	if(visible)
	  XIconifyWindow(gGui->display, gGui->panel_window, gGui->screen);
	else
	  XMapWindow(gGui->display, gGui->panel_window);
      }
      else {
	panel->visible = 0;
	XUnmapWindow (gGui->display, gGui->panel_window);
	XSync(gGui->display, False);
	XUnlockDisplay(gGui->display);
	xitk_hide_widgets(panel->widget_list);
	XLockDisplay(gGui->display);
      }
    }
    else {
      if(visible)
	XIconifyWindow(gGui->display, gGui->panel_window, (XDefaultScreen(gGui->display)));
      else
	XMapWindow(gGui->display, gGui->panel_window);
    }
    
    if(gGui->cursor_grabbed)
      XGrabPointer(gGui->video_display, gGui->video_window, 1, None, GrabModeAsync, GrabModeAsync, gGui->video_window, None, CurrentTime);
    
    /* Give focus to video output window */
    try_to_set_input_focus(gGui->video_window);
    
    XUnlockDisplay(gGui->display);
     
  }
  else {

    panel->visible = 1;
    gGui->nongui_error_msg = NULL;
    xitk_show_widgets(panel->widget_list);
    
    XLockDisplay(gGui->display);
    
    XRaiseWindow(gGui->display, gGui->panel_window); 
    XMapWindow(gGui->display, gGui->panel_window); 
    if(!gGui->use_root_window && gGui->video_display == gGui->display)
      XSetTransientForHint (gGui->display, gGui->panel_window, gGui->video_window);
    XUnlockDisplay (gGui->display);

    wait_for_window_visible(gGui->display, gGui->panel_window);
    layer_above_video(gGui->panel_window);
     
    if(gGui->cursor_grabbed) {
      XLockDisplay (gGui->display);
      XUngrabPointer(gGui->display, CurrentTime);
      XUnlockDisplay (gGui->display);
    }
    
#if defined(HAVE_XINERAMA) || defined(HAVE_XF86VIDMODE)
    if(
#ifdef HAVE_XINERAMA
       (((video_window_get_fullscreen_mode()) & (WINDOWED_MODE | FULLSCR_MODE)) &&
	(!((video_window_get_fullscreen_mode()) & FULLSCR_XI_MODE)))
#ifdef HAVE_XF86VIDMODE
       ||
#endif
#endif
#ifdef HAVE_XF86VIDMODE
       (gGui->XF86VidMode_fullscreen)
#endif
       ) {
      int x, y, w, h, desktopw, desktoph;
      
      xitk_get_window_position(gGui->display, gGui->panel_window, &x, &y, &w, &h);
      
      XLockDisplay(gGui->display);
      desktopw = DisplayWidth(gGui->display, gGui->screen);
      desktoph = DisplayHeight(gGui->display, gGui->screen);
      XUnlockDisplay(gGui->display);
      
      if(((x + w) <= 0) || ((y + h) <= 0) || (x >= desktopw) || (y >= desktoph)) {
	int newx, newy;
	
	newx = (desktopw - w) >> 1;
	newy = (desktoph - h) >> 1;
	
	XLockDisplay(gGui->display);
	XMoveWindow(gGui->display, gGui->panel_window, newx, newy);
	XUnlockDisplay(gGui->display);
	
	panel_store_new_position(newx, newy, w, h);
      }
    }
#endif
    
    if(gGui->logo_mode == 0) {
      int pos;
      
      if(xitk_is_widget_enabled(panel->playback_widgets.slider_play)) {
	if(gui_xine_get_pos_length(gGui->stream, &pos, NULL, NULL))
	  xitk_slider_set_pos(panel->playback_widgets.slider_play, pos);
	panel_update_runtime_display();
      }

      panel_update_mrl_display();
    }
    
  }
}

void panel_toggle_visibility (xitk_widget_t *w, void *data) {
  _panel_toggle_visibility(w, data);
  config_update_num ("gui.panel_visible", panel->visible);
}

void panel_check_mute(void) {
  xitk_checkbox_set_state(panel->mixer.mute, gGui->mixer.mute);
}

/*
 * Check and set the correct state of pause button.
 */
void panel_check_pause(void) {
  
  xitk_checkbox_set_state(panel->playback_widgets.pause, 
	  (((xine_get_status(gGui->stream) == XINE_STATUS_PLAY) && 
	    (xine_get_param(gGui->stream, XINE_PARAM_SPEED) == XINE_SPEED_PAUSE)) ? 1 : 0));
  
}

void panel_reset_runtime_label(void) {
  if(panel->runtime_mode == 0)
    xitk_label_change_label (panel->runtime_label, "00:00:00"); 
  else
    xitk_label_change_label (panel->runtime_label, "..:..:.."); 
}

static void _panel_change_display_mode(xitk_widget_t *w, void *data) {
  gGui->is_display_mrl = !gGui->is_display_mrl;
  panel_update_mrl_display();
  playlist_mrlident_toggle();
}
static void _panel_change_time_label(xitk_widget_t *w, void *data) {
  panel->runtime_mode = !panel->runtime_mode;
  panel_update_runtime_display();
}

/*
 * Reset the slider of panel window (set to 0).
 */
void panel_reset_slider (void) {
  xitk_slider_reset(panel->playback_widgets.slider_play);
  panel_reset_runtime_label();
}

/*
 * Update audio/spu channel displayed informations.
 */
void panel_update_channel_display (void) {
  int   channel;
  char  buffer[XINE_LANG_MAX];
  char *lang = NULL;

  memset(&buffer, 0, sizeof(buffer));
  channel = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
  switch (channel) {
  case -2:
    lang = "off";
    break;

  case -1:
    if(!xine_get_audio_lang (gGui->stream, channel, &buffer[0]))
      lang = "auto";
    else
      lang = buffer;
    break;

  default:
    if(!xine_get_audio_lang (gGui->stream, channel, &buffer[0]))
      snprintf(buffer, sizeof(buffer), "%3d", channel);
    lang = buffer;
    break;
  }
  xitk_label_change_label (panel->audiochan_label, lang);

  memset(&buffer, 0, sizeof(buffer));
  channel = xine_get_param(gGui->stream, XINE_PARAM_SPU_CHANNEL);
  switch (channel) {
  case -2:
    lang = "off";
    break;

  case -1:
    if(!xine_get_spu_lang (gGui->stream, channel, &buffer[0]))
      lang = "auto";
    else
      lang = buffer;
    break;

  default:
    if(!xine_get_spu_lang (gGui->stream, channel, &buffer[0]))
      snprintf(buffer, sizeof(buffer), "%3d", channel);
    lang = buffer;
    break;
  }
  xitk_label_change_label (panel->spuid_label, lang);
}

static void panel_audio_lang_list(xitk_widget_t *w, void *data) {
  int x, y;
  int wx, wy;

  xitk_get_window_position(gGui->display, gGui->panel_window, &wx, &wy, NULL, NULL);
  xitk_get_widget_pos(panel->audiochan_label, &x, &y);
  x += wx;
  y += (wy + xitk_get_widget_height(panel->audiochan_label));
  audio_lang_menu(panel->widget_list, x, y);
}

static void panel_spu_lang_list(xitk_widget_t *w, void *data) {
  int x, y;
  int wx, wy;

  xitk_get_window_position(gGui->display, gGui->panel_window, &wx, &wy, NULL, NULL);
  xitk_get_widget_pos(panel->spuid_label, &x, &y);
  x += wx;
  y += (wy + xitk_get_widget_height(panel->spuid_label));
  spu_lang_menu(panel->widget_list, x, y);
}
/*
 * Update displayed MRL according to the current one.
 */
void panel_update_mrl_display (void) {
  panel_set_title((gGui->is_display_mrl) ? gGui->mmk.mrl : gGui->mmk.ident);
}

/*
 *
 */
void panel_toggle_audio_mute(xitk_widget_t *w, void *data, int state) {

  if(gGui->mixer.method == SOFTWARE_MIXER) {
    gGui->mixer.mute = state;
    xine_set_param(gGui->stream, XINE_PARAM_AUDIO_AMP_MUTE, gGui->mixer.mute);
    osd_display_info(_("Amp: %s"), gGui->mixer.mute ? _("Muted") : _("Unmuted"));
  }
  else if(gGui->mixer.caps & MIXER_CAP_MUTE) {
    gGui->mixer.mute = state;
    xine_set_param(gGui->stream, XINE_PARAM_AUDIO_MUTE, gGui->mixer.mute);
    osd_display_info(_("Audio: %s"), gGui->mixer.mute ? _("Muted") : _("Unmuted"));
  }
  panel_check_mute();
}

/*
 *  Use internal xine-lib framegrabber function
 *  to snapshot current frame.
 */
static void panel_snapshot_error(void *data, char *message) {
  xine_error(message);
}
static void panel_snapshot_info(void *data, char *message) {
  xine_info(message);
}
void panel_snapshot(xitk_widget_t *w, void *data) {
  create_snapshot(gGui->mmk.mrl, panel_snapshot_error, panel_snapshot_info, NULL);
}

/*
 * Handle paddle moving of slider.
 */
static void panel_slider_cb(xitk_widget_t *w, void *data, int pos) {

  if(w == panel->playback_widgets.slider_play) {
    if(xitk_is_widget_enabled(panel->playback_widgets.slider_play)) {
      gui_set_current_position (pos);
      if(xine_get_status(gGui->stream) != XINE_STATUS_PLAY) {
	panel_reset_slider();
      }
      else {
	int pos;
	
	if(gui_xine_get_pos_length(gGui->stream, &pos, NULL, NULL))
	  xitk_slider_set_pos(panel->playback_widgets.slider_play, pos);
	
	panel_update_runtime_display();
      }
    }
  }
  else if(w == panel->mixer.slider) {

    if(gGui->mixer.method == SOUND_CARD_MIXER)
      change_audio_vol(pos);
    else if(gGui->mixer.method == SOFTWARE_MIXER)
      change_amp_vol(pos);
    
  }
  
  panel_check_pause();
}

/*
 * Handle X events here.
 */
static void panel_handle_event(XEvent *event, void *data) {

  switch(event->type) {
  case ButtonPress:
    {
      XButtonEvent *bevent = (XButtonEvent *) event;

      if(bevent->button == Button3)
	video_window_menu(panel->widget_list);
    }
    break;
    
  case KeyPress:
  case ButtonRelease:
    gui_handle_event(event, data);
    break;

  case MappingNotify:
    XLockDisplay(gGui->display);
    XRefreshKeyboardMapping((XMappingEvent *) event);
    XUnlockDisplay(gGui->display);
    break;

  case MapNotify:
    /* When panel becomes visible by any means,               */
    /* all other hidden GUI windows shall also become visible */
    if(!playlist_is_visible())
      playlist_toggle_visibility(NULL, NULL);
    if(!control_is_visible())
      control_toggle_visibility(NULL, NULL);
    if(!mrl_browser_is_visible())
      mrl_browser_toggle_visibility(NULL, NULL);
    if(!setup_is_visible())
      setup_toggle_visibility(NULL, NULL);
    if(!viewlog_is_visible())
      viewlog_toggle_visibility(NULL, NULL);
    if(!kbedit_is_visible())
      kbedit_toggle_visibility(NULL, NULL);
    if(!event_sender_is_visible())
      event_sender_toggle_visibility(NULL, NULL);
    if(!stream_infos_is_visible())
      stream_infos_toggle_visibility(NULL, NULL);
    if(!tvset_is_visible())
      tvset_toggle_visibility(NULL, NULL);
    if(!vpplugin_is_visible())
      vpplugin_toggle_visibility(NULL, NULL);
    if(!applugin_is_visible())
      applugin_toggle_visibility(NULL, NULL);
    if(!help_is_visible())
      help_toggle_visibility(NULL, NULL);
    break;
  }
  
}

/*
 * Create buttons from information if input plugins autoplay featured. 
 * We couldn't do this into panel_init(), this function is
 * called before xine engine initialization.
 */
void panel_add_autoplay_buttons(void) {
  int                        x, y, dir;
  int                        i = 0, max;
  xitk_labelbutton_widget_t  lb;
  const char *const         *autoplay_plugins = xine_get_autoplay_input_plugin_ids(gGui->xine);
  const char                *autoplay_label;
  
  XITK_WIDGET_INIT(&lb, gGui->imlib_data);

  x   = xitk_skin_get_coord_x(gGui->skin_config, "AutoPlayGUI");
  y   = xitk_skin_get_coord_y(gGui->skin_config, "AutoPlayGUI");
  dir = xitk_skin_get_direction(gGui->skin_config, "AutoPlayGUI");
  max = xitk_skin_get_max_buttons(gGui->skin_config, "AutoPlayGUI");

  if(autoplay_plugins) {
    autoplay_label = *autoplay_plugins++;
    while(autoplay_label) {
      
      lb.skin_element_name = "AutoPlayGUI";
      lb.button_type       = CLICK_BUTTON;
      lb.label             = (char *)autoplay_label;
      lb.callback          = playlist_scan_input;
      lb.state_callback    = NULL;
      lb.userdata          = NULL;
      xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)),
				(panel->autoplay_plugins[i] =
				 xitk_labelbutton_create (panel->widget_list, 
							  gGui->skin_config, &lb)));
      xitk_set_widget_tips_and_timeout(panel->autoplay_plugins[i],
				       (char *) xine_get_input_plugin_description(gGui->xine, autoplay_label),
				       panel->tips.timeout);
      
      if(!panel->tips.enable)
	xitk_disable_widget_tips(panel->autoplay_plugins[i]);
      
      (void) xitk_set_widget_pos(panel->autoplay_plugins[i], x, y);
  
      switch(dir) {
      case DIRECTION_UP:
      case DIRECTION_DOWN:
	if(dir == DIRECTION_DOWN)
	  y += xitk_get_widget_height(panel->autoplay_plugins[i]) + 1;
	else
	  y -= (xitk_get_widget_height(panel->autoplay_plugins[i]) + 1);
	break;
      case DIRECTION_LEFT:
      case DIRECTION_RIGHT:
	if(dir == DIRECTION_RIGHT)
	  x += xitk_get_widget_width(panel->autoplay_plugins[i]) + 1;
	else
	  x -= (xitk_get_widget_width(panel->autoplay_plugins[i]) + 1);
	break;
      }
      
      if(max && (i >= max))
	xitk_disable_and_hide_widget(panel->autoplay_plugins[i]);
      
      i++;
      
      autoplay_label = *autoplay_plugins++;
    }
  }
  
  if(i)
    panel->autoplay_plugins[i+1] = NULL;
  
}

/*
 * Check if there a mixer control available,
 */
void panel_add_mixer_control(void) {
  
  gGui->mixer.caps = MIXER_CAP_NOTHING;

  if(gGui->ao_port) {
    if((xine_get_param(gGui->stream, XINE_PARAM_AUDIO_VOLUME)) != -1)
      gGui->mixer.caps |= MIXER_CAP_VOL;
    if((xine_get_param(gGui->stream, XINE_PARAM_AUDIO_MUTE)) != -1)
      gGui->mixer.caps |= MIXER_CAP_MUTE;
  }
  
  if(((gGui->mixer.method == SOUND_CARD_MIXER) && gGui->mixer.caps & MIXER_CAP_VOL) ||
     (gGui->mixer.method == SOFTWARE_MIXER)) {
    int level = 0;

    xitk_enable_widget(panel->mixer.slider);
    
    if(gGui->mixer.method == SOUND_CARD_MIXER)
      level = gGui->mixer.volume_level = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_VOLUME);
    else if(gGui->mixer.method == SOFTWARE_MIXER)
      level = gGui->mixer.amp_level = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_AMP_LEVEL);
    
    xitk_slider_set_pos(panel->mixer.slider, level);
  }

  if(gGui->mixer.caps & MIXER_CAP_MUTE) {
    xitk_enable_widget(panel->mixer.mute);
    gGui->mixer.mute = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_MUTE);
    xitk_checkbox_set_state(panel->mixer.mute, gGui->mixer.mute);
  }

  /* Tips should be available only if widgets are enabled */
  if(gGui->mixer.caps & MIXER_CAP_VOL)
    xitk_set_widget_tips_and_timeout(panel->mixer.slider, _("Volume control"), panel->tips.timeout);
  if(gGui->mixer.caps & MIXER_CAP_MUTE)
    xitk_set_widget_tips_and_timeout(panel->mixer.mute, _("Mute toggle"), panel->tips.timeout);

  if(!panel->tips.enable) {
    xitk_disable_widget_tips(panel->mixer.slider);
    xitk_disable_widget_tips(panel->mixer.mute);
  }

}

void panel_deinit(void) {
  if(panel_is_visible())
    _panel_toggle_visibility(NULL, NULL);
  panel_exit(NULL, NULL);
}

void panel_reparent(void) {
  if(panel) {
    reparent_window(gGui->panel_window);
  }
}

/*
 * Create the panel window, and fit all widgets in.
 */
void panel_init (void) {
  GC                        gc;
  XSizeHints                hint;
  XWMHints                 *wm_hint;
  XSetWindowAttributes      attr;
  char                     *title;
  Atom                      prop;
  MWMHints                  mwmhints;
  XClassHint               *xclasshint;
  xitk_button_widget_t      b;
  xitk_checkbox_widget_t    cb;
  xitk_label_widget_t       lbl;
  xitk_slider_widget_t      sl;
  xitk_widget_t            *w;
  
  xine_strdupa(title, _("xine Panel"));

  XITK_WIDGET_INIT(&b, gGui->imlib_data);
  XITK_WIDGET_INIT(&cb, gGui->imlib_data);
  XITK_WIDGET_INIT(&lbl, gGui->imlib_data);
  XITK_WIDGET_INIT(&sl, gGui->imlib_data);

  panel = (_panel_t *) xine_xmalloc(sizeof(_panel_t));

  panel->playback_widgets.enabled = -1;

  panel->skin_on_change = 0;

  XLockDisplay (gGui->display);
  
  /*
   * load bg image before opening window, so we can determine it's size
   */
  if (!(panel->bg_image = 
	Imlib_load_image(gGui->imlib_data,
			 xitk_skin_get_skin_filename(gGui->skin_config, "BackGround")))) {
    xine_error(_("panel: couldn't find image for background\n"));
    exit(-1);
  }

  XUnlockDisplay(gGui->display);

  /*
   * open the panel window
   */

  panel->x = hint.x = xine_config_register_num (gGui->xine, "gui.panel_x", 
						200,
						CONFIG_NO_DESC,
						CONFIG_NO_HELP,
						CONFIG_LEVEL_DEB,
						CONFIG_NO_CB,
						CONFIG_NO_DATA);
  panel->y = hint.y = xine_config_register_num (gGui->xine, "gui.panel_y",
						100,
						CONFIG_NO_DESC,
						CONFIG_NO_HELP,
						CONFIG_LEVEL_DEB,
						CONFIG_NO_CB,
						CONFIG_NO_DATA);

  hint.width = panel->bg_image->rgb_width;
  hint.height = panel->bg_image->rgb_height;
  hint.flags = PPosition | PSize;
  
  attr.override_redirect = False;
  attr.background_pixel  = gGui->black.pixel;
  /*
   * XXX:multivis
   * To avoid BadMatch errors on XCreateWindow:
   * If the parent and the new window have different depths, we must supply either
   * a BorderPixmap or a BorderPixel.
   * If the parent and the new window use different visuals, we must supply a
   * Colormap
   */
  attr.border_pixel      = gGui->black.pixel;

  XLockDisplay(gGui->display);
  attr.colormap          = Imlib_get_colormap(gGui->imlib_data);
  /*  
      printf ("imlib_data: %d visual : %d\n",gGui->imlib_data,gGui->imlib_data->x.visual);
      printf ("w : %d h : %d\n",hint.width, hint.height);
  */
  
  gGui->panel_window = XCreateWindow (gGui->display, 
				      gGui->imlib_data->x.root, 
				      hint.x, hint.y,
				      hint.width, hint.height, 0, 
				      gGui->imlib_data->x.depth,
				      InputOutput,
				      gGui->imlib_data->x.visual,
				      CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect,
				      &attr);

  XmbSetWMProperties(gGui->display, gGui->panel_window, title, title, NULL, 0,
                     &hint, NULL, NULL);

  XSelectInput(gGui->display, gGui->panel_window, INPUT_MOTION | KeymapStateMask);
  XUnlockDisplay(gGui->display);
  
  if(!video_window_is_visible())
    xitk_set_wm_window_type(gGui->panel_window, WINDOW_TYPE_NORMAL);
  else
    xitk_unset_wm_window_type(gGui->panel_window, WINDOW_TYPE_NORMAL);
  
  if(is_layer_above())
    xitk_set_layer_above(gGui->panel_window);
  
  /*
   * wm, no border please
   */
  
  XLockDisplay(gGui->display);
  prop = XInternAtom(gGui->display, "_MOTIF_WM_HINTS", False);
  mwmhints.flags = MWM_HINTS_DECORATIONS;
  mwmhints.decorations = 0;

  XChangeProperty(gGui->display, gGui->panel_window, prop, prop, 32,
                  PropModeReplace, (unsigned char *) &mwmhints,
                  PROP_MWM_HINTS_ELEMENTS);
  
  if(!gGui->use_root_window && gGui->video_display == gGui->display)
    XSetTransientForHint (gGui->display, gGui->panel_window, gGui->video_window);

  /* 
   * set wm properties 
   */

  if((xclasshint = XAllocClassHint()) != NULL) {
    xclasshint->res_name = title;
    xclasshint->res_class = "xine";
    XSetClassHint(gGui->display, gGui->panel_window, xclasshint);
    XFree(xclasshint);
  }

  wm_hint = XAllocWMHints();
  if (wm_hint != NULL) {
    wm_hint->input         = True;
    wm_hint->initial_state = NormalState;
    wm_hint->icon_pixmap   = gGui->icon;
    wm_hint->flags         = InputHint | StateHint | IconPixmapHint;
    XSetWMHints(gGui->display, gGui->panel_window, wm_hint);
    XFree(wm_hint);
  }

  /*
   * set background image
   */
  
  gc = XCreateGC(gGui->display, gGui->panel_window, 0, 0);

  Imlib_apply_image(gGui->imlib_data, panel->bg_image, gGui->panel_window);
  XUnlockDisplay(gGui->display);

  /*
   * Widget-list
   */

  panel->widget_list = xitk_widget_list_new();
  xitk_widget_list_set(panel->widget_list, WIDGET_LIST_LIST, (xitk_list_new()));
  xitk_widget_list_set(panel->widget_list, WIDGET_LIST_WINDOW, (void *) gGui->panel_window);
  xitk_widget_list_set(panel->widget_list, WIDGET_LIST_GC, gc);
 
  lbl.window    = (XITK_WIDGET_LIST_WINDOW(panel->widget_list));
  lbl.gc        = (XITK_WIDGET_LIST_GC(panel->widget_list));

  /* Prev button */
  b.skin_element_name = "Prev";
  b.callback          = gui_nextprev;
  b.userdata          = (void *)GUI_PREV;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.prev = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));

  /*  Stop button */
  b.skin_element_name = "Stop";
  b.callback          = gui_stop;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.stop = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(panel->playback_widgets.stop, _("Stop playback"));
  
  /*  Play button */
  b.skin_element_name = "Play";
  b.callback          = gui_play;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.play = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(panel->playback_widgets.play, _("Play selected entry"));

  /*  Pause button */
  cb.skin_element_name = "Pause";
  cb.callback          = gui_pause;
  cb.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.pause = xitk_checkbox_create(panel->widget_list, gGui->skin_config, &cb)));
  xitk_set_widget_tips(panel->playback_widgets.pause, _("Pause/Resume playback"));
  
  /*  Next button */
  b.skin_element_name = "Next";
  b.callback          = gui_nextprev;
  b.userdata          = (void *)GUI_NEXT;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.next = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));

  /*  Eject button */
  b.skin_element_name = "Eject";
  b.callback          = gui_eject;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
   (panel->playback_widgets.eject = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(panel->playback_widgets.eject, _("Eject current medium"));

  /*  Exit button */
  b.skin_element_name = "Exit";
  b.callback          = gui_exit;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)),
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Quit"));
 
  /*  Setup button */
  b.skin_element_name = "Setup";
  b.callback          = gui_setup_show;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Setup window"));

  /*  Event sender button */
  b.skin_element_name = "Nav";
  b.callback          = gui_event_sender_show;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Navigator"));
  
  /*  Close button */
  b.skin_element_name = "Close";
  b.callback          = panel_toggle_visibility;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)),
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Hide GUI"));

  /*  Fullscreen button */
  b.skin_element_name = "FullScreen";
  b.callback          = gui_set_fullscreen_mode;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Fullscreen/Window mode"));

  /*  Next audio channel */
  b.skin_element_name = "AudioNext";
  b.callback          = gui_change_audio_channel;
  b.userdata          = (void *)GUI_NEXT;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Next audio channel"));

  /*  Prev audio channel */
  b.skin_element_name = "AudioPrev";
  b.callback          = gui_change_audio_channel;
  b.userdata          = (void *)GUI_PREV;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Previous audio channel"));

  /*  Prev spuid */
  b.skin_element_name = "SpuNext";
  b.callback          = gui_change_spu_channel;
  b.userdata          = (void *)GUI_NEXT;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Next SPU channel"));

  /*  Next spuid */
  b.skin_element_name = "SpuPrev";
  b.callback          = gui_change_spu_channel;
  b.userdata          = (void *)GUI_PREV;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Previous SPU channel"));

  /*  Label title */
  lbl.skin_element_name = "TitleLabel";
  lbl.label             = "";
  lbl.callback          = _panel_change_display_mode;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->title_label = xitk_label_create (panel->widget_list, gGui->skin_config, &lbl)));

  /*  Runtime label */
  lbl.skin_element_name = "TimeLabel";
  lbl.label             = "00:00:00";
  lbl.callback          = _panel_change_time_label;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->runtime_label = xitk_label_create (panel->widget_list, gGui->skin_config, &lbl)));
  xitk_set_widget_tips(panel->runtime_label, _("Total time: --:--:--"));
  /* 
   * Init to default, otherwise if panel is hide
   * at startup, label is empty 'till it's updated
   */
  panel->runtime_mode   = 0;
  panel_reset_runtime_label();

  /*  Audio channel label */
  lbl.skin_element_name = "AudioLabel";
  lbl.label             = "";
  lbl.callback          = panel_audio_lang_list;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->audiochan_label = xitk_label_create (panel->widget_list, gGui->skin_config, &lbl)));

  /*  Spuid label */
  lbl.skin_element_name = "SpuLabel";
  lbl.label             = "";
  lbl.callback          = panel_spu_lang_list;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->spuid_label = xitk_label_create (panel->widget_list, gGui->skin_config, &lbl)));

  /*  slider seek */
  sl.skin_element_name = "SliderPlay";
  sl.min               = 0;
  sl.max               = 65535;
  sl.step              = 1;
  sl.callback          = NULL;
  sl.userdata          = NULL;
  sl.motion_callback   = panel_slider_cb;
  sl.motion_userdata   = NULL;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
    (panel->playback_widgets.slider_play = xitk_slider_create(panel->widget_list, gGui->skin_config, &sl)));
  
  xitk_widget_keyable(panel->playback_widgets.slider_play, 0);

  xitk_set_widget_tips(panel->playback_widgets.slider_play, _("Stream playback position slider"));
  xitk_slider_reset(panel->playback_widgets.slider_play);
  
  if(!gGui->playlist.num)
    xitk_disable_widget(panel->playback_widgets.slider_play);
  
  /* Mixer volume slider */
  sl.skin_element_name = "SliderVol";
  sl.min               = 0;
  sl.max               = (gGui->mixer.method == SOUND_CARD_MIXER) ? 100 : 200;
  sl.step              = 1;
  sl.callback          = NULL;
  sl.userdata          = NULL;
  sl.motion_callback   = panel_slider_cb;
  sl.motion_userdata   = NULL;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->mixer.slider = xitk_slider_create(panel->widget_list, gGui->skin_config, &sl)));
  xitk_slider_reset(panel->mixer.slider);
  xitk_disable_widget(panel->mixer.slider);

  /*  Mute toggle */
  cb.skin_element_name = "Mute";
  cb.callback          = panel_toggle_audio_mute;
  cb.userdata          = NULL;
  xitk_list_append_content ((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
	   (panel->mixer.mute = xitk_checkbox_create (panel->widget_list, gGui->skin_config, &cb)));
  xitk_disable_widget(panel->mixer.mute);

  /* Snapshot */
  b.skin_element_name = "Snapshot";
  b.callback          = panel_snapshot;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Take a snapshot"));

  /*  Playback speed slow */
  b.skin_element_name = "PlaySlow";
  b.callback          = gui_change_speed_playback;
  b.userdata          = (void *)GUI_NEXT;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Slow motion"));

  /*  Playback speed fast */
  b.skin_element_name = "PlayFast";
  b.callback          = gui_change_speed_playback;
  b.userdata          = (void *)GUI_PREV;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Fast motion"));
  
  /*  Playlist button */
  b.skin_element_name = "PlBtn";
  b.callback          = gui_playlist_show;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Playlist"));
  
  /*  Control button */
  b.skin_element_name = "CtlBtn";
  b.callback          = gui_control_show;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Control"));

  /*  Mrl button */
  b.skin_element_name = "MrlBtn";
  b.callback          = gui_mrlbrowser_show;
  b.userdata          = NULL;
  xitk_list_append_content((XITK_WIDGET_LIST_LIST(panel->widget_list)), 
			   (w = xitk_button_create(panel->widget_list, gGui->skin_config, &b)));
  xitk_set_widget_tips(w, _("Open Location"));
  

  panel->tips.enable = xine_config_register_bool(gGui->xine, "gui.tips_visible", 
						 1,
						 _("gui tips visibility"), 
						 _("If disabled, no tooltips are shown."), 
						 CONFIG_LEVEL_ADV,
						 panel_enable_tips_cb,
						 CONFIG_NO_DATA);
  panel->tips.timeout = (unsigned long) xine_config_register_num(gGui->xine, "gui.tips_timeout", 
								 5000,
								 _("Tips timeout (ms)"), 
								 _("Persistence time of tooltips, in milliseconds."), 
								 CONFIG_LEVEL_ADV,
								 panel_timeout_tips_cb, 
								 CONFIG_NO_DATA);

  panel_update_mrl_display();
  panel_update_nextprev_tips();

  /* 
   * show panel 
   */
  {
    int visible = xine_config_register_bool(gGui->xine, "gui.panel_visible", 
					    1,
					    _("gui panel visibility"),
					    CONFIG_NO_HELP,
					    CONFIG_LEVEL_DEB,
					    CONFIG_NO_CB,
					    CONFIG_NO_DATA);

      panel->visible = (!gGui->no_gui) ? visible : 0;
  }
  
  /*  The user don't want panel on startup */
  if(panel->visible && (actions_on_start(gGui->actions_on_start, ACTID_TOGGLE_VISIBLITY))) {
    panel->visible = !panel->visible;
    config_update_num ("gui.panel_visible", panel->visible);
  }
  
  if((gGui->use_root_window || gGui->video_display != gGui->display) && (!panel->visible))
    panel->visible = 1;
  
  if (panel->visible) {
    XLockDisplay(gGui->display);
    XRaiseWindow(gGui->display, gGui->panel_window); 
    XMapWindow(gGui->display, gGui->panel_window); 
    XUnlockDisplay(gGui->display);
  }
  else
    xitk_hide_widgets(panel->widget_list);
  
  
  panel->widget_key = xitk_register_event_handler("panel", 
						  gGui->panel_window, 
						  panel_handle_event,
						  panel_store_new_position,
						  gui_dndcallback,
						  panel->widget_list,
						  NULL);

  gGui->cursor_visible = 1;
  video_window_set_cursor_visibility(gGui->cursor_visible);
  
  {
    pthread_attr_t       pth_attrs;
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
    struct sched_param   pth_params;
#endif
    
    pthread_attr_init(&pth_attrs);

    /* this won't work on linux, freebsd 5.0 */
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
    pthread_attr_getschedparam(&pth_attrs, &pth_params);
    pth_params.sched_priority = sched_get_priority_min(SCHED_OTHER);
    pthread_attr_setschedparam(&pth_attrs, &pth_params);
#endif
    
    pthread_create(&panel->slider_thread, &pth_attrs, slider_loop, NULL);
  }

  if(panel->visible)
    try_to_set_input_focus(gGui->panel_window);
}

void panel_set_title(char *title) {
  if(panel && panel->title_label)
    xitk_label_change_label(panel->title_label, title);
}
