vlcplugin_gtk.cpp 9.26 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
#include "vlcplugin_gtk.h"
#include <gdk/gdkx.h>
#include <cstring>

static uint32_t getXid(GtkWidget *widget) {
    GdkDrawable *video_drawable = gtk_widget_get_window(widget);
    return (uint32_t)gdk_x11_drawable_get_xid(video_drawable);
}

VlcPluginGtk::VlcPluginGtk(NPP instance, NPuint16_t mode) :
    VlcPluginBase(instance, mode),
    parent(NULL),
    parent_vbox(NULL),
14
    video(NULL),
15
    toolbar(NULL)
16 17 18 19 20 21 22 23 24 25 26
{
}

VlcPluginGtk::~VlcPluginGtk()
{
}

void VlcPluginGtk::set_player_window()
{
    libvlc_media_player_set_xwindow(libvlc_media_player,
                                    (uint32_t)getXid(video));
27
    libvlc_video_set_mouse_input(libvlc_media_player, 0);
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
}

void VlcPluginGtk::toggle_fullscreen()
{
    if (playlist_isplaying())
        libvlc_toggle_fullscreen(libvlc_media_player);
}

void VlcPluginGtk::set_fullscreen(int yes)
{
    if (playlist_isplaying())
        libvlc_set_fullscreen(libvlc_media_player, yes);
}

int  VlcPluginGtk::get_fullscreen()
{
    int r = 0;
    if (playlist_isplaying())
        r = libvlc_get_fullscreen(libvlc_media_player);
    return r;
}

void VlcPluginGtk::show_toolbar()
{
52 53
    gtk_box_pack_start(GTK_BOX(parent_vbox), toolbar, false, false, 0);
    gtk_widget_show_all(toolbar);
54 55 56 57
}

void VlcPluginGtk::hide_toolbar()
{
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    gtk_widget_hide(toolbar);
    gtk_container_remove(GTK_CONTAINER(parent_vbox), toolbar);
}

struct tool_actions_t
{
    const gchar *stock_id;
    vlc_toolbar_clicked_t clicked;
};
static const tool_actions_t tool_actions[] = {
    {GTK_STOCK_MEDIA_PLAY, clicked_Play},
    {GTK_STOCK_MEDIA_PAUSE, clicked_Pause},
    {GTK_STOCK_MEDIA_STOP, clicked_Stop},
    {"gtk-volume-muted", clicked_Mute},
    {"gtk-volume-unmuted", clicked_Unmute}
};

Cheng Sun's avatar
Cheng Sun committed
75
static void toolbar_handler(GtkToolButton *btn, gpointer user_data)
76
{
Cheng Sun's avatar
Cheng Sun committed
77
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
78 79 80 81 82 83 84
    const gchar *stock_id = gtk_tool_button_get_stock_id(btn);
    for (int i = 0; i < sizeof(tool_actions)/sizeof(tool_actions_t); ++i) {
        if (!strcmp(stock_id, tool_actions[i].stock_id)) {
            plugin->control_handler(tool_actions[i].clicked);
            return;
        }
    }
Cheng Sun's avatar
Cheng Sun committed
85
    fprintf(stderr, "WARNING: No idea what toolbar button you just clicked on (%s)\n", stock_id?stock_id:"NULL");
86 87
}

88 89 90 91 92 93 94 95 96 97 98 99 100
static void menu_handler(GtkMenuItem *menuitem, gpointer user_data)
{
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
    const gchar *stock_id = gtk_menu_item_get_label(GTK_MENU_ITEM(menuitem));
    for (int i = 0; i < sizeof(tool_actions)/sizeof(tool_actions_t); ++i) {
        if (!strcmp(stock_id, tool_actions[i].stock_id)) {
            plugin->control_handler(tool_actions[i].clicked);
            return;
        }
    }
    fprintf(stderr, "WARNING: No idea what menu item you just clicked on (%s)\n", stock_id?stock_id:"NULL");
}

101
void VlcPluginGtk::popup_menu()
102 103
{
    /* construct menu */
104
    GtkWidget *popupmenu = gtk_menu_new();
105 106 107 108 109 110 111 112
    GtkWidget *menuitem;

    /* play/pause */
    menuitem = gtk_image_menu_item_new_from_stock(
                        playlist_isplaying() ?
                        GTK_STOCK_MEDIA_PAUSE :
                        GTK_STOCK_MEDIA_PLAY, NULL);
    g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_handler), this);
113
    gtk_menu_shell_append(GTK_MENU_SHELL(popupmenu), menuitem);
114 115 116 117
    /* stop */
    menuitem = gtk_image_menu_item_new_from_stock(
                                GTK_STOCK_MEDIA_STOP, NULL);
    g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_handler), this);
118
    gtk_menu_shell_append(GTK_MENU_SHELL(popupmenu), menuitem);
119

120 121 122 123
    gtk_widget_show_all(popupmenu);
    gtk_menu_attach_to_widget(GTK_MENU(popupmenu), video, NULL);
    gtk_menu_popup(GTK_MENU(popupmenu), NULL, NULL, NULL, NULL,
                   0, gtk_get_current_event_time());
124 125 126 127 128 129
}

static bool video_button_handler(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
    if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
130
        plugin->popup_menu();
131 132 133 134 135 136 137
        return true;
    }
    return false;
}

static bool video_popup_handler(GtkWidget *widget, gpointer user_data) {
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
138
    plugin->popup_menu();
139 140 141
    return true;
}

Cheng Sun's avatar
Cheng Sun committed
142
static bool time_slider_handler(GtkRange *range, GtkScrollType scroll, gdouble value, gpointer user_data)
143
{
Cheng Sun's avatar
Cheng Sun committed
144
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
145 146 147 148
    libvlc_media_player_set_position(plugin->getMD(), value/100.0);
    return false;
}

Cheng Sun's avatar
Cheng Sun committed
149
static bool vol_slider_handler(GtkRange *range, GtkScrollType scroll, gdouble value, gpointer user_data)
150
{
Cheng Sun's avatar
Cheng Sun committed
151
    VlcPluginGtk *plugin = (VlcPluginGtk *) user_data;
152 153
    libvlc_audio_set_volume(plugin->getMD(), value);
    return false;
154 155 156 157
}

void VlcPluginGtk::update_controls()
{
158 159 160 161 162 163 164
    GtkToolItem *toolbutton;

    /* play/pause button */
    const gchar *stock_id = playlist_isplaying() ? GTK_STOCK_MEDIA_PAUSE : GTK_STOCK_MEDIA_PLAY;
    toolbutton = gtk_toolbar_get_nth_item(GTK_TOOLBAR(toolbar), 0);
    if (strcmp(gtk_tool_button_get_stock_id(GTK_TOOL_BUTTON(toolbutton)), stock_id)) {
        gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(toolbutton), stock_id);
Cheng Sun's avatar
Cheng Sun committed
165
        /* work around firefox not displaying the icon properly after change */
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
        g_object_ref(toolbutton);
        gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(toolbutton));
        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolbutton, 0);
        g_object_unref(toolbutton);
    }

    /* time slider */
    if (!libvlc_media_player ||
            !libvlc_media_player_is_seekable(libvlc_media_player)) {
        gtk_widget_set_sensitive(time_slider, false);
        gtk_range_set_value(GTK_RANGE(time_slider), 0);
    } else {
        gtk_widget_set_sensitive(time_slider, true);
        gdouble timepos = 100*libvlc_media_player_get_position(libvlc_media_player);
        gtk_range_set_value(GTK_RANGE(time_slider), timepos);
    }

    gtk_widget_show_all(toolbar);
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

bool VlcPluginGtk::create_windows()
{
    Display *p_display = ( (NPSetWindowCallbackStruct *)
                           npwindow.ws_info )->display;
    Window socket = (Window) npwindow.window;
    GdkColor color_black;
    gdk_color_parse("black", &color_black);

    parent = gtk_plug_new(socket);
    gtk_widget_modify_bg(parent, GTK_STATE_NORMAL, &color_black);

    parent_vbox = gtk_vbox_new(false, 0);
    gtk_container_add(GTK_CONTAINER(parent), parent_vbox);

    video = gtk_drawing_area_new();
    gtk_widget_modify_bg(video, GTK_STATE_NORMAL, &color_black);
202 203 204 205 206
    gtk_widget_add_events(video,
            GDK_BUTTON_PRESS_MASK
          | GDK_BUTTON_RELEASE_MASK);
    g_signal_connect(G_OBJECT(video), "button-press-event", G_CALLBACK(video_button_handler), this);
    g_signal_connect(G_OBJECT(video), "popup-menu", G_CALLBACK(video_popup_handler), this);
207 208 209 210
    gtk_box_pack_start(GTK_BOX(parent_vbox), video, true, true, 0);

    gtk_widget_show_all(parent);

Cheng Sun's avatar
Cheng Sun committed
211 212 213

    /*** TOOLBAR ***/

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
    GtkToolItem *toolitem;
    /* play/pause */
    toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
    g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(toolbar_handler), this);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    /* stop */
    toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
    g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(toolbar_handler), this);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);

    /* time slider */
    toolitem = gtk_tool_item_new();
    time_slider = gtk_hscale_new_with_range(0, 100, 10);
    gtk_scale_set_draw_value(GTK_SCALE(time_slider), false);
    g_signal_connect(G_OBJECT(time_slider), "change-value", G_CALLBACK(time_slider_handler), this);
    gtk_container_add(GTK_CONTAINER(toolitem), time_slider);
    gtk_tool_item_set_expand(toolitem, true);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
    
    /* volume slider */
    toolitem = gtk_tool_item_new();
    GtkWidget *vol_slider = gtk_hscale_new_with_range(0, 200, 10);
    gtk_scale_set_draw_value(GTK_SCALE(vol_slider), false);
    g_signal_connect(G_OBJECT(vol_slider), "change-value", G_CALLBACK(vol_slider_handler), this);
    gtk_range_set_value(GTK_RANGE(vol_slider), 100);
    gtk_widget_set_size_request(vol_slider, 100, -1);
    gtk_container_add(GTK_CONTAINER(toolitem), vol_slider);
    gtk_tool_item_set_expand(toolitem, false);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);

    update_controls();
    show_toolbar();

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    return true;
}

bool VlcPluginGtk::resize_windows()
{
    GtkRequisition req;
    req.width = npwindow.width;
    req.height = npwindow.height;
    gtk_widget_size_request(parent, &req);
#if 0
    Window root_return, parent_return, *children_return;
    unsigned int i_nchildren;
    XQueryTree( p_display, npvideo,
                &root_return, &parent_return, &children_return,
                &i_nchildren );

    if( i_nchildren > 0 )
    {
        /* XXX: Make assumptions related to the window parenting structure in
           vlc/modules/video_output/x11/xcommon.c */
        Window base_window = children_return[i_nchildren - 1];

        i_ret = XResizeWindow( p_display, base_window,
                npwindow.width, ( npwindow.height - i_tb_height ) );
    }

    return true;
#endif
}

bool VlcPluginGtk::destroy_windows()
{
    /* TODO */
}