#include "e_x.h" #include "e_mem.h" #include "e_str.h" #include #include #include typedef struct _window_list Window_List; struct _window_list { Window win; Window_List *next; }; static Display *disp; static Visual *default_vis; static Colormap default_cm; static int default_depth; static Window default_win; static Window default_root; static XContext xid_context = 0; static int lock_scroll = 0; static int lock_num = 0; static int lock_caps = 0; static Window focused_win = 0; static int mod_shift = 0; static int mod_ctrl = 0; static int mod_alt = 0; static int mod_win = 0; static Window grabkey_win = 0; static int mouse_x = 0, mouse_y = 0; static Window current_dnd_win = 0; static int current_dnd_target_ok = 0; static int x_grabs = 0; static Window_List *ignore_wins = NULL; static Window grab_pointer_win = 0; static int dnd_copy = 0; static int dnd_link = 0; static int dnd_move = 1; static void e_handle_x_error(Display * d, XErrorEvent * ev); static void e_handle_x_io_error(Display * d); static Window e_window_at_xy_0(Window base, int bx, int by, int x, int y); static void e_handle_x_error(Display * d, XErrorEvent * ev) { /* ignroe all X errors */ return; d = NULL; ev = NULL; } static void e_handle_x_io_error(Display * d) { /* FIXME: call clean exit handler */ exit(1); d = NULL; } void e_del_child(Window win, Window child) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) return; if (xid) { int i; for (i = 0; i < xid->children_num; i++) { if (xid->children[i] == child) { int j; for (j = i; j < xid->children_num - 1; j++) xid->children[j] = xid->children[j + 1]; xid->children_num--; REALLOC(xid->children, Window, xid->children_num); return; } } } } void e_add_child(Window win, Window child) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) return; if (xid) { xid->children_num++; if (!xid->children) xid->children = NEW(Window, xid->children_num); else REALLOC(xid->children, Window, xid->children_num); xid->children[xid->children_num - 1] = child; } } void e_raise_child(Window win, Window child) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) return; if (xid) { int i; for (i = 0; i < xid->children_num; i++) { if (xid->children[i] == child) { int j; for (j = i; j < xid->children_num - 1; j++) xid->children[j] = xid->children[j + 1]; xid->children[xid->children_num - 1] = child; return; } } } } void e_lower_child(Window win, Window child) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) return; if (xid) { int i; for (i = 0; i < xid->children_num; i++) { if (xid->children[i] == child) { int j; for (j = i; j > 0; j--) xid->children[j] = xid->children[j - 1]; xid->children[0] = child; return; } } } } E_XID * e_add_xid(Window win, int x, int y, int w, int h, int depth, Window parent) { E_XID *xid = NULL; e_window_add_events(win, XEV_IN_OUT | XEV_CONFIGURE | XEV_VISIBILITY); xid = NEW(E_XID, 1); xid->win = win; xid->x = x; xid->y = y; xid->w = w; xid->h = h; xid->mapped = 0; xid->depth = depth; xid->mouse_in = 0; xid->parent = parent; xid->root = e_window_get_root(parent); xid->children_num = 0; xid->children = NULL; XSaveContext(disp, xid->win, xid_context, (XPointer) xid); return xid; } E_XID * e_validate_xid(Window win) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) { XWindowAttributes att; Window root_ret = 0, parent_ret = 0, *children_ret = NULL; unsigned int children_ret_num = 0; e_window_add_events(win, XEV_IN_OUT | XEV_CONFIGURE | XEV_VISIBILITY | XEV_CHILD_CHANGE); xid = NEW(E_XID, 1); xid->win = win; if (!XGetWindowAttributes(disp, win, &att)) { FREE(xid); return NULL; } if (!XQueryTree(disp, win, &root_ret, &parent_ret, &children_ret, &children_ret_num)) { FREE(xid); return NULL; } xid->parent = parent_ret; if (xid->parent) e_validate_xid(xid->parent); if (children_ret) { xid->children_num = children_ret_num; xid->children = NEW(Window, children_ret_num); MEMCPY(children_ret, xid->children, Window, children_ret_num); XFree(children_ret); } else { xid->children_num = 0; xid->children = NULL; } xid->root = root_ret; xid->x = att.x; xid->y = att.y; xid->w = att.width; xid->h = att.height; if (att.map_state == IsUnmapped) xid->mapped = 0; else xid->mapped = 1; xid->depth = att.depth; xid->mouse_in = 0; XSaveContext(disp, xid->win, xid_context, (XPointer) xid); } return xid; } void e_unvalidate_xid(Window win) { E_XID *xid = NULL; if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT) return; if (xid) { int i; for (i = 0; i < xid->children_num; i++) e_unvalidate_xid(xid->children[i]); IF_FREE(xid->children); FREE(xid); XDeleteContext(disp, win, xid_context); } } void e_sync(void) { XSync(disp, False); } void e_flush(void) { XFlush(disp); } Window e_window_new(Window parent, int x, int y, int w, int h) { Window win; XSetWindowAttributes attr; if (!parent) parent = default_root; attr.backing_store = NotUseful; attr.override_redirect = False; attr.colormap = default_cm; attr.border_pixel = 0; attr.background_pixmap = None; attr.save_under = False; attr.do_not_propagate_mask = True; win = XCreateWindow(disp, parent, x, y, w, h, 0, default_depth, InputOutput, default_vis, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap | CWBackPixmap | CWBorderPixel | CWDontPropagate, &attr); e_add_xid(win, x, y, w, h, default_depth, parent); return win; } Window e_window_override_new(Window parent, int x, int y, int w, int h) { Window win; XSetWindowAttributes attr; if (!parent) parent = default_root; attr.backing_store = NotUseful; attr.override_redirect = True; attr.colormap = default_cm; attr.border_pixel = 0; attr.background_pixmap = None; attr.save_under = False; attr.do_not_propagate_mask = True; win = XCreateWindow(disp, parent, x, y, w, h, 0, default_depth, InputOutput, default_vis, CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWColormap | CWBackPixmap | CWBorderPixel | CWDontPropagate, &attr); e_add_xid(win, x, y, w, h, default_depth, parent); return win; } Window e_window_input_new(Window parent, int x, int y, int w, int h) { Window win; XSetWindowAttributes attr; if (!parent) parent = default_root; attr.override_redirect = True; attr.do_not_propagate_mask = True; win = XCreateWindow(disp, parent, x, y, w, h, 0, 0, InputOnly, default_vis, CWOverrideRedirect | CWDontPropagate, &attr); e_add_xid(win, x, y, w, h, 0, parent); return win; } void e_window_show(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if (xid->mapped) xid->mapped = 1; XMapWindow(disp, win); } } void e_window_hide(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if (!xid->mapped) return; xid->mapped = 0; XUnmapWindow(disp, win); } } Pixmap e_pixmap_new(Window win, int w, int h, int dep) { if (!win) win = default_win; if (dep == 0) dep = default_depth; return XCreatePixmap(disp, win, w, h, dep); } void e_pixmap_free(Pixmap pmap) { if (!pmap) return; XFreePixmap(disp, pmap); } void e_window_set_background_pixmap(Window win, Pixmap pmap) { XSetWindowBackgroundPixmap(disp, win, pmap); } void e_window_set_shape_mask(Window win, Pixmap mask) { XShapeCombineMask(disp, win, ShapeBounding, 0, 0, mask, ShapeSet); } void e_window_clear(Window win) { XClearWindow(disp, win); } void e_window_clear_area(Window win, int x, int y, int w, int h) { XClearArea(disp, win, x, y, w, h, False); } void e_pointer_xy(Window win, int *x, int *y) { Window dw; unsigned int dm; int wx, wy; if (win == 0) win = default_root; XQueryPointer(disp, win, &dw, &dw, &mouse_x, &mouse_y, &wx, &wy, &dm); if (x) *x = wx; if (y) *y = wy; } void e_pointer_xy_set(int x, int y) { mouse_x = x; mouse_y = y; } void e_pointer_xy_get(int *x, int *y) { if (x) *x = mouse_x; if (y) *y = mouse_y; } void e_window_set_events(Window win, long mask) { if (win == 0) win = default_root; XSelectInput(disp, win, mask); } void e_window_remove_events(Window win, long mask) { XWindowAttributes att; if (win == 0) win = default_root; if (XGetWindowAttributes(disp, win, &att) == True) { mask = att.your_event_mask & (~mask); e_window_set_events(win, mask); } } void e_window_add_events(Window win, long mask) { XWindowAttributes att; if (win == 0) win = default_root; if (XGetWindowAttributes(disp, win, &att) == True) { mask = att.your_event_mask | mask; e_window_set_events(win, mask); } } void e_window_move(Window win, int x, int y) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if ((xid->x == x) && (xid->y == y)) return; xid->x = x; xid->y = y; XMoveWindow(disp, win, x, y); } } void e_window_resize(Window win, int w, int h) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if ((xid->w == w) && (xid->h == h)) return; xid->w = w; xid->h = h; XResizeWindow(disp, win, w, h); } } void e_window_move_resize(Window win, int x, int y, int w, int h) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if ((xid->x == x) && (xid->y == y) && (xid->w == w) && (xid->h == h)) return; xid->x = x; xid->y = y; xid->w = w; xid->h = h; XMoveResizeWindow(disp, win, x, y, w, h); } } int e_x_get_fd(void) { return ConnectionNumber(disp); } void e_display_init(char *display) { int revert; xid_context = XUniqueContext(); disp = XOpenDisplay(display); if (!disp) { char *d; d = getenv("DISPLAY"); if (d) fprintf(stderr, "Fatal Error:\n" "Cannot connect to the display nominated by your DISPLAY variable:\n" "%s\n" "Try changing your DISPLAY variable like:\n" "DISPLAY=host:0 efm\n", d); else fprintf(stderr, "Fatal Error:\n" "No DISPLAY variable set so cannot determine display to connect to.\n" "Try setting your DISPLAY variable like:\n" "DISPLAY=host:0 efm\n"); exit(1); } XSetErrorHandler((XErrorHandler) e_handle_x_error); XSetIOErrorHandler((XIOErrorHandler) e_handle_x_io_error); default_vis = DefaultVisual(disp, DefaultScreen(disp)); default_depth = DefaultDepth(disp, DefaultScreen(disp)); default_cm = DefaultColormap(disp, DefaultScreen(disp)); default_win = DefaultRootWindow(disp); default_root = DefaultRootWindow(disp); mod_shift = e_mod_mask_shift_get(); mod_ctrl = e_mod_mask_ctrl_get(); mod_alt = e_mod_mask_alt_get(); mod_win = e_mod_mask_win_get(); XGetInputFocus(disp, &focused_win, &revert); e_window_set_events(default_root, XEV_KEY | XEV_IN_OUT | XEV_MOUSE_MOVE | XEV_CONFIGURE | XEV_CHILD_CHANGE | XEV_PROPERTY | XEV_COLORMAP | XEV_VISIBILITY); e_pointer_xy(0, NULL, NULL); imlib_context_set_display(disp); imlib_context_set_visual(default_vis); imlib_context_set_colormap(default_cm); imlib_context_set_drawable(default_root); imlib_context_set_dither(0); imlib_context_set_blend(1); } int e_events_pending(void) { if (!disp) return 0; return XPending(disp); } void e_get_next_event(XEvent * event) { XNextEvent(disp, event); } int e_event_shape_get_id(void) { int base = -1, err_base; XShapeQueryExtension(disp, &base, &err_base); base += ShapeNotify; return base; } KeySym e_key_get_keysym_from_keycode(KeyCode keycode) { return XKeycodeToKeysym(disp, keycode, 0); } char * e_key_get_string_from_keycode(KeyCode keycode) { return e_string_dup(XKeysymToString(e_key_get_keysym_from_keycode(keycode))); } void e_event_allow(int mode, Time t) { XAllowEvents(disp, mode, t); } int e_lock_mask_scroll_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Scroll_Lock); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_lock_mask_num_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Num_Lock); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_lock_mask_caps_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Caps_Lock); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_mod_mask_shift_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Shift_L); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_mod_mask_ctrl_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Control_L); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_mod_mask_alt_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Alt_L); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_mod_mask_win_get(void) { static int have_mask = 0; static int mask = 0; XModifierKeymap *mod; KeyCode nl; int i; int masks[8] = { ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; if (have_mask) return mask; mod = XGetModifierMapping(disp); nl = XKeysymToKeycode(disp, XK_Meta_L); if ((mod) && (mod->max_keypermod > 0)) { for (i = 0; i < (8 * mod->max_keypermod); i++) { if ((nl) && (mod->modifiermap[i] == nl)) { mask = masks[i / mod->max_keypermod]; if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); if (mask == e_mod_mask_alt_get()) mask = 0; if (mask == e_mod_mask_ctrl_get()) mask = 0; have_mask = 1; return mask; } } } if (mod) { if (mod->modifiermap) XFree(mod->modifiermap); XFree(mod); } return 0; } int e_lock_mask_get(void) { static int mask = 0; Window root_ret, child_ret; int root_x_ret, root_y_ret, win_x_ret, win_y_ret; unsigned int mask_ret; if (!mask) mask = e_lock_mask_scroll_get() | e_lock_mask_num_get() | e_lock_mask_caps_get(); XQueryPointer(disp, default_root, &root_ret, &child_ret, &root_x_ret, &root_y_ret, &win_x_ret, &win_y_ret, &mask_ret); return (mask_ret & mask); } int e_modifier_mask_get(void) { Window root_ret, child_ret; int root_x_ret, root_y_ret, win_x_ret, win_y_ret; unsigned int mask_ret; XQueryPointer(disp, default_root, &root_ret, &child_ret, &root_x_ret, &root_y_ret, &win_x_ret, &win_y_ret, &mask_ret); return (mask_ret); } Window e_get_key_grab_win(void) { return grabkey_win; } void e_key_grab(char *key, Ev_Key_Modifiers mods, int anymod, int sync) { KeyCode keycode; int i, mod, mask_scroll, mask_num, mask_caps, masks[8], mode; keycode = e_key_get_keycode(key); mod = 0; mode = GrabModeAsync; if (sync) mode = GrabModeSync; if (!grabkey_win) grabkey_win = default_root; if (mods & EV_KEY_MODIFIER_SHIFT) mod |= mod_shift; if (mods & EV_KEY_MODIFIER_CTRL) mod |= mod_ctrl; if (mods & EV_KEY_MODIFIER_ALT) mod |= mod_alt; if (mods & EV_KEY_MODIFIER_WIN) mod |= mod_win; mask_scroll = e_lock_mask_scroll_get(); mask_num = e_lock_mask_num_get(); mask_caps = e_lock_mask_caps_get(); masks[0] = 0; masks[1] = mask_scroll; masks[2] = mask_num; masks[3] = mask_caps; masks[4] = mask_scroll | mask_num; masks[5] = mask_scroll | mask_caps; masks[6] = mask_num | mask_caps; masks[7] = mask_scroll | mask_num | mask_caps; if (anymod) XGrabKey(disp, keycode, AnyModifier, grabkey_win, False, mode, mode); else { for (i = 0; i < 8; i++) XGrabKey(disp, keycode, masks[i] | mod, grabkey_win, False, mode, mode); } } void e_key_ungrab(char *key, Ev_Key_Modifiers mods, int anymod) { KeyCode keycode; keycode = e_key_get_keycode(key); if (anymod) XUngrabKey(disp, keycode, AnyModifier, default_root); else { int i, mod, mask_scroll, mask_num, mask_caps, masks[8]; mod = 0; if (mods & EV_KEY_MODIFIER_SHIFT) mod |= mod_shift; if (mods & EV_KEY_MODIFIER_CTRL) mod |= mod_ctrl; if (mods & EV_KEY_MODIFIER_ALT) mod |= mod_alt; if (mods & EV_KEY_MODIFIER_WIN) mod |= mod_win; mask_scroll = e_lock_mask_scroll_get(); mask_num = e_lock_mask_num_get(); mask_caps = e_lock_mask_caps_get(); masks[0] = 0; masks[1] = mask_scroll; masks[2] = mask_num; masks[3] = mask_caps; masks[4] = mask_scroll | mask_num; masks[5] = mask_scroll | mask_caps; masks[6] = mask_num | mask_caps; masks[7] = mask_scroll | mask_num | mask_caps; for (i = 0; i < 8; i++) XUngrabKey(disp, keycode, masks[i] | mod, grabkey_win); } } KeyCode e_key_get_keycode(char *key) { return XKeysymToKeycode(disp, XStringToKeysym(key)); } void e_window_destroy(Window win) { e_unvalidate_xid(win); XDestroyWindow(disp, win); } void e_window_reparent(Window win, Window parent, int x, int y) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { if (parent == 0) parent = default_root; XReparentWindow(disp, win, parent, x, y); e_del_child(xid->parent, win); e_add_child(parent, win); xid->parent = parent; xid->x = x; xid->y = y; } } void e_window_raise(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { XRaiseWindow(disp, win); e_raise_child(xid->parent, win); } } void e_window_lower(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) { XLowerWindow(disp, win); e_lower_child(xid->parent, win); } } void e_window_get_geometry(Window win, int *x, int *y, int *w, int *h) { E_XID *xid = NULL; if (win == 0) win = default_root; xid = e_validate_xid(win); if (xid) { if (x) *x = xid->x; if (y) *y = xid->y; if (w) *w = xid->w; if (h) *h = xid->h; } else { if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0; } } int e_window_get_depth(Window win) { E_XID *xid = NULL; if (win == 0) win = default_root; xid = e_validate_xid(win); if (xid) return xid->depth; return -1; } int e_window_exists(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) return 1; return 0; } Window e_window_get_parent(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) return xid->parent; return 0; } Window * e_window_get_children(Window win, int *num) { E_XID *xid = NULL; if (win == 0) win = default_root; xid = e_validate_xid(win); if (xid) { Window *wlist = NULL; *num = xid->children_num; if (xid->children) { wlist = NEW(Window, xid->children_num); MEMCPY(xid->children, wlist, Window, xid->children_num); } return wlist; } *num = 0; return NULL; } int e_window_mouse_in(Window win) { E_XID *xid = NULL; if (win == 0) win = default_root; xid = e_validate_xid(win); if (xid) return xid->mouse_in; return 0; } void e_window_mouse_set_in(Window win, int in) { E_XID *xid = NULL; if (win == 0) win = default_root; xid = e_validate_xid(win); if (xid) xid->mouse_in = in; } Display * e_display_get(void) { return disp; } Window e_window_get_root(Window win) { E_XID *xid = NULL; xid = e_validate_xid(win); if (xid) return xid->root; return 0; } void e_lock_scroll_set(int onoff) { lock_scroll = onoff; } int e_lock_scroll_get(void) { return lock_scroll; } void e_lock_num_set(int onoff) { lock_num = onoff; } int e_lock_num_get(void) { return lock_num; } void e_lock_caps_set(int onoff) { lock_caps = onoff; } int e_lock_caps_get(void) { return lock_caps; } void e_mod_shift_set(int onoff) { mod_shift = onoff; } int e_mod_shift_get(void) { return mod_shift; } void e_mod_ctrl_set(int onoff) { mod_ctrl = onoff; } int e_mod_ctrl_get(void) { return mod_ctrl; } void e_mod_alt_set(int onoff) { mod_alt = onoff; } int e_mod_alt_get(void) { return mod_alt; } void e_mod_win_set(int onoff) { mod_win = onoff; } int e_mod_win_get(void) { return mod_win; } void e_focus_window_set(Window win) { focused_win = win; } Window e_focus_window_get(void) { return focused_win; } void e_focus_to_window(Window win) { if (win == 0) win = default_root; XSetInputFocus(disp, win, RevertToPointerRoot, CurrentTime); } Atom e_atom_get(char *name) { return XInternAtom(disp, name, False); } void e_window_set_delete_inform(Window win) { static Atom protocols[1] = { 0 }; E_ATOM(protocols[0], "WM_DELETE_WINDOW"); XSetWMProtocols(disp, win, protocols, 1); } void e_window_property_set(Window win, Atom type, Atom format, int size, void *data, int number) { if (win == 0) win = default_root; if (size != 32) XChangeProperty(disp, win, type, format, size, PropModeReplace, (unsigned char *)data, number); else { long *dat; int i, *ptr; dat = NEW(long, number); for (ptr = (int *)data, i = 0; i < number; i++) dat[i] = ptr[i]; XChangeProperty(disp, win, type, format, size, PropModeReplace, (unsigned char *)dat, number); FREE(dat); } } void * e_window_property_get(Window win, Atom type, Atom format, int *size) { unsigned char *retval; Atom type_ret; unsigned long bytes_after, num_ret; int format_ret; void *data = NULL; retval = NULL; if (win == 0) win = default_root; XGetWindowProperty(disp, win, type, 0, 0x7fffffffL, False, format, &type_ret, &format_ret, &num_ret, &bytes_after, &retval); if (retval) { if (format_ret == 32) { int i; *size = num_ret * sizeof(unsigned int); data = NEW(unsigned int, num_ret); for (i = 0; i < (int)num_ret; i++) ((unsigned int *)data)[i] = ((unsigned long *)retval)[i]; } else if (format_ret == 16) { int i; *size = num_ret * sizeof(unsigned short); data = NEW(unsigned short, *size); for (i = 0; i < (int)num_ret; i++) ((unsigned short *)data)[i] = ((unsigned short *)retval)[i]; } else if (format_ret == 8) { /* format_ret == 8 */ *size = num_ret; data = NEW(char, num_ret); if (data) memcpy(data, retval, num_ret); } XFree(retval); return data; } *size = 0; return NULL; } void e_window_dnd_advertise(Window win) { static Atom atom_xdndaware = 0; int dnd_version = 3; E_ATOM(atom_xdndaware, "XdndAware"); e_window_property_set(win, atom_xdndaware, XA_ATOM, 32, &dnd_version, 1); } void e_grab(void) { x_grabs++; if (x_grabs == 1) XGrabServer(disp); } void e_ungrab(void) { x_grabs--; if (x_grabs == 0) { XUngrabServer(disp); e_sync(); } } void e_window_ignore(Window win) { Window_List *w; if (win == 0) win = default_root; w = NEW(Window_List, 1); w->win = win; w->next = ignore_wins; ignore_wins = w; } void e_window_no_ignore(Window win) { Window_List *w, *pw; if (win == 0) win = default_root; for (pw = NULL, w = ignore_wins; w; pw = w, w = w->next) { if (w->win == win) { if (pw) pw->next = w->next; else ignore_wins = w->next; FREE(w); return; } } } int e_window_is_ignored(Window win) { Window_List *w; if (win == 0) win = default_root; for (w = ignore_wins; w; w = w->next) { if (w->win == win) return 1; } return 0; } static Window e_window_at_xy_0(Window base, int bx, int by, int x, int y) { Window *list = NULL; XWindowAttributes att; Window child = 0, parent_win = 0, root_win = 0; int i; unsigned int ww, wh, num; int wx, wy; if ((!XGetWindowAttributes(disp, base, &att)) || (att.map_state != IsViewable)) return 0; wx = att.x; wy = att.y; ww = att.width; wh = att.height; wx += bx; wy += by; if (!((x >= wx) && (y >= wy) && (x < (int)(wx + ww)) && (y < (int)(wy + wh)))) return 0; if (!XQueryTree(disp, base, &root_win, &parent_win, &list, &num)) return base; if (list) { for (i = num - 1;; i--) { if (!e_window_is_ignored(list[i])) { if ((child = e_window_at_xy_0(list[i], wx, wy, x, y)) != 0) { XFree(list); return child; } } if (!i) break; } XFree(list); } return base; } Window e_window_get_at_xy(int x, int y) { Window child; e_grab(); child = e_window_at_xy_0(default_root, 0, 0, x, y); if (child) { e_ungrab(); return child; } e_ungrab(); return default_root; } int e_window_dnd_capable(Window win) { static Atom atom_xdndaware = 0; int dnd_version = 3; int *atom_ret; int size = 0; E_ATOM(atom_xdndaware, "XdndAware"); atom_ret = e_window_property_get(win, atom_xdndaware, XA_ATOM, &size); if ((atom_ret) && (size >= sizeof(int))) { if (atom_ret[0] == dnd_version) { FREE(atom_ret); return 1; } FREE(atom_ret); } return 0; } void e_window_dnd_handle_motion(Window source_win, int x, int y, int dragging) { static Atom atom_xdndenter = 0; static Atom atom_xdndleave = 0; static Atom atom_xdnddrop = 0; static Atom atom_xdndposition = 0; static Atom atom_xdndactioncopy = 0; static Atom atom_xdndactionmove = 0; static Atom atom_xdndactionlink = 0; static Atom atom_xdndactionask = 0; static Atom atom_text_uri_list = 0; static Atom atom_text_plain = 0; Window win; XEvent xevent; win = e_window_get_at_xy(x, y); while ((win) && (!e_window_dnd_capable(win))) win = e_window_get_parent(win); E_ATOM(atom_xdndenter, "XdndEnter"); E_ATOM(atom_xdndleave, "XdndLeave"); E_ATOM(atom_xdnddrop, "XdndDrop"); E_ATOM(atom_xdndposition, "XdndPosition"); E_ATOM(atom_xdndactioncopy, "XdndActionCopy"); E_ATOM(atom_xdndactionmove, "XdndActionMove"); E_ATOM(atom_xdndactionlink, "XdndActionLink"); E_ATOM(atom_xdndactionask, "XdndActionAsk"); E_ATOM(atom_text_uri_list, "text/uri-list"); E_ATOM(atom_text_plain, "text/plain"); if ((win != current_dnd_win) && (current_dnd_win)) { /* send leave to old dnd win */ xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.format = 32; xevent.xclient.window = current_dnd_win; xevent.xclient.message_type = atom_xdndleave; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = 0; xevent.xclient.data.l[2] = 0; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; XSendEvent(disp, current_dnd_win, False, 0, &xevent); } if (win) { if (win != current_dnd_win) { /* send enter on new win */ xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdndenter; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = (3 << 24); xevent.xclient.data.l[2] = atom_text_uri_list; xevent.xclient.data.l[3] = atom_text_plain; xevent.xclient.data.l[4] = 0; XSendEvent(disp, win, False, 0, &xevent); } /* send position information */ xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdndposition; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = (3 << 24); xevent.xclient.data.l[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); xevent.xclient.data.l[3] = CurrentTime; if (dnd_copy) xevent.xclient.data.l[4] = atom_xdndactioncopy; else if (dnd_link) xevent.xclient.data.l[4] = atom_xdndactionlink; else if (dnd_move) xevent.xclient.data.l[4] = atom_xdndactionmove; else xevent.xclient.data.l[4] = atom_xdndactionask; XSendEvent(disp, win, False, 0, &xevent); } if (!dragging) { if (win) { if (current_dnd_target_ok) { xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdnddrop; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = 0; xevent.xclient.data.l[2] = CurrentTime; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; XSendEvent(disp, win, False, 0, &xevent); } else { xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdndleave; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = 0; xevent.xclient.data.l[2] = 0; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; XSendEvent(disp, win, False, 0, &xevent); } } current_dnd_target_ok = 0; } current_dnd_win = win; } int e_dnd_selection_convert(Window win, Window req, Atom type) { static Atom atom_xdndselection = 0; static Atom atom_jxselectionwindowproperty = 0; E_ATOM(atom_xdndselection, "XdndSelection"); E_ATOM(atom_jxselectionwindowproperty, "JXSelectionWindowProperty"); if (win == XGetSelectionOwner(disp, atom_xdndselection)) { XConvertSelection(disp, atom_xdndselection, type, atom_jxselectionwindowproperty, req, CurrentTime); return 1; } return 0; } void * e_dnd_selection_get(Window win, Window req, Atom type, int *size) { unsigned char *data = NULL; long bytes_read; unsigned long remaining = 1; *size = 0; bytes_read = 0; while (remaining) { unsigned char *s; Atom actual; int format; unsigned long count; s = NULL; if (XGetWindowProperty(disp, win, type, bytes_read / 4, 0x10000, 1, AnyPropertyType, &actual, &format, &count, &remaining, &s) != Success) { /* error occured */ XFree(s); IF_FREE(data); *size = 0; return NULL; } if (s) { /* got some mroe data - append it */ bytes_read += count; if (!data) data = NEW(char, bytes_read); else REALLOC(data, char, bytes_read); MEMCPY(s, data + (bytes_read - count), char, count); XFree(s); } } *size = bytes_read; return data; req = 0; } void e_dnd_set_data(Window win) { static int atom_xdndactioncopy = 0; static int atom_xdndactionmove = 0; static int atom_xdndactionlink = 0; static int atom_xdndactionask = 0; static Atom atom_xdndactionlist = 0; static Atom atom_xdndselection = 0; E_ATOM(atom_xdndactioncopy, "XdndActionCopy"); E_ATOM(atom_xdndactionmove, "XdndActionMove"); E_ATOM(atom_xdndactionlink, "XdndActionLink"); E_ATOM(atom_xdndactionask, "XdndActionAsk"); E_ATOM(atom_xdndactionlist, "XdndActionList"); E_ATOM(atom_xdndselection, "XdndSelection"); if (dnd_copy) e_window_property_set(win, atom_xdndactionlist, XA_ATOM, 32, &atom_xdndactioncopy, 1); else if (dnd_link) e_window_property_set(win, atom_xdndactionlist, XA_ATOM, 32, &atom_xdndactionlink, 1); else if (dnd_move) e_window_property_set(win, atom_xdndactionlist, XA_ATOM, 32, &atom_xdndactionmove, 1); else e_window_property_set(win, atom_xdndactionlist, XA_ATOM, 32, &atom_xdndactionask, 1); XSetSelectionOwner(disp, atom_xdndselection, win, CurrentTime); } void e_dnd_send_data(Window win, Window source_win, void *data, int size, Atom dest_atom, int plain_text) { XEvent xevent; static Atom atom_text_plain = 0; static Atom atom_text_uri_list = 0; static Atom atom_xdndselection = 0; Atom target; E_ATOM(atom_xdndselection, "XdndSelection"); E_ATOM(atom_text_uri_list, "text/uri-list"); E_ATOM(atom_text_plain, "text/plain"); target = atom_text_uri_list; if (plain_text) target = atom_text_plain; e_window_property_set(win, dest_atom, target, 8, data, size); xevent.xselection.type = SelectionNotify; xevent.xselection.property = dest_atom; xevent.xselection.display = disp; xevent.xselection.requestor = win; xevent.xselection.selection = atom_xdndselection; xevent.xselection.target = target; xevent.xselection.time = CurrentTime; XSendEvent(disp, win, False, 0, &xevent); return; source_win = 0; } void e_dnd_set_mode_copy(void) { dnd_copy = 1; dnd_link = 0; dnd_move = 0; } void e_dnd_set_mode_link(void) { dnd_copy = 0; dnd_link = 1; dnd_move = 0; } void e_dnd_set_mode_move(void) { dnd_copy = 0; dnd_link = 0; dnd_move = 1; } void e_dnd_set_mode_ask(void) { dnd_copy = 0; dnd_link = 0; dnd_move = 0; } void e_dnd_own_selection(Window win) { static Atom atom_xdndselection = 0; static Atom atom_jxselectionwindowproperty = 0; E_ATOM(atom_xdndselection, "XdndSelection"); E_ATOM(atom_jxselectionwindowproperty, "JXSelectionWindowProperty"); if (!XSetSelectionOwner(disp, atom_xdndselection, win, CurrentTime)) return; } void e_dnd_send_drop(Window win, Window source_win) { static Atom atom_xdnddrop = 0; XEvent xevent; E_ATOM(atom_xdnddrop, "XdndDrop"); e_dnd_own_selection(source_win); memset(&xevent, 0, sizeof(xevent)); xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdnddrop; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = CurrentTime; xevent.xclient.data.l[2] = 0; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; XSendEvent(disp, win, False, 0, &xevent); } void e_window_dnd_send_status_ok(Window source_win, Window win, int x, int y, int w, int h) { static Atom atom_xdndstatus = 0; static Atom atom_xdndactioncopy = 0; static Atom atom_xdndactionmove = 0; static Atom atom_xdndactionlink = 0; static Atom atom_xdndactionask = 0; XEvent xevent; E_ATOM(atom_xdndstatus, "XdndStatus"); E_ATOM(atom_xdndactioncopy, "XdndActionCopy"); E_ATOM(atom_xdndactionmove, "XdndActionMove"); E_ATOM(atom_xdndactionlink, "XdndActionLink"); E_ATOM(atom_xdndactionask, "XdndActionAsk"); memset(&xevent, 0, sizeof(xevent)); xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdndstatus; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = 3; xevent.xclient.data.l[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); xevent.xclient.data.l[3] = ((h << 16) & 0xffff0000) | (w & 0xffff); if (dnd_copy) xevent.xclient.data.l[4] = atom_xdndactioncopy; else if (dnd_link) xevent.xclient.data.l[4] = atom_xdndactionlink; else if (dnd_move) xevent.xclient.data.l[4] = atom_xdndactionmove; else xevent.xclient.data.l[4] = atom_xdndactionask; XSendEvent(disp, win, False, 0, &xevent); } void e_window_dnd_send_finished(Window source_win, Window win) { static Atom atom_xdndfinished = 0; XEvent xevent; E_ATOM(atom_xdndfinished, "XdndFinished"); memset(&xevent, 0, sizeof(xevent)); xevent.xany.type = ClientMessage; xevent.xany.display = disp; xevent.xclient.window = win; xevent.xclient.message_type = atom_xdndfinished; xevent.xclient.format = 32; xevent.xclient.data.l[0] = source_win; xevent.xclient.data.l[1] = 0; xevent.xclient.data.l[2] = 0; xevent.xclient.data.l[3] = 0; xevent.xclient.data.l[4] = 0; XSendEvent(disp, win, False, 0, &xevent); } void e_window_dnd_ok(int ok) { current_dnd_target_ok = ok; } void e_window_dnd_finished(void) { current_dnd_win = 0; } void e_window_set_title(Window win, char *title) { XStoreName(disp, win, title); } void e_window_set_name_class(Window win, char *name, char *class) { XClassHint hint; hint.res_name = name; hint.res_class = class; XSetClassHint(disp, win, &hint); } void e_window_set_min_size(Window win, int w, int h) { XSizeHints hints; long ret; memset(&hints, 0, sizeof(XSizeHints)); XGetWMNormalHints(disp, win, &hints, &ret); hints.flags |= PMinSize | PSize | USSize; hints.min_width = w; hints.min_height = h; XSetWMNormalHints(disp, win, &hints); } void e_window_set_max_size(Window win, int w, int h) { XSizeHints hints; long ret; memset(&hints, 0, sizeof(XSizeHints)); XGetWMNormalHints(disp, win, &hints, &ret); hints.flags |= PMaxSize | PSize | USSize; hints.max_width = w; hints.max_height = h; XSetWMNormalHints(disp, win, &hints); } void e_window_set_xy_hints(Window win, int x, int y) { XSizeHints hints; long ret; memset(&hints, 0, sizeof(XSizeHints)); XGetWMNormalHints(disp, win, &hints, &ret); hints.flags |= PPosition | USPosition | PSize | USSize; hints.x = x; hints.y = y; XSetWMNormalHints(disp, win, &hints); } void e_window_get_frame_size(Window win, int *l, int *r, int *t, int *b) { static Atom atom_e_frame_size = 0; int *data, size; E_ATOM(atom_e_frame_size, "_E_FRAME_SIZE"); data = e_window_property_get(win, atom_e_frame_size, XA_CARDINAL, &size); if (data) { if (size == (4 * sizeof(int))) { if (l) *l = data[0]; if (r) *r = data[1]; if (t) *t = data[2]; if (b) *b = data[3]; } else { if (l) *l = 0; if (r) *r = 0; if (t) *t = 0; if (b) *b = 0; } FREE(data); } else { if (l) *l = 0; if (r) *r = 0; if (t) *t = 0; if (b) *b = 0; } } int e_window_save_under(Window win) { XSetWindowAttributes att; XWindowAttributes gatt; att.save_under = True; XChangeWindowAttributes(disp, win, CWSaveUnder, &att); XGetWindowAttributes(disp, win, &gatt); if (gatt.save_under == True) return 1; return 0; } GC e_gc_new(Drawable d) { XGCValues gcv; if (d == 0) d = default_root; return XCreateGC(disp, d, 0, &gcv); } void e_gc_free(GC gc) { XFreeGC(disp, gc); } void e_gc_set_fg(GC gc, int val) { XSetForeground(disp, gc, val); } void e_fill_rectangle(Drawable d, GC gc, int x, int y, int w, int h) { XFillRectangle(disp, d, gc, x, y, w, h); } void e_draw_rectangle(Drawable d, GC gc, int x, int y, int w, int h) { XDrawRectangle(disp, d, gc, x, y, w - 1, h - 1); } void e_draw_line(Drawable d, GC gc, int x1, int y1, int x2, int y2) { XDrawLine(disp, d, gc, x1, y1, x2, y2); } void e_window_hint_set_layer(Window win, int layer) { static Atom atom_win_layer = 0; E_ATOM(atom_win_layer, "_WIN_LAYER"); e_window_property_set(win, atom_win_layer, XA_CARDINAL, 32, &layer, 1); } void e_window_hint_set_sticky(Window win, int sticky) { static Atom atom_win_state = 0; static Atom atom_win_hints = 0; int data; E_ATOM(atom_win_state, "_WIN_STATE"); E_ATOM(atom_win_hints, "_WIN_HINTS"); if (sticky) { data = ((1 << 0) | (1 << 8) | (1 << 9)); e_window_property_set(win, atom_win_state, XA_CARDINAL, 32, &data, 1); data = ((1 << 0) | (1 << 1) | (1 << 2)); e_window_property_set(win, atom_win_hints, XA_CARDINAL, 32, &data, 1); } else { data = 0; e_window_property_set(win, atom_win_state, XA_CARDINAL, 32, &data, 1); e_window_property_set(win, atom_win_hints, XA_CARDINAL, 32, &data, 1); } } void e_window_hint_set_borderless(Window win) { static Atom atom_motif_wm_hints = 0; int data[5]; E_ATOM(atom_motif_wm_hints, "_MOTIF_WM_HINTS"); data[0] = 0x3; data[1] = 0x0; data[2] = 0x0; data[3] = 0x2ada27b0; data[4] = 0x2aabd6b0; e_window_property_set(win, atom_motif_wm_hints, atom_motif_wm_hints, 32, data, 5); } void e_grab_mouse(Window win, int confine, Cursor cursor) { int ret; if (confine) ret = XGrabPointer(disp, win, False, XEV_BUTTON | XEV_MOUSE_MOVE | XEV_IN_OUT, GrabModeAsync, GrabModeAsync, win, cursor, CurrentTime); else ret = XGrabPointer(disp, win, False, XEV_BUTTON | XEV_MOUSE_MOVE | XEV_IN_OUT, GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); if (ret == GrabSuccess) grab_pointer_win = win; } void e_ungrab_mouse(void) { XUngrabPointer(disp, CurrentTime); grab_pointer_win = 0; } Window e_grab_window_get(void) { return grab_pointer_win; } void e_window_gravity_reset(Window win) { XSetWindowAttributes att; att.win_gravity = NorthWestGravity; XChangeWindowAttributes(disp, win, CWWinGravity, &att); } void e_pointer_warp_by(int dx, int dy) { XWarpPointer(disp, None, None, 0, 0, 0, 0, dx, dy); } void e_pointer_warp_to(int x, int y) { XWarpPointer(disp, None, default_root, 0, 0, 0, 0, x, y); } void e_gc_set_include_inferiors(GC gc) { XGCValues gcv; gcv.subwindow_mode = IncludeInferiors; XChangeGC(disp, gc, GCSubwindowMode, &gcv); } void e_area_copy(Drawable src, Drawable dest, GC gc, int sx, int sy, int sw, int sh, int dx, int dy) { if (src == 0) src = default_root; if (dest == 0) dest = default_root; XCopyArea(disp, src, dest, gc, sx, sy, sw, sh, dx, dy); } Window e_window_root(void) { return default_root; } void e_window_get_virtual_area(Window win, int *area_x, int *area_y) { static Atom atom_win_area = 0; int *data, size; E_ATOM(atom_win_area, "_WIN_AREA"); data = e_window_property_get(win, atom_win_area, XA_CARDINAL, &size); if (data) { if (size == (sizeof(int) * 2)) { if (area_x) *area_x = data[0]; if (area_y) *area_y = data[1]; } FREE(data); } } void e_get_virtual_area(int *area_x, int *area_y) { static Atom atom_win_area = 0; int *data, size; E_ATOM(atom_win_area, "_WIN_AREA"); data = e_window_property_get(default_root, atom_win_area, XA_CARDINAL, &size); if (data) { if (size == (sizeof(int) * 2)) { if (area_x) *area_x = data[0]; if (area_y) *area_y = data[1]; } FREE(data); } }