/** * Create an X11 window. */ static int Open (vout_window_t *wnd, const vout_window_cfg_t *cfg) { xcb_generic_error_t *err; xcb_void_cookie_t ck; vout_window_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) return VLC_ENOMEM; p_sys->embedded = false; /* Connect to X */ char *display = var_InheritString (wnd, "x11-display"); int snum; xcb_connection_t *conn = xcb_connect (display, &snum); if (xcb_connection_has_error (conn) /*== NULL*/) goto error; /* Find configured screen */ const xcb_setup_t *setup = xcb_get_setup (conn); const xcb_screen_t *scr = NULL; for (xcb_screen_iterator_t i = xcb_setup_roots_iterator (setup); i.rem > 0; xcb_screen_next (&i)) { if (snum == 0) { scr = i.data; break; } snum--; } if (scr == NULL) { msg_Err (wnd, "bad X11 screen number"); goto error; } /* Create window */ const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; uint32_t values[2] = { /* XCB_CW_BACK_PIXEL */ scr->black_pixel, /* XCB_CW_EVENT_MASK */ XCB_EVENT_MASK_KEY_PRESS, }; xcb_window_t window = xcb_generate_id (conn); ck = xcb_create_window_checked (conn, scr->root_depth, window, scr->root, cfg->x, cfg->y, cfg->width, cfg->height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual, mask, values); err = xcb_request_check (conn, ck); if (err) { msg_Err (wnd, "creating window: X11 error %d", err->error_code); free (err); goto error; } wnd->handle.xid = window; wnd->display.x11 = display; wnd->control = Control; wnd->sys = p_sys; p_sys->conn = conn; if (var_InheritBool (wnd, "keyboard-events")) p_sys->keys = CreateKeyHandler (VLC_OBJECT(wnd), conn); else p_sys->keys = NULL; p_sys->root = scr->root; /* ICCCM * No cut&paste nor drag&drop, only Window Manager communication. */ set_ascii_prop (conn, window, XA_WM_NAME, /* xgettext: This is a plain ASCII spelling of "VLC media player" for the ICCCM window name. This must be pure ASCII. The limitation is partially with ICCCM and partially with VLC. For Latin script languages, you may need to strip accents. For other scripts, you will need to transliterate into Latin. */ vlc_pgettext ("ASCII", "VLC media player")); set_ascii_prop (conn, window, XA_WM_ICON_NAME, /* xgettext: This is a plain ASCII spelling of "VLC" for the ICCCM window name. This must be pure ASCII. */ vlc_pgettext ("ASCII", "VLC")); set_wm_hints (conn, window); xcb_change_property (conn, XCB_PROP_MODE_REPLACE, window, XA_WM_CLASS, XA_STRING, 8, 8, "vlc\0Vlc"); set_hostname_prop (conn, window); /* EWMH */ xcb_intern_atom_cookie_t utf8_string_ck = intern_string (conn, "UTF8_STRING");; xcb_intern_atom_cookie_t net_wm_name_ck = intern_string (conn, "_NET_WM_NAME"); xcb_intern_atom_cookie_t net_wm_icon_name_ck = intern_string (conn, "_NET_WM_ICON_NAME"); xcb_intern_atom_cookie_t wm_window_role_ck = intern_string (conn, "WM_WINDOW_ROLE"); xcb_atom_t utf8 = get_atom (conn, utf8_string_ck); xcb_atom_t net_wm_name = get_atom (conn, net_wm_name_ck); char *title = var_InheritString (wnd, "video-title"); if (title) { set_string (conn, window, utf8, net_wm_name, title); free (title); } else set_string (conn, window, utf8, net_wm_name, _("VLC media player")); xcb_atom_t net_wm_icon_name = get_atom (conn, net_wm_icon_name_ck); set_string (conn, window, utf8, net_wm_icon_name, _("VLC")); xcb_atom_t wm_window_role = get_atom (conn, wm_window_role_ck); set_ascii_prop (conn, window, wm_window_role, "vlc-video"); /* Cache any EWMH atom we may need later */ CacheAtoms (p_sys); /* Make the window visible */ xcb_map_window (conn, window); if (var_InheritBool (wnd, "video-wallpaper")) { vout_window_SetState (wnd, VOUT_WINDOW_STATE_BELOW); vout_window_SetFullScreen (wnd, true); } /* Create the event thread. It will dequeue all events, so any checked * request from this thread must be completed at this point. */ if ((p_sys->keys != NULL) && vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW)) DestroyKeyHandler (p_sys->keys); xcb_flush (conn); /* Make sure map_window is sent (should be useless) */ return VLC_SUCCESS; error: xcb_disconnect (conn); free (display); free (p_sys); return VLC_EGENERIC; }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_HIDE_MOUSE: /* FIXME TODO */ break; #ifndef NDEBUG case VOUT_DISPLAY_RESET_PICTURES: // not needed assert(0); #endif case VOUT_DISPLAY_CHANGE_FULLSCREEN: { const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *); return vout_window_SetFullScreen (sys->window, cfg->is_fullscreen); } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { unsigned state = va_arg (ap, unsigned); return vout_window_SetState (sys->window, state); } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_ZOOM: { const vout_display_cfg_t *cfg = va_arg (ap, const vout_display_cfg_t *); const video_format_t *src = &vd->source; if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE) { bool force = false; force = va_arg (ap, int); if (force && (cfg->display.width != vd->cfg->display.width || cfg->display.height != vd->cfg->display.height) && vout_window_SetSize (sys->window, cfg->display.width, cfg->display.height)) return VLC_EGENERIC; } vout_display_place_t place; vout_display_PlacePicture (&place, src, cfg, false); glViewport (0, 0, place.width, place.height); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: { const vout_display_cfg_t *cfg = vd->cfg; const video_format_t *src = va_arg (ap, const video_format_t *); vout_display_place_t place; vout_display_PlacePicture (&place, src, cfg, false); glViewport (0, 0, place.width, place.height); return VLC_SUCCESS; } case VOUT_DISPLAY_GET_OPENGL: { vlc_gl_t **pgl = va_arg (ap, vlc_gl_t **); *pgl = sys->gl; return VLC_SUCCESS; } default: msg_Err (vd, "Unknown request %d", query); }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *sys = vd->sys; switch (query) { case VOUT_DISPLAY_CHANGE_FULLSCREEN: { const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *); return vout_window_SetFullScreen (sys->embed, c->is_fullscreen); } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { const vout_display_cfg_t *p_cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); const bool is_forced = (bool)va_arg (ap, int); if (is_forced) { /* Changing the dimensions of the parent window takes place * asynchronously (in the X server). Also it might fail or result * in different dimensions than requested. Request the size change * and return a failure since the size is not (yet) changed. * If the change eventually succeeds, HandleParentStructure() * will trigger a non-forced display size change later. */ vout_window_SetSize (sys->embed, p_cfg->display.width, p_cfg->display.height); return VLC_EGENERIC; } vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, p_cfg, false); if (place.width != vd->fmt.i_visible_width || place.height != vd->fmt.i_visible_height) { vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; } /* Move the picture within the window */ const uint32_t values[] = { place.x, place.y }; xcb_configure_window (sys->conn, sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { unsigned state = va_arg (ap, unsigned); return vout_window_SetState (sys->embed, state); } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: /* I am not sure it is always necessary, but it is way simpler ... */ vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; case VOUT_DISPLAY_RESET_PICTURES: { ResetPictures (vd); vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); vd->fmt.i_width = vd->source.i_width * place.width / vd->source.i_visible_width; vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = vd->source.i_x_offset * place.width / vd->source.i_visible_width; vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.i_visible_height; return VLC_SUCCESS; } /* Hide the mouse. It will be send when * vout_display_t::info.b_hide_mouse is false */ case VOUT_DISPLAY_HIDE_MOUSE: xcb_change_window_attributes (sys->conn, sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t){ sys->cursor }); xcb_flush (sys->conn); return VLC_SUCCESS; default: msg_Err (vd, "Unknown request in XCB vout display"); return VLC_EGENERIC; } }
static int Control (vout_display_t *vd, int query, va_list ap) { vout_display_sys_t *p_sys = vd->sys; switch (query) { case VOUT_DISPLAY_CHANGE_FULLSCREEN: { const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *); return vout_window_SetFullScreen (p_sys->embed, c->is_fullscreen); } case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { const vout_display_cfg_t *p_cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *); const bool is_forced = (bool)va_arg (ap, int); if (is_forced && vout_window_SetSize (p_sys->embed, p_cfg->display.width, p_cfg->display.height)) return VLC_EGENERIC; vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, p_cfg, false); if (place.width != vd->fmt.i_visible_width || place.height != vd->fmt.i_visible_height) { vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; } /* Move the picture within the window */ const uint32_t values[] = { place.x, place.y }; xcb_configure_window (p_sys->conn, p_sys->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); return VLC_SUCCESS; } case VOUT_DISPLAY_CHANGE_WINDOW_STATE: { unsigned state = va_arg (ap, unsigned); return vout_window_SetState (p_sys->embed, state); } case VOUT_DISPLAY_CHANGE_ZOOM: case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: case VOUT_DISPLAY_CHANGE_SOURCE_CROP: /* I am not sure it is always necessary, but it is way simpler ... */ vout_display_SendEventPicturesInvalid (vd); return VLC_SUCCESS; case VOUT_DISPLAY_RESET_PICTURES: { ResetPictures (vd); vout_display_place_t place; vout_display_PlacePicture (&place, &vd->source, vd->cfg, false); vd->fmt.i_width = vd->source.i_width * place.width / vd->source.i_visible_width; vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height; vd->fmt.i_visible_width = place.width; vd->fmt.i_visible_height = place.height; vd->fmt.i_x_offset = vd->source.i_x_offset * place.width / vd->source.i_visible_width; vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.i_visible_height; return VLC_SUCCESS; } /* Hide the mouse. It will be send when * vout_display_t::info.b_hide_mouse is false */ case VOUT_DISPLAY_HIDE_MOUSE: xcb_change_window_attributes (p_sys->conn, p_sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t){ p_sys->cursor }); xcb_flush (p_sys->conn); return VLC_SUCCESS; default: msg_Err (vd, "Unknown request in XCB vout display"); return VLC_EGENERIC; } }