1590 lines
41 KiB
C
1590 lines
41 KiB
C
#include "ecore_xcb_private.h"
|
|
#include <X11/Xlib-xcb.h>
|
|
#include <dlfcn.h>
|
|
|
|
/* local function prototypes */
|
|
static int _ecore_xcb_shutdown(Eina_Bool close_display);
|
|
static Eina_Bool _ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED);
|
|
static Eina_Bool _ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED);
|
|
static Eina_Bool _ecore_xcb_idle_enter(void *data EINA_UNUSED);
|
|
|
|
/* local variables */
|
|
static int _ecore_xcb_init_count = 0;
|
|
static int _ecore_xcb_grab_count = 0;
|
|
static Ecore_Fd_Handler *_ecore_xcb_fd_handler = NULL;
|
|
static xcb_generic_event_t *_ecore_xcb_event_buffered = NULL;
|
|
static Ecore_Idle_Enterer *_ecore_xcb_idle_enterer = NULL;
|
|
|
|
static Ecore_X_Version _version = { VMAJ, VMIN, VMIC, VREV };
|
|
EAPI Ecore_X_Version *ecore_x_version = &_version;
|
|
|
|
/* external variables */
|
|
int _ecore_xcb_log_dom = -1;
|
|
Ecore_X_Display *_ecore_xcb_display = NULL;
|
|
Ecore_X_Connection *_ecore_xcb_conn = NULL;
|
|
Ecore_X_Screen *_ecore_xcb_screen = NULL;
|
|
Ecore_X_Atom _ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_NUM];
|
|
double _ecore_xcb_double_click_time = 0.25;
|
|
|
|
/**
|
|
* @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions
|
|
* @ingroup Ecore_X_Group
|
|
*
|
|
* Functions that start and shut down the Ecore X Library.
|
|
*/
|
|
|
|
/**
|
|
* Initialize the X display connection to the given display.
|
|
*
|
|
* @param name Display target name. If @c NULL, the default display is
|
|
* assumed.
|
|
* @return The number of times the library has been initialized without
|
|
* being shut down. 0 is returned if an error occurs.
|
|
* @ingroup Ecore_X_Init_Group
|
|
*/
|
|
EAPI int
|
|
ecore_x_init(const char *name)
|
|
{
|
|
char *gl = NULL;
|
|
uint32_t mask, list[1];
|
|
|
|
/* check if we have initialized already */
|
|
if (++_ecore_xcb_init_count != 1)
|
|
return _ecore_xcb_init_count;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
/* try to initialize eina */
|
|
if (!eina_init()) return --_ecore_xcb_init_count;
|
|
|
|
/* setup ecore_xcb log domain */
|
|
_ecore_xcb_log_dom =
|
|
eina_log_domain_register("ecore_x", ECORE_XCB_DEFAULT_LOG_COLOR);
|
|
if (_ecore_xcb_log_dom < 0)
|
|
{
|
|
EINA_LOG_ERR("Cannot create Ecore Xcb log domain");
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
/* try to initialize ecore */
|
|
if (!ecore_init())
|
|
{
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
/* try to initialize ecore_event */
|
|
if (!ecore_event_init())
|
|
{
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
/* NB: XLib has XInitThreads */
|
|
|
|
/* check for env var which says we are not going to use GL @ all
|
|
*
|
|
* NB: This is done because if someone wants a 'pure' xcb implementation
|
|
* of ecore_x, all they need do is export this variable in the environment
|
|
* and ecore_x will not use xlib stuff at all.
|
|
*
|
|
* The upside is you can get pure xcb-based ecore_x (w/ all the speed), but
|
|
* there is a down-side here in that you cannot get OpenGL without XLib :(
|
|
*/
|
|
if ((gl = getenv("ECORE_X_NO_XLIB")))
|
|
{
|
|
/* we found the env var that says 'Yes, we are not ever gonna try
|
|
* OpenGL so it is safe to not use XLib at all' */
|
|
|
|
/* try to connect to the display server */
|
|
_ecore_xcb_conn = xcb_connect(name, NULL);
|
|
}
|
|
else
|
|
{
|
|
/* env var was not specified, so we will assume that the user
|
|
* may want opengl @ some point. connect this way for opengl to work */
|
|
void *libxcb, *libxlib;
|
|
Display *(*_real_display)(const char *display);
|
|
xcb_connection_t *(*_real_connection)(Display * dpy);
|
|
void (*_real_queue)(Display *dpy, enum XEventQueueOwner owner);
|
|
int (*_real_close)(Display *dpy);
|
|
#ifdef EVAS_FRAME_QUEUING
|
|
Status (*_real_threads)(void);
|
|
#endif
|
|
|
|
/* want to dlopen here to avoid actual library linkage */
|
|
libxlib = dlopen("libX11.so", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxlib)
|
|
libxlib = dlopen("libX11.so.6", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxlib)
|
|
libxlib = dlopen("libX11.so.6.3.0", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxlib)
|
|
{
|
|
ERR("Could not dlsym to libX11");
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_event_shutdown();
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
libxcb = dlopen("libX11-xcb.so", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxcb)
|
|
libxcb = dlopen("libX11-xcb.so.1", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxcb)
|
|
libxcb = dlopen("libX11-xcb.so.1.0.0", (RTLD_LAZY | RTLD_GLOBAL));
|
|
if (!libxcb)
|
|
{
|
|
ERR("Could not dlsym to libX11-xcb");
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_event_shutdown();
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
_real_display = dlsym(libxlib, "XOpenDisplay");
|
|
_real_close = dlsym(libxlib, "XCloseDisplay");
|
|
_real_connection = dlsym(libxcb, "XGetXCBConnection");
|
|
_real_queue = dlsym(libxcb, "XSetEventQueueOwner");
|
|
#ifdef EVAS_FRAME_QUEUING
|
|
_real_threads = dlsym(libxlib, "XInitThreads");
|
|
#endif
|
|
|
|
if (_real_display)
|
|
{
|
|
#ifdef EVAS_FRAME_QUEUING
|
|
if (_real_threads) _real_threads();
|
|
#endif
|
|
_ecore_xcb_display = _real_display(name);
|
|
if (!_ecore_xcb_display)
|
|
{
|
|
ERR("Could not open Display via XLib");
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_event_shutdown();
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
if (_real_connection)
|
|
_ecore_xcb_conn = _real_connection(_ecore_xcb_display);
|
|
if (!_ecore_xcb_conn)
|
|
{
|
|
ERR("Could not get XCB Connection from XLib");
|
|
|
|
if (_real_close) _real_close(_ecore_xcb_display);
|
|
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_event_shutdown();
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
if (_real_queue)
|
|
_real_queue(_ecore_xcb_display, XCBOwnsEventQueue);
|
|
}
|
|
}
|
|
|
|
if (xcb_connection_has_error(_ecore_xcb_conn))
|
|
{
|
|
CRIT("XCB Connection has error");
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
ecore_event_shutdown();
|
|
ecore_shutdown();
|
|
eina_shutdown();
|
|
return --_ecore_xcb_init_count;
|
|
}
|
|
|
|
/* grab the default screen */
|
|
_ecore_xcb_screen =
|
|
xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
|
|
|
|
/* NB: This method of init/finalize extensions first, then atoms
|
|
* Does end up being 2 round trips to X, BUT if we do extensions init then
|
|
* atoms init first, and call the 'finalize' functions later, we end up
|
|
* being slower, so it's a trade-off. This current method clocks in
|
|
* around 0.003 for fetching atoms VS 0.010 for init both then finalize */
|
|
|
|
/* prefetch extension data */
|
|
_ecore_xcb_extensions_init();
|
|
|
|
/* finalize extensions */
|
|
_ecore_xcb_extensions_finalize();
|
|
|
|
/* set keyboard autorepeat */
|
|
mask = XCB_KB_AUTO_REPEAT_MODE;
|
|
list[0] = XCB_AUTO_REPEAT_MODE_ON;
|
|
xcb_change_keyboard_control(_ecore_xcb_conn, mask, list);
|
|
|
|
/* setup xcb events */
|
|
_ecore_xcb_events_init();
|
|
|
|
/* setup xcb keymasks */
|
|
_ecore_xcb_keymap_init();
|
|
|
|
/* finalize xcb keymasks */
|
|
_ecore_xcb_keymap_finalize();
|
|
|
|
/* setup ecore fd handler */
|
|
_ecore_xcb_fd_handler =
|
|
ecore_main_fd_handler_add(xcb_get_file_descriptor(_ecore_xcb_conn),
|
|
ECORE_FD_READ, _ecore_xcb_fd_handle,
|
|
_ecore_xcb_conn, _ecore_xcb_fd_handle_buff,
|
|
_ecore_xcb_conn);
|
|
|
|
if (!_ecore_xcb_fd_handler)
|
|
return _ecore_xcb_shutdown(EINA_TRUE);
|
|
|
|
/* prefetch atoms */
|
|
_ecore_xcb_atoms_init();
|
|
|
|
/* finalize atoms */
|
|
_ecore_xcb_atoms_finalize();
|
|
|
|
/* icccm_init: dummy function */
|
|
ecore_x_icccm_init();
|
|
|
|
/* setup netwm */
|
|
ecore_x_netwm_init();
|
|
|
|
/* old e hints init: dummy function */
|
|
ecore_x_e_init();
|
|
|
|
_ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] =
|
|
ECORE_X_ATOM_WM_DELETE_WINDOW;
|
|
_ecore_xcb_atoms_wm_protocol[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] =
|
|
ECORE_X_ATOM_WM_TAKE_FOCUS;
|
|
_ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_PING] =
|
|
ECORE_X_ATOM_NET_WM_PING;
|
|
_ecore_xcb_atoms_wm_protocol[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] =
|
|
ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
|
|
|
|
/* setup selection */
|
|
_ecore_xcb_selection_init();
|
|
|
|
/* setup dnd */
|
|
_ecore_xcb_dnd_init();
|
|
|
|
_ecore_xcb_idle_enterer =
|
|
ecore_idle_enterer_add(_ecore_xcb_idle_enter, NULL);
|
|
|
|
return _ecore_xcb_init_count;
|
|
}
|
|
|
|
/**
|
|
* Shuts down the Ecore X library.
|
|
*
|
|
* In shutting down the library, the X display connection is terminated
|
|
* and any event handlers for it are removed.
|
|
*
|
|
* @return The number of times the library has been initialized without
|
|
* being shut down.
|
|
* @ingroup Ecore_X_Init_Group
|
|
*/
|
|
EAPI int
|
|
ecore_x_shutdown(void)
|
|
{
|
|
return _ecore_xcb_shutdown(EINA_TRUE);
|
|
}
|
|
|
|
/**
|
|
* Shuts down the Ecore X library.
|
|
*
|
|
* As ecore_x_shutdown, except do not close Display, only connection.
|
|
*
|
|
* @return The number of times the library has been initialized without
|
|
* being shut down. 0 is returned if an error occurs.
|
|
* @ingroup Ecore_X_Init_Group
|
|
*/
|
|
EAPI int
|
|
ecore_x_disconnect(void)
|
|
{
|
|
return _ecore_xcb_shutdown(EINA_FALSE);
|
|
}
|
|
|
|
/**
|
|
* @defgroup Ecore_X_Flush_Group X Synchronization Functions
|
|
* @ingroup Ecore_X_Group
|
|
*
|
|
* Functions that ensure that all commands that have been issued by the
|
|
* Ecore X library have been sent to the server.
|
|
*/
|
|
|
|
/**
|
|
* Sends all X commands in the X Display buffer.
|
|
* @ingroup Ecore_X_Flush_Group
|
|
*/
|
|
EAPI void
|
|
ecore_x_flush(void)
|
|
{
|
|
// LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
CHECK_XCB_CONN;
|
|
xcb_flush(_ecore_xcb_conn);
|
|
}
|
|
|
|
/**
|
|
* Retrieves the Ecore_X_Screen handle used for the current X connection.
|
|
* @return The current default screen.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*/
|
|
EAPI Ecore_X_Screen *
|
|
ecore_x_default_screen_get(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
return (Ecore_X_Screen *)_ecore_xcb_screen;
|
|
}
|
|
|
|
EAPI Ecore_X_Connection *
|
|
ecore_x_connection_get(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
CHECK_XCB_CONN;
|
|
return (Ecore_X_Connection *)_ecore_xcb_conn;
|
|
}
|
|
|
|
/**
|
|
* Return the last event time
|
|
*/
|
|
EAPI Ecore_X_Time
|
|
ecore_x_current_time_get(void)
|
|
{
|
|
return _ecore_xcb_events_last_time_get();
|
|
}
|
|
|
|
/**
|
|
* Flushes the command buffer and waits until all requests have been
|
|
* processed by the server.
|
|
* @ingroup Ecore_X_Flush_Group
|
|
*/
|
|
EAPI void
|
|
ecore_x_sync(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
CHECK_XCB_CONN;
|
|
free(xcb_get_input_focus_reply(_ecore_xcb_conn,
|
|
xcb_get_input_focus_unchecked(_ecore_xcb_conn),
|
|
NULL));
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_grab(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
CHECK_XCB_CONN;
|
|
_ecore_xcb_grab_count++;
|
|
if (_ecore_xcb_grab_count == 1)
|
|
xcb_grab_server(_ecore_xcb_conn);
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_ungrab(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
CHECK_XCB_CONN;
|
|
_ecore_xcb_grab_count--;
|
|
if (_ecore_xcb_grab_count < 0) _ecore_xcb_grab_count = 0;
|
|
if (_ecore_xcb_grab_count == 0)
|
|
xcb_ungrab_server(_ecore_xcb_conn);
|
|
}
|
|
|
|
/**
|
|
* Send client message with given type and format 32.
|
|
*
|
|
* @param win The window the message is sent to.
|
|
* @param type The client message type.
|
|
* @param mask The mask of the message to be sent.
|
|
* @param d0 The client message data item 1
|
|
* @param d1 The client message data item 2
|
|
* @param d2 The client message data item 3
|
|
* @param d3 The client message data item 4
|
|
* @param d4 The client message data item 5
|
|
*
|
|
* @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
|
|
*/
|
|
EAPI Eina_Bool
|
|
ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type,
|
|
Ecore_X_Event_Mask mask,
|
|
long d0, long d1, long d2, long d3, long d4)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
xcb_void_cookie_t cookie;
|
|
xcb_generic_error_t *err;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
memset(&ev, 0, sizeof(xcb_client_message_event_t));
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 32;
|
|
ev.window = win;
|
|
ev.type = type;
|
|
ev.data.data32[0] = (uint32_t)d0;
|
|
ev.data.data32[1] = (uint32_t)d1;
|
|
ev.data.data32[2] = (uint32_t)d2;
|
|
ev.data.data32[3] = (uint32_t)d3;
|
|
ev.data.data32[4] = (uint32_t)d4;
|
|
|
|
cookie = xcb_send_event(_ecore_xcb_conn, 0, win, mask, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, cookie);
|
|
if (err)
|
|
{
|
|
DBG("Problem Sending Event");
|
|
DBG("\tType: %d", type);
|
|
DBG("\tWin: %d", win);
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Send client message with given type and format 8.
|
|
*
|
|
* @param win The window the message is sent to.
|
|
* @param type The client message type.
|
|
* @param data Data to be sent.
|
|
* @param len Number of data bytes, max @c 20.
|
|
*
|
|
* @return @c EINA_TRUE on success @c EINA_FALSE otherwise.
|
|
*/
|
|
EAPI Eina_Bool
|
|
ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type,
|
|
const void *data, int len)
|
|
{
|
|
xcb_client_message_event_t ev;
|
|
xcb_void_cookie_t cookie;
|
|
xcb_generic_error_t *err;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
memset(&ev, 0, sizeof(xcb_client_message_event_t));
|
|
|
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
|
ev.format = 8;
|
|
ev.window = win;
|
|
ev.type = type;
|
|
if (len > 20) len = 20;
|
|
memcpy(ev.data.data8, data, len);
|
|
memset(ev.data.data8 + len, 0, 20 - len);
|
|
|
|
cookie = xcb_send_event(_ecore_xcb_conn, 0, win,
|
|
XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, cookie);
|
|
if (err)
|
|
{
|
|
DBG("Problem Sending Event");
|
|
DBG("\tType: %d", type);
|
|
DBG("\tWin: %d", win);
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b)
|
|
{
|
|
xcb_translate_coordinates_cookie_t cookie;
|
|
xcb_translate_coordinates_reply_t *reply;
|
|
xcb_button_press_event_t ev;
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
Ecore_X_Window root = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
root = ecore_x_window_root_get(win);
|
|
cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
|
|
reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
memset(&ev, 0, sizeof(xcb_button_press_event_t));
|
|
|
|
ev.response_type = XCB_BUTTON_PRESS;
|
|
ev.event = win;
|
|
ev.child = win;
|
|
ev.root = root;
|
|
ev.event_x = x;
|
|
ev.event_y = y;
|
|
ev.same_screen = 1;
|
|
ev.state = 1 << b;
|
|
ev.detail = b; // xcb uses detail for button
|
|
ev.root_x = reply->dst_x;
|
|
ev.root_y = reply->dst_y;
|
|
ev.time = ecore_x_current_time_get();
|
|
free(reply);
|
|
|
|
vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
|
|
XCB_EVENT_MASK_BUTTON_PRESS, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b)
|
|
{
|
|
xcb_translate_coordinates_cookie_t cookie;
|
|
xcb_translate_coordinates_reply_t *reply;
|
|
xcb_button_release_event_t ev;
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
Ecore_X_Window root = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
root = ecore_x_window_root_get(win);
|
|
cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
|
|
reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
memset(&ev, 0, sizeof(xcb_button_release_event_t));
|
|
|
|
ev.response_type = XCB_BUTTON_RELEASE;
|
|
ev.event = win;
|
|
ev.child = win;
|
|
ev.root = root;
|
|
ev.event_x = x;
|
|
ev.event_y = y;
|
|
ev.same_screen = 1;
|
|
ev.state = 0;
|
|
ev.root_x = reply->dst_x;
|
|
ev.root_y = reply->dst_y;
|
|
ev.detail = b; // xcb uses detail for button
|
|
ev.time = ecore_x_current_time_get();
|
|
free(reply);
|
|
|
|
vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
|
|
XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y)
|
|
{
|
|
xcb_translate_coordinates_cookie_t cookie;
|
|
xcb_translate_coordinates_reply_t *reply;
|
|
xcb_motion_notify_event_t ev;
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
Ecore_X_Window root = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
root = ecore_x_window_root_get(win);
|
|
cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
|
|
reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
memset(&ev, 0, sizeof(xcb_motion_notify_event_t));
|
|
|
|
ev.response_type = XCB_MOTION_NOTIFY;
|
|
ev.event = win;
|
|
ev.child = win;
|
|
ev.root = root;
|
|
ev.event_x = x;
|
|
ev.event_y = y;
|
|
ev.same_screen = 1;
|
|
ev.state = 0;
|
|
ev.detail = 0; // xcb uses 'detail' for is_hint
|
|
ev.root_x = reply->dst_x;
|
|
ev.root_y = reply->dst_y;
|
|
ev.time = ecore_x_current_time_get();
|
|
free(reply);
|
|
|
|
vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
|
|
XCB_EVENT_MASK_POINTER_MOTION, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y)
|
|
{
|
|
xcb_translate_coordinates_cookie_t cookie;
|
|
xcb_translate_coordinates_reply_t *reply;
|
|
xcb_enter_notify_event_t ev;
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
Ecore_X_Window root = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
root = ecore_x_window_root_get(win);
|
|
cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
|
|
reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
memset(&ev, 0, sizeof(xcb_enter_notify_event_t));
|
|
|
|
ev.response_type = XCB_ENTER_NOTIFY;
|
|
ev.event = win;
|
|
ev.child = win;
|
|
ev.root = root;
|
|
ev.event_x = x;
|
|
ev.event_y = y;
|
|
ev.same_screen_focus = 1;
|
|
ev.mode = XCB_NOTIFY_MODE_NORMAL;
|
|
ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR;
|
|
/* ev.focus = 0; */
|
|
ev.state = 0;
|
|
ev.root_x = reply->dst_x;
|
|
ev.root_y = reply->dst_y;
|
|
ev.time = ecore_x_current_time_get();
|
|
free(reply);
|
|
|
|
vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
|
|
XCB_EVENT_MASK_ENTER_WINDOW, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_mouse_out_send(Ecore_X_Window win, int x, int y)
|
|
{
|
|
xcb_translate_coordinates_cookie_t cookie;
|
|
xcb_translate_coordinates_reply_t *reply;
|
|
xcb_leave_notify_event_t ev;
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
Ecore_X_Window root = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
root = ecore_x_window_root_get(win);
|
|
cookie = xcb_translate_coordinates(_ecore_xcb_conn, win, root, x, y);
|
|
reply = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
memset(&ev, 0, sizeof(xcb_leave_notify_event_t));
|
|
|
|
ev.response_type = XCB_LEAVE_NOTIFY;
|
|
ev.event = win;
|
|
ev.child = win;
|
|
ev.root = root;
|
|
ev.event_x = x;
|
|
ev.event_y = y;
|
|
ev.same_screen_focus = 1;
|
|
ev.mode = XCB_NOTIFY_MODE_NORMAL;
|
|
ev.detail = XCB_NOTIFY_DETAIL_NONLINEAR;
|
|
/* ev.focus = 0; */
|
|
ev.state = 0;
|
|
ev.root_x = reply->dst_x;
|
|
ev.root_y = reply->dst_y;
|
|
ev.time = ecore_x_current_time_get();
|
|
free(reply);
|
|
|
|
vcookie = xcb_send_event(_ecore_xcb_conn, 1, win,
|
|
XCB_EVENT_MASK_LEAVE_WINDOW, (const char *)&ev);
|
|
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_keyboard_grab(Ecore_X_Window win)
|
|
{
|
|
xcb_grab_keyboard_cookie_t cookie;
|
|
xcb_grab_keyboard_reply_t *reply;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
cookie =
|
|
xcb_grab_keyboard_unchecked(_ecore_xcb_conn, 0, win, XCB_CURRENT_TIME,
|
|
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
|
|
reply = xcb_grab_keyboard_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
free(reply);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_keyboard_ungrab(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_ungrab_keyboard(_ecore_xcb_conn, XCB_CURRENT_TIME);
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y)
|
|
{
|
|
xcb_query_pointer_cookie_t cookie;
|
|
xcb_query_pointer_reply_t *reply;
|
|
|
|
// LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
// if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root;
|
|
|
|
if (x) *x = -1;
|
|
if (y) *y = -1;
|
|
|
|
cookie = xcb_query_pointer_unchecked(_ecore_xcb_conn, win);
|
|
reply = xcb_query_pointer_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return;
|
|
if (x) *x = reply->win_x;
|
|
if (y) *y = reply->win_y;
|
|
free(reply);
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold)
|
|
{
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
vcookie =
|
|
xcb_change_pointer_control_checked(_ecore_xcb_conn,
|
|
accel_num, accel_denom, threshold,
|
|
1, 1);
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold)
|
|
{
|
|
xcb_get_pointer_control_cookie_t cookie;
|
|
xcb_get_pointer_control_reply_t *reply;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
if (accel_num) *accel_num = 0;
|
|
if (accel_denom) *accel_denom = 0;
|
|
if (threshold) *threshold = 0;
|
|
|
|
cookie = xcb_get_pointer_control_unchecked(_ecore_xcb_conn);
|
|
reply = xcb_get_pointer_control_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
if (accel_num) *accel_num = reply->acceleration_numerator;
|
|
if (accel_denom) *accel_denom = reply->acceleration_denominator;
|
|
if (threshold) *threshold = reply->threshold;
|
|
free(reply);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_mapping_set(unsigned char *map, int nmap)
|
|
{
|
|
xcb_set_pointer_mapping_cookie_t cookie;
|
|
xcb_set_pointer_mapping_reply_t *reply;
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
cookie = xcb_set_pointer_mapping_unchecked(_ecore_xcb_conn, nmap, map);
|
|
reply = xcb_set_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
if (reply->status == XCB_MAPPING_STATUS_SUCCESS)
|
|
ret = EINA_TRUE;
|
|
|
|
free(reply);
|
|
return ret;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_mapping_get(unsigned char *map, int nmap)
|
|
{
|
|
xcb_get_pointer_mapping_cookie_t cookie;
|
|
xcb_get_pointer_mapping_reply_t *reply;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
if (map) *map = 0;
|
|
nmap = 0;
|
|
|
|
cookie = xcb_get_pointer_mapping_unchecked(_ecore_xcb_conn);
|
|
reply = xcb_get_pointer_mapping_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
nmap = xcb_get_pointer_mapping_map_length(reply);
|
|
if (nmap <= 0)
|
|
{
|
|
free(reply);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
if (map)
|
|
{
|
|
uint8_t *tmp;
|
|
int i = 0;
|
|
|
|
tmp = xcb_get_pointer_mapping_map(reply);
|
|
for (i = 0; i < nmap; i++)
|
|
map[i] = tmp[i];
|
|
}
|
|
|
|
free(reply);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_grab(Ecore_X_Window win)
|
|
{
|
|
xcb_grab_pointer_cookie_t cookie;
|
|
xcb_grab_pointer_reply_t *reply;
|
|
uint16_t mask;
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
|
|
XCB_EVENT_MASK_POINTER_MOTION);
|
|
|
|
cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
|
|
reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE;
|
|
|
|
free(reply);
|
|
return ret;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_confine_grab(Ecore_X_Window win)
|
|
{
|
|
xcb_grab_pointer_cookie_t cookie;
|
|
xcb_grab_pointer_reply_t *reply;
|
|
uint16_t mask;
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
mask = (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
|
|
XCB_EVENT_MASK_POINTER_MOTION);
|
|
|
|
cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, win, mask,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
XCB_GRAB_MODE_ASYNC,
|
|
win, XCB_NONE, XCB_CURRENT_TIME);
|
|
reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (!reply) return EINA_FALSE;
|
|
|
|
ret = (reply->status == XCB_GRAB_STATUS_SUCCESS) ? EINA_TRUE : EINA_FALSE;
|
|
|
|
free(reply);
|
|
return ret;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_pointer_ungrab(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME);
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
ecore_x_pointer_warp(Ecore_X_Window win, int x, int y)
|
|
{
|
|
xcb_void_cookie_t vcookie;
|
|
xcb_generic_error_t *err;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
vcookie =
|
|
xcb_warp_pointer_checked(_ecore_xcb_conn, XCB_NONE, win, 0, 0, 0, 0, x, y);
|
|
err = xcb_request_check(_ecore_xcb_conn, vcookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Invoke the standard system beep to alert users
|
|
*
|
|
* @param percent The volume at which the bell rings. Must be in the range
|
|
* [-100,+100]. If percent >= 0, the final volume will be:
|
|
* base - [(base * percent) / 100] + percent
|
|
* Otherwise, it's calculated as:
|
|
* base + [(base * percent) / 100]
|
|
* where @c base is the bell's base volume as set by XChangeKeyboardControl(3).
|
|
*
|
|
* @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
|
|
*/
|
|
EAPI Eina_Bool
|
|
ecore_x_bell(int percent)
|
|
{
|
|
xcb_void_cookie_t cookie;
|
|
xcb_generic_error_t *err;
|
|
|
|
CHECK_XCB_CONN;
|
|
|
|
// FIXME: Use unchecked version after development is ironed out
|
|
cookie = xcb_bell_checked(_ecore_xcb_conn, percent);
|
|
err = xcb_request_check(_ecore_xcb_conn, cookie);
|
|
if (err)
|
|
{
|
|
_ecore_xcb_error_handle(err);
|
|
free(err);
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_display_size_get(Ecore_X_Display *dsp EINA_UNUSED, int *w, int *h)
|
|
{
|
|
xcb_screen_t *screen;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
/* grab the default screen */
|
|
screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
|
|
if (w) *w = screen->width_in_pixels;
|
|
if (h) *h = screen->height_in_pixels;
|
|
}
|
|
|
|
EAPI unsigned long
|
|
ecore_x_display_black_pixel_get(Ecore_X_Display *dsp EINA_UNUSED)
|
|
{
|
|
xcb_screen_t *screen;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
/* grab the default screen */
|
|
screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
|
|
return screen->black_pixel;
|
|
}
|
|
|
|
EAPI unsigned long
|
|
ecore_x_display_white_pixel_get(Ecore_X_Display *dsp EINA_UNUSED)
|
|
{
|
|
xcb_screen_t *screen;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
/* grab the default screen */
|
|
screen = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data;
|
|
return screen->white_pixel;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_pointer_last_xy_get(int *x, int *y)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (x) *x = _ecore_xcb_event_last_root_x;
|
|
if (y) *y = _ecore_xcb_event_last_root_y;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_focus_reset(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_set_input_focus(_ecore_xcb_conn, XCB_INPUT_FOCUS_POINTER_ROOT,
|
|
((xcb_screen_t *)_ecore_xcb_screen)->root,
|
|
XCB_CURRENT_TIME);
|
|
// ecore_x_flush();
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_events_allow_all(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME);
|
|
// ecore_x_flush();
|
|
}
|
|
|
|
/**
|
|
* Kill a specific client
|
|
*
|
|
* You can kill a specific client owning window @p win
|
|
*
|
|
* @param win Window of the client to be killed
|
|
*/
|
|
EAPI void
|
|
ecore_x_kill(Ecore_X_Window win)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_kill_client(_ecore_xcb_conn, win);
|
|
// ecore_x_flush();
|
|
}
|
|
|
|
/**
|
|
* Kill all clients with subwindows under a given window.
|
|
*
|
|
* You can kill all clients connected to the X server by using
|
|
* @ref ecore_x_window_root_list to get a list of root windows, and
|
|
* then passing each root window to this function.
|
|
*
|
|
* @param root The window whose children will be killed.
|
|
*/
|
|
EAPI void
|
|
ecore_x_killall(Ecore_X_Window root)
|
|
{
|
|
int screens = 0, i = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
ecore_x_grab();
|
|
|
|
screens = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem;
|
|
|
|
/* Traverse window tree starting from root, and drag each
|
|
* before the firing squad */
|
|
for (i = 0; i < screens; ++i)
|
|
{
|
|
xcb_query_tree_cookie_t cookie;
|
|
xcb_query_tree_reply_t *reply;
|
|
|
|
cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, root);
|
|
reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL);
|
|
if (reply)
|
|
{
|
|
xcb_window_t *wins = NULL;
|
|
int tree_c_len, j = 0;
|
|
|
|
wins = xcb_query_tree_children(reply);
|
|
tree_c_len = xcb_query_tree_children_length(reply);
|
|
for (j = 0; j < tree_c_len; j++)
|
|
xcb_kill_client(_ecore_xcb_conn, wins[j]);
|
|
free(reply);
|
|
}
|
|
}
|
|
|
|
ecore_x_ungrab();
|
|
ecore_x_sync(); // needed
|
|
}
|
|
|
|
/**
|
|
* Return the screen DPI
|
|
*
|
|
* This is a simplistic call to get DPI. It does not account for differing
|
|
* DPI in the x amd y axes nor does it account for multihead or xinerama and
|
|
* xrander where different parts of the screen may have differen DPI etc.
|
|
*
|
|
* @return the general screen DPI (dots/pixels per inch).
|
|
*/
|
|
EAPI int
|
|
ecore_x_dpi_get(void)
|
|
{
|
|
uint16_t mw = 0, w = 0;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
mw = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_millimeters;
|
|
if (mw <= 0) return 75;
|
|
w = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels;
|
|
return (((w * 254) / mw) + 5) / 10;
|
|
}
|
|
|
|
/**
|
|
* @defgroup Ecore_X_Display_Attr_Group X Display Attributes
|
|
* @ingroup Ecore_X_Group
|
|
*
|
|
* Functions that set and retrieve X display attributes.
|
|
*/
|
|
|
|
/**
|
|
* Retrieves the Ecore_X_Display handle used for the current X connection.
|
|
* @return The current X display.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*/
|
|
EAPI Ecore_X_Display *
|
|
ecore_x_display_get(void)
|
|
{
|
|
char *gl = NULL;
|
|
|
|
CHECK_XCB_CONN;
|
|
|
|
/* if we have the 'dont use xlib' env var, then we are not using
|
|
* XLib and thus cannot return a real XDisplay.
|
|
*
|
|
* NB: This may break EFL in some places and needs lots of testing !!! */
|
|
if ((gl = getenv("ECORE_X_NO_XLIB")))
|
|
return (Ecore_X_Display *)_ecore_xcb_conn;
|
|
else /* we can safely return an XDisplay var */
|
|
return (Ecore_X_Display *)_ecore_xcb_display;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the X display file descriptor.
|
|
* @return The current X display file descriptor.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*/
|
|
EAPI int
|
|
ecore_x_fd_get(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
return xcb_get_file_descriptor(_ecore_xcb_conn);
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int type, void *event),
|
|
void *data)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
_ecore_xcb_window_grab_replay_func = func;
|
|
_ecore_xcb_window_grab_replay_data = data;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the size of an Ecore_X_Screen.
|
|
* @param screen the handle to the screen to query.
|
|
* @param w where to return the width. May be NULL. Returns 0 on errors.
|
|
* @param h where to return the height. May be NULL. Returns 0 on errors.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
* @see ecore_x_default_screen_get()
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
EAPI void
|
|
ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h)
|
|
{
|
|
xcb_screen_t *s;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (w) *w = 0;
|
|
if (h) *h = 0;
|
|
if (!(s = (xcb_screen_t *)screen)) return;
|
|
if (w) *w = s->width_in_pixels;
|
|
if (h) *h = s->height_in_pixels;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the count of screens.
|
|
*
|
|
* @return The count of screens.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
EAPI int
|
|
ecore_x_screen_count_get(void)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
return xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn));
|
|
}
|
|
|
|
/**
|
|
* Retrieves the index number of the given screen.
|
|
*
|
|
* @param screen The screen for which index will be gotten.
|
|
* @return The index number of the screen.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
EAPI int
|
|
ecore_x_screen_index_get(const Ecore_X_Screen *screen)
|
|
{
|
|
xcb_screen_iterator_t iter;
|
|
int i = 0;
|
|
|
|
CHECK_XCB_CONN;
|
|
|
|
iter =
|
|
xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
|
|
for (; iter.rem; xcb_screen_next(&iter))
|
|
{
|
|
if (iter.data == (xcb_screen_t *)screen)
|
|
return i;
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the screen based on index number.
|
|
*
|
|
* @param idx The index that will be used to retrieve the screen.
|
|
* @return The Ecore_X_Screen at this index.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
EAPI Ecore_X_Screen *
|
|
ecore_x_screen_get(int idx)
|
|
{
|
|
xcb_screen_iterator_t iter;
|
|
int i = 0;
|
|
|
|
CHECK_XCB_CONN;
|
|
|
|
iter =
|
|
xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
|
|
for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
|
|
if (i == idx) return iter.data;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EAPI unsigned int
|
|
ecore_x_visual_id_get(Ecore_X_Visual visual)
|
|
{
|
|
return ((xcb_visualtype_t *)visual)->visual_id;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the default Visual.
|
|
*
|
|
* @param disp The Display to get the Default Visual from
|
|
* @param screen The Screen.
|
|
*
|
|
* @return The default visual.
|
|
* @since 1.1.0
|
|
*/
|
|
EAPI Ecore_X_Visual
|
|
ecore_x_default_visual_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
|
|
{
|
|
xcb_screen_t *s;
|
|
xcb_depth_iterator_t diter;
|
|
xcb_visualtype_iterator_t viter;
|
|
|
|
CHECK_XCB_CONN;
|
|
|
|
s = (xcb_screen_t *)screen;
|
|
diter = xcb_screen_allowed_depths_iterator(s);
|
|
for (; diter.rem; xcb_depth_next(&diter))
|
|
{
|
|
viter = xcb_depth_visuals_iterator(diter.data);
|
|
for (; viter.rem; xcb_visualtype_next(&viter))
|
|
{
|
|
if (viter.data->visual_id == s->root_visual)
|
|
return viter.data;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the default Colormap.
|
|
*
|
|
* @param disp The Display to get the Default Colormap from
|
|
* @param screen The Screen.
|
|
*
|
|
* @return The default colormap.
|
|
* @since 1.1.0
|
|
*/
|
|
EAPI Ecore_X_Colormap
|
|
ecore_x_default_colormap_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
|
|
{
|
|
xcb_screen_t *s;
|
|
|
|
s = (xcb_screen_t *)screen;
|
|
return s->default_colormap;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the default depth.
|
|
*
|
|
* @param disp The Display to get the Default Depth from
|
|
* @param screen The Screen.
|
|
*
|
|
* @return The default depth.
|
|
* @since 1.1.0
|
|
*/
|
|
EAPI int
|
|
ecore_x_default_depth_get(Ecore_X_Display *disp EINA_UNUSED, Ecore_X_Screen *screen)
|
|
{
|
|
xcb_screen_t *s;
|
|
|
|
s = (xcb_screen_t *)screen;
|
|
return s->root_depth;
|
|
}
|
|
|
|
EAPI void
|
|
ecore_x_xkb_select_group(int group)
|
|
{
|
|
// XXX: implement me */
|
|
}
|
|
|
|
/**
|
|
* Sets the timeout for a double and triple clicks to be flagged.
|
|
*
|
|
* This sets the time between clicks before the double_click flag is
|
|
* set in a button down event. If 3 clicks occur within double this
|
|
* time, the triple_click flag is also set.
|
|
*
|
|
* @param t The time in seconds
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*/
|
|
EAPI void
|
|
ecore_x_double_click_time_set(double t)
|
|
{
|
|
if (t < 0.0) t = 0.0;
|
|
_ecore_xcb_double_click_time = t;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the double and triple click flag timeout.
|
|
*
|
|
* See @ref ecore_x_double_click_time_set for more information.
|
|
*
|
|
* @return The timeout for double clicks in seconds.
|
|
* @ingroup Ecore_X_Display_Attr_Group
|
|
*/
|
|
EAPI double
|
|
ecore_x_double_click_time_get(void)
|
|
{
|
|
return _ecore_xcb_double_click_time;
|
|
}
|
|
|
|
/* local function prototypes */
|
|
static int
|
|
_ecore_xcb_shutdown(Eina_Bool close_display)
|
|
{
|
|
if (--_ecore_xcb_init_count != 0)
|
|
return _ecore_xcb_init_count;
|
|
|
|
if (!_ecore_xcb_conn)
|
|
return _ecore_xcb_init_count;
|
|
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
ecore_idle_enterer_del(_ecore_xcb_idle_enterer);
|
|
_ecore_xcb_idle_enterer = NULL;
|
|
|
|
if (_ecore_xcb_fd_handler)
|
|
ecore_main_fd_handler_del(_ecore_xcb_fd_handler);
|
|
|
|
/* disconnect from display server */
|
|
if (close_display)
|
|
xcb_disconnect(_ecore_xcb_conn);
|
|
else
|
|
{
|
|
close(xcb_get_file_descriptor(_ecore_xcb_conn));
|
|
_ecore_xcb_conn = NULL;
|
|
}
|
|
|
|
/* shutdown events */
|
|
_ecore_xcb_events_shutdown();
|
|
|
|
/* shutdown input extension */
|
|
_ecore_xcb_input_shutdown();
|
|
|
|
/* shutdown gesture extension */
|
|
_ecore_xcb_gesture_shutdown();
|
|
|
|
/* shutdown selection */
|
|
_ecore_xcb_selection_shutdown();
|
|
|
|
/* shutdown dnd */
|
|
_ecore_xcb_dnd_shutdown();
|
|
|
|
/* shutdown netwm */
|
|
ecore_x_netwm_shutdown();
|
|
|
|
/* shutdown keymap */
|
|
_ecore_xcb_keymap_shutdown();
|
|
|
|
/* shutdown ecore_event */
|
|
ecore_event_shutdown();
|
|
|
|
/* shutdown ecore */
|
|
ecore_shutdown();
|
|
|
|
/* unregister log domain */
|
|
eina_log_domain_unregister(_ecore_xcb_log_dom);
|
|
_ecore_xcb_log_dom = -1;
|
|
|
|
/* shutdown eina */
|
|
eina_shutdown();
|
|
|
|
return _ecore_xcb_init_count;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
|
{
|
|
xcb_connection_t *conn;
|
|
xcb_generic_event_t *ev = NULL;
|
|
|
|
conn = (xcb_connection_t *)data;
|
|
|
|
if (_ecore_xcb_event_buffered)
|
|
{
|
|
_ecore_xcb_events_handle(_ecore_xcb_event_buffered);
|
|
free(_ecore_xcb_event_buffered);
|
|
_ecore_xcb_event_buffered = NULL;
|
|
}
|
|
|
|
// xcb_flush(conn);
|
|
|
|
while ((ev = xcb_poll_for_event(conn)))
|
|
{
|
|
/* NB: Ecore Xlib uses filterevent for xim, but xcb does not support
|
|
* xim, so no need for it here */
|
|
|
|
/* check for errors first */
|
|
if (xcb_connection_has_error(conn))
|
|
{
|
|
xcb_generic_error_t *err;
|
|
|
|
err = (xcb_generic_error_t *)ev;
|
|
_ecore_xcb_io_error_handle(err);
|
|
}
|
|
else
|
|
{
|
|
/* FIXME: Filter event for XIM */
|
|
_ecore_xcb_events_handle(ev);
|
|
free(ev);
|
|
}
|
|
}
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
|
{
|
|
xcb_connection_t *conn;
|
|
xcb_generic_event_t *ev = NULL;
|
|
|
|
conn = (xcb_connection_t *)data;
|
|
ev = xcb_poll_for_event(conn);
|
|
if (ev)
|
|
{
|
|
/* check for errors first */
|
|
if (xcb_connection_has_error(conn))
|
|
{
|
|
xcb_generic_error_t *err;
|
|
|
|
err = (xcb_generic_error_t *)ev;
|
|
_ecore_xcb_io_error_handle(err);
|
|
return ECORE_CALLBACK_CANCEL;
|
|
}
|
|
_ecore_xcb_event_buffered = ev;
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|
|
return ECORE_CALLBACK_CANCEL;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_ecore_xcb_idle_enter(void *data EINA_UNUSED)
|
|
{
|
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
|
CHECK_XCB_CONN;
|
|
|
|
xcb_flush(_ecore_xcb_conn);
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|