#include "e.h" //#define INOUTDEBUG_MOUSE 1 //#define INOUTDEBUG_FOCUS 1 /* local subsystem functions */ static void _e_border_pri_raise(E_Border *bd); static void _e_border_pri_norm(E_Border *bd); static void _e_border_free(E_Border *bd); static void _e_border_del(E_Border *bd); #ifdef PRINT_LOTS_OF_DEBUG #define E_PRINT_BORDER_INFO(X) \ _e_border_print(X, __PRETTY_FUNC__) static void _e_border_print(E_Border *bd, const char *func); #endif static void _e_border_shadow(E_Border *bd); /* FIXME: these likely belong in a separate icccm/client handler */ /* and the border needs to become a dumb object that just does what its */ /* told to do */ static Eina_Bool _e_border_cb_window_show_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_destroy(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_hide(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_reparent(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_configure_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_resize_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_gravity(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_stack_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_property(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_colormap(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_shape(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_focus_in(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_focus_out(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_client_message(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_state_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_window_move_resize_request(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_desktop_change(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_sync_alarm(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_efreet_cache_update(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_config_icon_theme(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_config_mode(void *data, int ev_type, void *ev); static Eina_Bool _e_border_cb_pointer_warp(void *data, int ev_type, void *ev); static void _e_border_cb_signal_bind(void *data, Evas_Object *obj, const char *emission, const char *source); static Eina_Bool _e_border_cb_grab_replay(void *data, int type, void *event); static void _e_border_cb_drag_finished(E_Drag *drag, int dropped); #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) static Eina_Bool _e_border_cb_desk_window_profile_change(void *data, int ev_type, void *ev); #endif static void _e_border_eval(E_Border *bd); static void _e_border_eval0(E_Border *bd); static void _e_border_container_layout_hook(E_Container *con); static void _e_border_moveinfo_gather(E_Border *bd, const char *source); static void _e_border_resize_handle(E_Border *bd); static Eina_Bool _e_border_shade_animator(void *data); static void _e_border_event_border_add_free(void *data, void *ev); static void _e_border_event_border_remove_free(void *data, void *ev); static void _e_border_event_border_zone_set_free(void *data, void *ev); static void _e_border_event_border_desk_set_free(void *data, void *ev); static void _e_border_event_border_stack_free(void *data, void *ev); static void _e_border_event_border_icon_change_free(void *data, void *ev); static void _e_border_event_border_title_change_free(void *data, void *ev); static void _e_border_event_border_urgent_change_free(void *data, void *ev); static void _e_border_event_border_focus_in_free(void *data, void *ev); static void _e_border_event_border_focus_out_free(void *data, void *ev); static void _e_border_event_border_resize_free(void *data, void *ev); static void _e_border_event_border_move_free(void *data, void *ev); static void _e_border_event_border_show_free(void *data, void *ev); static void _e_border_event_border_hide_free(void *data, void *ev); static void _e_border_event_border_iconify_free(void *data, void *ev); static void _e_border_event_border_uniconify_free(void *data, void *ev); static void _e_border_event_border_stick_free(void *data, void *ev); static void _e_border_event_border_unstick_free(void *data, void *ev); static void _e_border_event_border_property_free(void *data, void *ev); static void _e_border_event_border_fullscreen_free(void *data, void *ev); static void _e_border_event_border_unfullscreen_free(void *data, void *ev); static void _e_border_zone_update(E_Border *bd); static int _e_border_resize_begin(E_Border *bd); static int _e_border_resize_end(E_Border *bd); static void _e_border_resize_update(E_Border *bd); static int _e_border_move_begin(E_Border *bd); static int _e_border_move_end(E_Border *bd); static void _e_border_move_update(E_Border *bd); static Eina_Bool _e_border_cb_ping_poller(void *data); static Eina_Bool _e_border_cb_kill_timer(void *data); static void _e_border_hook_call(E_Border_Hook_Point hookpoint, void *bd); static void _e_border_client_move_resize_send(E_Border *bd); static void _e_border_shape_input_rectangle_set(E_Border *bd); static void _e_border_show(E_Border *bd); static void _e_border_hide(E_Border *bd); static void _e_border_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static void _e_border_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static void _e_border_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static void _e_border_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static void _e_border_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static void _e_border_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info); static Eina_Bool _e_border_cb_mouse_x_wheel(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Wheel *ev); static Eina_Bool _e_border_cb_mouse_x_up(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Button *ev); static Eina_Bool _e_border_cb_mouse_x_down(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Button *ev); static Eina_Bool _e_border_cb_mouse_x_move(void *d, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev); static Eina_Bool _e_border_cb_mouse_x_in(void *d, int t EINA_UNUSED, Ecore_X_Event_Mouse_In *ev); static Eina_Bool _e_border_cb_mouse_x_out(void *d, int t EINA_UNUSED, Ecore_X_Event_Mouse_Out *ev); static void _e_border_action_finish(void); static void _e_border_move_lost_window_to_center(E_Border *bd); static void _e_border_reset_lost_window(E_Border *bd); static Eina_Bool _e_border_pointer_warp_to_center_timer(void *data); /* local subsystem globals */ static Eina_List *handlers = NULL; static Eina_List *borders = NULL; static Eina_Hash *borders_hash = NULL; static E_Border *focused = NULL; static E_Border *focusing = NULL; static Eina_List *focus_next = NULL; static Ecore_X_Time focus_time = 0; static E_Border *bdresize = NULL; static E_Border *bdmove = NULL; static E_Drag *drag_border = NULL; static int grabbed = 0; static Eina_List *focus_stack = NULL; static Eina_List *raise_stack = NULL; static E_Border *warp_timer_border = NULL; static Eina_Bool focus_locked = EINA_FALSE; static Ecore_X_Randr_Screen_Size screen_size = { -1, -1 }; static int screen_size_index = -1; static int focus_track_frozen = 0; static int warp_to = 0; static int warp_to_x = 0; static int warp_to_y = 0; static int warp_x[2] = {0}; //{cur,prev} static int warp_y[2] = {0}; //{cur,prev} static Ecore_X_Window warp_to_win; static Ecore_Timer *warp_timer = NULL; static Ecore_X_Window action_input_win = 0; static E_Border *action_border = NULL; static Ecore_Event_Handler *action_handler_key = NULL; static Ecore_Event_Handler *action_handler_mouse = NULL; static Ecore_Timer *action_timer = NULL; static Ecore_X_Rectangle action_orig; EAPI int E_EVENT_BORDER_ADD = 0; EAPI int E_EVENT_BORDER_REMOVE = 0; EAPI int E_EVENT_BORDER_ZONE_SET = 0; EAPI int E_EVENT_BORDER_DESK_SET = 0; EAPI int E_EVENT_BORDER_RESIZE = 0; EAPI int E_EVENT_BORDER_MOVE = 0; EAPI int E_EVENT_BORDER_SHOW = 0; EAPI int E_EVENT_BORDER_HIDE = 0; EAPI int E_EVENT_BORDER_ICONIFY = 0; EAPI int E_EVENT_BORDER_UNICONIFY = 0; EAPI int E_EVENT_BORDER_STICK = 0; EAPI int E_EVENT_BORDER_UNSTICK = 0; EAPI int E_EVENT_BORDER_STACK = 0; EAPI int E_EVENT_BORDER_ICON_CHANGE = 0; EAPI int E_EVENT_BORDER_TITLE_CHANGE = 0; EAPI int E_EVENT_BORDER_URGENT_CHANGE = 0; EAPI int E_EVENT_BORDER_FOCUS_IN = 0; EAPI int E_EVENT_BORDER_FOCUS_OUT = 0; EAPI int E_EVENT_BORDER_PROPERTY = 0; EAPI int E_EVENT_BORDER_FULLSCREEN = 0; EAPI int E_EVENT_BORDER_UNFULLSCREEN = 0; #define GRAV_SET(bd, grav) \ ecore_x_window_gravity_set(bd->win, grav); \ if (bd->client.lock_win) ecore_x_window_gravity_set(bd->client.lock_win, grav); \ ecore_x_window_gravity_set(bd->client.win, grav); static Eina_List * _e_border_sub_borders_new(E_Border *bd) { Eina_List *list = NULL, *l; E_Border *child; EINA_LIST_FOREACH(bd->transients, l, child) { if (!eina_list_data_find(list, child)) list = eina_list_append(list, child); } return list; } /* externally accessible functions */ EINTERN int e_border_init(void) { E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW_REQUEST, _e_border_cb_window_show_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DESTROY, _e_border_cb_window_destroy, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_HIDE, _e_border_cb_window_hide, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_REPARENT, _e_border_cb_window_reparent, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, _e_border_cb_window_configure_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, _e_border_cb_window_resize_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_GRAVITY, _e_border_cb_window_gravity, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK_REQUEST, _e_border_cb_window_stack_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY, _e_border_cb_window_property, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_COLORMAP, _e_border_cb_window_colormap, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHAPE, _e_border_cb_window_shape, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_IN, _e_border_cb_window_focus_in, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_OUT, _e_border_cb_window_focus_out, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_CLIENT_MESSAGE, _e_border_cb_client_message, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STATE_REQUEST, _e_border_cb_window_state_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST, _e_border_cb_window_move_resize_request, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DESKTOP_CHANGE, _e_border_cb_desktop_change, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SYNC_ALARM, _e_border_cb_sync_alarm, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_border_cb_mouse_x_down, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _e_border_cb_mouse_x_up, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_IN, _e_border_cb_mouse_x_in, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_OUT, _e_border_cb_mouse_x_out, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL, _e_border_cb_mouse_x_wheel, NULL); E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE, _e_border_cb_mouse_x_move, NULL); ecore_x_passive_grab_replay_func_set(_e_border_cb_grab_replay, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_POINTER_WARP, _e_border_cb_pointer_warp, NULL); E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_DESKTOP_CACHE_UPDATE, _e_border_cb_efreet_cache_update, NULL); E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE, _e_border_cb_efreet_cache_update, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME, _e_border_cb_config_icon_theme, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_MODE_CHANGED, _e_border_cb_config_mode, NULL); #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_WINDOW_PROFILE_CHANGE, _e_border_cb_desk_window_profile_change, NULL); #endif if (!borders_hash) borders_hash = eina_hash_string_superfast_new(NULL); E_EVENT_BORDER_ADD = ecore_event_type_new(); E_EVENT_BORDER_REMOVE = ecore_event_type_new(); E_EVENT_BORDER_DESK_SET = ecore_event_type_new(); E_EVENT_BORDER_ZONE_SET = ecore_event_type_new(); E_EVENT_BORDER_RESIZE = ecore_event_type_new(); E_EVENT_BORDER_MOVE = ecore_event_type_new(); E_EVENT_BORDER_SHOW = ecore_event_type_new(); E_EVENT_BORDER_HIDE = ecore_event_type_new(); E_EVENT_BORDER_ICONIFY = ecore_event_type_new(); E_EVENT_BORDER_UNICONIFY = ecore_event_type_new(); E_EVENT_BORDER_STICK = ecore_event_type_new(); E_EVENT_BORDER_UNSTICK = ecore_event_type_new(); E_EVENT_BORDER_STACK = ecore_event_type_new(); E_EVENT_BORDER_ICON_CHANGE = ecore_event_type_new(); E_EVENT_BORDER_TITLE_CHANGE = ecore_event_type_new(); E_EVENT_BORDER_URGENT_CHANGE = ecore_event_type_new(); E_EVENT_BORDER_FOCUS_IN = ecore_event_type_new(); E_EVENT_BORDER_FOCUS_OUT = ecore_event_type_new(); E_EVENT_BORDER_PROPERTY = ecore_event_type_new(); E_EVENT_BORDER_FULLSCREEN = ecore_event_type_new(); E_EVENT_BORDER_UNFULLSCREEN = ecore_event_type_new(); // e_init_undone(); return 1; } EINTERN int e_border_shutdown(void) { E_FREE_LIST(handlers, ecore_event_handler_del); if (borders_hash) eina_hash_free(borders_hash); borders_hash = NULL; e_int_border_menu_hooks_clear(); focus_locked = EINA_FALSE; if (warp_timer) ecore_timer_del(warp_timer); warp_timer = NULL; warp_timer_border = NULL; return 1; } EAPI void e_border_focus_lock_set(Eina_Bool lock) { focus_locked = !!lock; } EAPI Eina_Bool e_border_focus_lock_get(void) { return focus_locked; } EAPI E_Border * e_border_new(E_Container *con, Ecore_X_Window win, int first_map, int internal) { E_Border *bd; Ecore_X_Window_Attributes *att; unsigned int managed, desk[2]; int deskx, desky; if (eina_hash_find(borders_hash, e_util_winid_str_get(win))) return NULL; bd = E_OBJECT_ALLOC(E_Border, E_BORDER_TYPE, _e_border_free); if (!bd) return NULL; ecore_x_window_shadow_tree_flush(); e_object_del_func_set(E_OBJECT(bd), E_OBJECT_CLEANUP_FUNC(_e_border_del)); bd->w = 1; bd->h = 1; /* FIXME: ewww - round trip */ bd->client.argb = ecore_x_window_argb_get(win); /* match bd parent argbness */ if (bd->client.argb) bd->win = ecore_x_window_manager_argb_new(con->win, 0, 0, bd->w, bd->h); else { bd->win = ecore_x_window_override_new(con->win, 0, 0, bd->w, bd->h); ecore_x_window_shape_events_select(bd->win, 1); } e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, bd->win); e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, bd->win); e_focus_setup(bd); /* FIXME: Round trip. XCB */ /* fetch needed to avoid grabbing the server as window may vanish */ att = &bd->client.initial_attributes; if ((!ecore_x_window_attributes_get(win, att)) || (att->input_only)) { // printf("##- ATTR FETCH FAILED/INPUT ONLY FOR 0x%x - ABORT MANAGE\n", win); ecore_x_window_free(bd->win); e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); ecore_x_window_free(bd->win); free(bd); return NULL; } ecore_x_window_container_manage(bd->win); if (!internal) ecore_x_window_client_manage(win); ecore_x_window_configure(bd->win, ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, 0, 0, 0, 0, 0, win, ECORE_X_WINDOW_STACK_BELOW); ecore_x_event_mask_set(bd->win, ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT); /* printf("##- ON MAP CLIENT 0x%x SIZE %ix%i %i:%i\n", * bd->client.win, bd->client.w, bd->client.h, att->x, att->y); */ /* FIXME: if first_map is 1 then we should ignore the first hide event * or ensure the window is already hidden and events flushed before we * create a border for it */ if (first_map) { // printf("##- FIRST MAP\n"); bd->x = att->x; bd->y = att->y; bd->changes.pos = 1; bd->re_manage = 1; // needed to be 1 for internal windw and on restart. // bd->ignore_first_unmap = 2; } bd->client.win = win; bd->zone = e_zone_current_get(con); _e_border_hook_call(E_BORDER_HOOK_NEW_BORDER, bd); bd->client.icccm.title = NULL; bd->client.icccm.name = NULL; bd->client.icccm.class = NULL; bd->client.icccm.icon_name = NULL; bd->client.icccm.machine = NULL; bd->client.icccm.min_w = 1; bd->client.icccm.min_h = 1; bd->client.icccm.max_w = 32767; bd->client.icccm.max_h = 32767; bd->client.icccm.base_w = 0; bd->client.icccm.base_h = 0; bd->client.icccm.step_w = -1; bd->client.icccm.step_h = -1; bd->client.icccm.min_aspect = 0.0; bd->client.icccm.max_aspect = 0.0; bd->client.icccm.accepts_focus = 1; bd->client.netwm.pid = 0; bd->client.netwm.name = NULL; bd->client.netwm.icon_name = NULL; bd->client.netwm.desktop = 0; bd->client.netwm.state.modal = 0; bd->client.netwm.state.sticky = 0; bd->client.netwm.state.shaded = 0; bd->client.netwm.state.hidden = 0; bd->client.netwm.state.maximized_v = 0; bd->client.netwm.state.maximized_h = 0; bd->client.netwm.state.skip_taskbar = 0; bd->client.netwm.state.skip_pager = 0; bd->client.netwm.state.fullscreen = 0; bd->client.netwm.state.stacking = E_STACKING_NONE; bd->client.netwm.action.move = 0; bd->client.netwm.action.resize = 0; bd->client.netwm.action.minimize = 0; bd->client.netwm.action.shade = 0; bd->client.netwm.action.stick = 0; bd->client.netwm.action.maximized_h = 0; bd->client.netwm.action.maximized_v = 0; bd->client.netwm.action.fullscreen = 0; bd->client.netwm.action.change_desktop = 0; bd->client.netwm.action.close = 0; bd->client.netwm.opacity = 255; bd->client.netwm.type = ECORE_X_WINDOW_TYPE_UNKNOWN; { int at_num = 0, i; Ecore_X_Atom *atoms; atoms = ecore_x_window_prop_list(bd->client.win, &at_num); bd->client.icccm.fetch.command = 1; if (atoms) { Eina_Bool video_parent = EINA_FALSE; Eina_Bool video_position = EINA_FALSE; /* icccm */ for (i = 0; i < at_num; i++) { if (atoms[i] == ECORE_X_ATOM_WM_NAME) bd->client.icccm.fetch.title = 1; else if (atoms[i] == ECORE_X_ATOM_WM_CLASS) bd->client.icccm.fetch.name_class = 1; else if (atoms[i] == ECORE_X_ATOM_WM_ICON_NAME) bd->client.icccm.fetch.icon_name = 1; else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_MACHINE) bd->client.icccm.fetch.machine = 1; else if (atoms[i] == ECORE_X_ATOM_WM_HINTS) bd->client.icccm.fetch.hints = 1; else if (atoms[i] == ECORE_X_ATOM_WM_NORMAL_HINTS) bd->client.icccm.fetch.size_pos_hints = 1; else if (atoms[i] == ECORE_X_ATOM_WM_PROTOCOLS) bd->client.icccm.fetch.protocol = 1; else if (atoms[i] == ECORE_X_ATOM_MOTIF_WM_HINTS) bd->client.mwm.fetch.hints = 1; else if (atoms[i] == ECORE_X_ATOM_WM_TRANSIENT_FOR) { bd->client.icccm.fetch.transient_for = 1; bd->client.netwm.fetch.type = 1; } else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_LEADER) bd->client.icccm.fetch.client_leader = 1; else if (atoms[i] == ECORE_X_ATOM_WM_WINDOW_ROLE) bd->client.icccm.fetch.window_role = 1; else if (atoms[i] == ECORE_X_ATOM_WM_STATE) bd->client.icccm.fetch.state = 1; } /* netwm, loop again, netwm will ignore some icccm, so we * have to be sure that netwm is checked after */ for (i = 0; i < at_num; i++) { if (atoms[i] == ECORE_X_ATOM_NET_WM_NAME) { /* Ignore icccm */ bd->client.icccm.fetch.title = 0; bd->client.netwm.fetch.name = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON_NAME) { /* Ignore icccm */ bd->client.icccm.fetch.icon_name = 0; bd->client.netwm.fetch.icon_name = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON) { bd->client.netwm.fetch.icon = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_USER_TIME) { bd->client.netwm.fetch.user_time = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT) { DBG("ECORE_X_ATOM_NET_WM_STRUT"); bd->client.netwm.fetch.strut = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL) { DBG("ECORE_X_ATOM_NET_WM_STRUT_PARTIAL"); bd->client.netwm.fetch.strut = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_TYPE) { /* Ignore mwm bd->client.mwm.fetch.hints = 0; */ bd->client.netwm.fetch.type = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_STATE) { bd->client.netwm.fetch.state = 1; } else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY) bd->client.netwm.fetch.opacity = 1; } /* other misc atoms */ for (i = 0; i < at_num; i++) { /* loop to check for own atoms */ if (atoms[i] == E_ATOM_WINDOW_STATE) { bd->client.e.fetch.state = 1; } /* loop to check for qtopia atoms */ if (atoms[i] == ATM__QTOPIA_SOFT_MENU) bd->client.qtopia.fetch.soft_menu = 1; else if (atoms[i] == ATM__QTOPIA_SOFT_MENUS) bd->client.qtopia.fetch.soft_menus = 1; /* loop to check for vkbd atoms */ else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) bd->client.vkbd.fetch.state = 1; else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD) bd->client.vkbd.fetch.vkbd = 1; /* loop to check for illume atoms */ else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_CONFORMANT) bd->client.illume.conformant.fetch.conformant = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE) bd->client.illume.quickpanel.fetch.state = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL) bd->client.illume.quickpanel.fetch.quickpanel = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR) bd->client.illume.quickpanel.fetch.priority.major = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR) bd->client.illume.quickpanel.fetch.priority.minor = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE) bd->client.illume.quickpanel.fetch.zone = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED) bd->client.illume.drag.fetch.locked = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG) bd->client.illume.drag.fetch.drag = 1; else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE) bd->client.illume.win_state.fetch.state = 1; else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_PARENT) video_parent = EINA_TRUE; else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_POSITION) video_position = EINA_TRUE; #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) /* loop to check for window profile list atom */ else if (atoms[i] == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED) bd->client.e.fetch.profile = 1; #endif } if (video_position && video_parent) { bd->client.e.state.video = 1; bd->client.e.fetch.video_parent = 1; bd->client.e.fetch.video_position = 1; ecore_x_window_lower(bd->win); ecore_x_composite_window_events_disable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_TRUE); fprintf(stderr, "We found a video window \\o/ %x\n", win); } free(atoms); } } bd->client.border.changed = 1; bd->client.w = att->w; bd->client.h = att->h; bd->w = bd->client.w; bd->h = bd->client.h; bd->resize_mode = E_POINTER_RESIZE_NONE; bd->layer = 100; bd->saved.layer = bd->layer; bd->changes.icon = 1; bd->changes.size = 1; bd->changes.shape = 1; bd->changes.shape_input = 1; bd->offer_resistance = 1; /* just to friggin make java happy - we're DELAYING the reparent until * eval time... */ /* ecore_x_window_reparent(win, bd->win, 0, 0); */ bd->need_reparent = 1; ecore_x_window_border_width_set(win, 0); bd->shape = e_container_shape_add(con); bd->take_focus = 1; bd->new_client = 1; BD_CHANGED(bd); // bd->zone = e_zone_current_get(con); bd->desk = e_desk_current_get(bd->zone); e_container_border_add(bd); borders = eina_list_append(borders, bd); eina_hash_add(borders_hash, e_util_winid_str_get(bd->client.win), bd); eina_hash_add(borders_hash, e_util_winid_str_get(bd->win), bd); managed = 1; ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &managed, 1); ecore_x_window_prop_card32_set(win, E_ATOM_CONTAINER, &bd->zone->container->num, 1); ecore_x_window_prop_card32_set(win, E_ATOM_ZONE, &bd->zone->num, 1); { unsigned int zgeom[4]; zgeom[0] = bd->zone->x; zgeom[1] = bd->zone->y; zgeom[2] = bd->zone->w; zgeom[3] = bd->zone->h; ecore_x_window_prop_card32_set(win, E_ATOM_ZONE_GEOMETRY, zgeom, 4); } e_desk_xy_get(bd->desk, &deskx, &desky); desk[0] = deskx; desk[1] = desky; ecore_x_window_prop_card32_set(win, E_ATOM_DESK, desk, 2); focus_stack = eina_list_append(focus_stack, bd); return bd; } EAPI void e_border_res_change_geometry_save(E_Border *bd) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->pre_res_change.valid) return; bd->pre_res_change.valid = 1; bd->pre_res_change.x = bd->x; bd->pre_res_change.y = bd->y; bd->pre_res_change.w = bd->w; bd->pre_res_change.h = bd->h; bd->pre_res_change.saved.x = bd->saved.x; bd->pre_res_change.saved.y = bd->saved.y; bd->pre_res_change.saved.w = bd->saved.w; bd->pre_res_change.saved.h = bd->saved.h; } EAPI void e_border_res_change_geometry_restore(E_Border *bd) { struct { unsigned char valid : 1; int x, y, w, h; struct { int x, y, w, h; } saved; } pre_res_change; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!bd->pre_res_change.valid) return; if (bd->new_client) return; ecore_x_window_shadow_tree_flush(); memcpy(&pre_res_change, &bd->pre_res_change, sizeof(pre_res_change)); if (bd->fullscreen) { e_border_unfullscreen(bd); e_border_fullscreen(bd, e_config->fullscreen_policy); } else if (bd->maximized != E_MAXIMIZE_NONE) { E_Maximize max; max = bd->maximized; e_border_unmaximize(bd, E_MAXIMIZE_BOTH); e_border_maximize(bd, max); } else { int x, y, w, h, zx, zy, zw, zh; bd->saved.x = bd->pre_res_change.saved.x; bd->saved.y = bd->pre_res_change.saved.y; bd->saved.w = bd->pre_res_change.saved.w; bd->saved.h = bd->pre_res_change.saved.h; e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh); if (bd->saved.w > zw) bd->saved.w = zw; if ((bd->saved.x + bd->saved.w) > (zx + zw)) bd->saved.x = zx + zw - bd->saved.w; if (bd->saved.h > zh) bd->saved.h = zh; if ((bd->saved.y + bd->saved.h) > (zy + zh)) bd->saved.y = zy + zh - bd->saved.h; x = bd->pre_res_change.x; y = bd->pre_res_change.y; w = bd->pre_res_change.w; h = bd->pre_res_change.h; if (w > zw) w = zw; if (h > zh) h = zh; if ((x + w) > (zx + zw)) x = zx + zw - w; if ((y + h) > (zy + zh)) y = zy + zh - h; e_border_move_resize(bd, x, y, w, h); } memcpy(&bd->pre_res_change, &pre_res_change, sizeof(pre_res_change)); } EAPI void e_border_zone_set(E_Border *bd, E_Zone *zone) { E_Event_Border_Zone_Set *ev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); E_OBJECT_CHECK(zone); E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE); if (!zone) return; if (bd->zone == zone) return; /* if the window does not lie in the new zone, move it so that it does */ if (!E_INTERSECTS(bd->x, bd->y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h)) { int x, y; /* first guess -- get offset from old zone, and apply to new zone */ x = zone->x + (bd->x - bd->zone->x); y = zone->y + (bd->y - bd->zone->y); /* keep window from hanging off bottom and left */ if (x + bd->w > zone->x + zone->w) x += (zone->x + zone->w) - (x + bd->w); if (y + bd->h > zone->y + zone->h) y += (zone->y + zone->h) - (y + bd->h); /* make sure to and left are on screen (if the window is larger than the zone, it will hang off the bottom / right) */ if (x < zone->x) x = zone->x; if (y < zone->y) y = zone->y; if (!E_INTERSECTS(x, y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h)) { /* still not in zone at all, so just move it to closest edge */ if (x < zone->x) x = zone->x; if (x >= zone->x + zone->w) x = zone->x + zone->w - bd->w; if (y < zone->y) y = zone->y; if (y >= zone->y + zone->h) y = zone->y + zone->h - bd->h; } e_border_move(bd, x, y); } bd->zone = zone; if (bd->desk->zone != bd->zone) e_border_desk_set(bd, e_desk_current_get(bd->zone)); ev = E_NEW(E_Event_Border_Zone_Set, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_zone_set_event"); ev->zone = zone; e_object_ref(E_OBJECT(zone)); ecore_event_add(E_EVENT_BORDER_ZONE_SET, ev, _e_border_event_border_zone_set_free, NULL); ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_ZONE, &bd->zone->num, 1); // XXXXXXXXXXXXXXXXXXXXXXXXX // XXX ZZZZZZZZZZZZZZZZZZZzz // need to adjust this if zone pos/size changes { unsigned int zgeom[4]; zgeom[0] = bd->zone->x; zgeom[1] = bd->zone->y; zgeom[2] = bd->zone->w; zgeom[3] = bd->zone->h; ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_ZONE_GEOMETRY, zgeom, 4); } e_remember_update(bd); e_border_res_change_geometry_save(bd); e_border_res_change_geometry_restore(bd); bd->pre_res_change.valid = 0; } EAPI void e_border_desk_set(E_Border *bd, E_Desk *desk) { E_Event_Border_Desk_Set *ev; E_Desk *old_desk; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); E_OBJECT_CHECK(desk); E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE); if (bd->desk == desk) return; #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) if ((e_config->use_desktop_window_profile) && (bd->client.e.state.profile.use)) { if (bd->client.e.state.profile.wait_for_done) return; if (e_util_strcmp(bd->client.e.state.profile.name, desk->window_profile)) { ecore_x_e_window_profile_change_request_send(bd->client.win, desk->window_profile); bd->client.e.state.profile.wait_for_done = 1; return; } } #endif ecore_x_window_shadow_tree_flush(); if (bd->fullscreen) { bd->desk->fullscreen_borders--; desk->fullscreen_borders++; } old_desk = bd->desk; bd->desk = desk; e_border_zone_set(bd, desk->zone); _e_border_hook_call(E_BORDER_HOOK_SET_DESK, bd); e_hints_window_desktop_set(bd); ev = E_NEW(E_Event_Border_Desk_Set, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_desk_set_event"); ev->desk = old_desk; e_object_ref(E_OBJECT(old_desk)); ecore_event_add(E_EVENT_BORDER_DESK_SET, ev, _e_border_event_border_desk_set_free, NULL); if (bd->ignore_first_unmap != 1) { if ((bd->desk->visible) || (bd->sticky)) e_border_show(bd); else e_border_hide(bd, 1); } if (e_config->transient.desktop) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_FREE(list, child) e_border_desk_set(child, bd->desk); } e_remember_update(bd); } EAPI void e_border_show(E_Border *bd) { E_Event_Border_Show *ev; unsigned int visible; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->visible) return; ecore_x_window_shadow_tree_flush(); e_container_shape_show(bd->shape); if (!bd->need_reparent) ecore_x_window_show(bd->client.win); e_hints_window_visible_set(bd); bd->hidden = 0; bd->visible = 1; bd->changes.visible = 1; visible = 1; ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &visible, 1); ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MANAGED, &visible, 1); if (bd->new_client) return; ev = E_NEW(E_Event_Border_Show, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_show_event"); ecore_event_add(E_EVENT_BORDER_SHOW, ev, _e_border_event_border_show_free, NULL); } EAPI void e_border_hide(E_Border *bd, int manage) { unsigned int visible; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!bd->visible) goto send_event; ecore_x_window_shadow_tree_flush(); if (bd->moving) _e_border_move_end(bd); if (bd->resize_mode != E_POINTER_RESIZE_NONE) _e_border_resize_end(bd); if (action_border == bd) _e_border_action_finish(); e_container_shape_hide(bd->shape); if (!bd->iconic) e_hints_window_hidden_set(bd); bd->visible = 0; bd->changes.visible = 1; if (!bd->need_reparent) { if (bd->focused) { e_border_focus_set(bd, 0, 1); if (manage != 2) { E_Border *pbd; E_Zone *zone; E_Desk *desk; zone = e_util_zone_current_get(e_manager_current_get()); desk = e_desk_current_get(zone); if ((bd->parent) && (bd->parent->desk == desk) && (bd->parent->modal == bd)) e_border_focus_set(bd->parent, 1, 1); else if (e_config->focus_revert_on_hide_or_close) { Eina_Bool unlock = bd->lock_focus_out; bd->lock_focus_out = 1; e_desk_last_focused_focus(desk); bd->lock_focus_out = unlock; } else if (e_config->focus_policy == E_FOCUS_MOUSE) { pbd = e_border_under_pointer_get(desk, bd); if (pbd) e_border_focus_set(pbd, 1, 1); } } } switch (manage) { case 2: break; case 3: bd->hidden = 1; case 1: default: if (!e_comp_evas_exists(bd)) { /* Make sure that this border isn't deleted */ bd->await_hide_event++; ecore_x_window_hide(bd->client.win); } } } visible = 0; ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &visible, 1); if (!manage) ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MANAGED, &visible, 1); bd->post_show = 0; send_event: if (bd->new_client) return; if (!stopping) { E_Event_Border_Hide *ev; ev = E_NEW(E_Event_Border_Hide, 1); ev->border = bd; ev->manage = manage; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_hide_event"); ecore_event_add(E_EVENT_BORDER_HIDE, ev, _e_border_event_border_hide_free, NULL); } } static void _pri_adj(int pid, int set, int adj, Eina_Bool use_adj, Eina_Bool adj_children, Eina_Bool do_children) { int newpri = set; if (use_adj) newpri = getpriority(PRIO_PROCESS, pid) + adj; setpriority(PRIO_PROCESS, pid, newpri); // shouldnt need to do this as default ionice class is "none" (0), and // this inherits io priority FROM nice level // ioprio_set(IOPRIO_WHO_PROCESS, pid, // IOPRIO_PRIO_VALUE(2, 5)); if (do_children) { Eina_List *files; char *file, buf[PATH_MAX]; FILE *f; int pid2, ppid; // yes - this is /proc specific... so this may not work on some // os's - works on linux. too bad for others. files = ecore_file_ls("/proc"); EINA_LIST_FREE(files, file) { if (isdigit(file[0])) { snprintf(buf, sizeof(buf), "/proc/%s/stat", file); f = fopen(buf, "r"); if (f) { pid2 = -1; ppid = -1; if (fscanf(f, "%i %*s %*s %i %*s", &pid2, &ppid) == 2) { fclose(f); if (ppid == pid) { if (adj_children) _pri_adj(pid2, set, adj, EINA_TRUE, adj_children, do_children); else _pri_adj(pid2, set, adj, use_adj, adj_children, do_children); } } else fclose(f); } } free(file); } } } static void _e_border_pri_raise(E_Border *bd) { if (bd->client.netwm.pid <= 0) return; if (bd->client.netwm.pid == getpid()) return; _pri_adj(bd->client.netwm.pid, e_config->priority - 1, -1, EINA_FALSE, // EINA_TRUE, EINA_TRUE); EINA_TRUE, EINA_FALSE); // printf("WIN: pid %i, title %s (HI!!!!!!!!!!!!!!!!!!)\n", // bd->client.netwm.pid, e_border_name_get(bd)); } static void _e_border_pri_norm(E_Border *bd) { if (bd->client.netwm.pid <= 0) return; if (bd->client.netwm.pid == getpid()) return; _pri_adj(bd->client.netwm.pid, e_config->priority, 1, EINA_FALSE, // EINA_TRUE, EINA_TRUE); EINA_TRUE, EINA_FALSE); // printf("WIN: pid %i, title %s (NORMAL)\n", // bd->client.netwm.pid, e_border_name_get(bd)); } static void _e_border_client_move_resize_send(E_Border *bd) { if (bd->internal_ecore_evas) ecore_evas_managed_move(bd->internal_ecore_evas, bd->client_inset.l, bd->client_inset.t); ecore_x_icccm_move_resize_send(bd->client.win, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t, bd->client.w, bd->client.h); } static void _e_border_pending_move_resize_add(E_Border *bd, int move, int resize, int x, int y, int w, int h, Eina_Bool without_border, unsigned int serial) { E_Border_Pending_Move_Resize *pnd; pnd = E_NEW(E_Border_Pending_Move_Resize, 1); if (!pnd) return; pnd->resize = resize; pnd->move = move; pnd->without_border = without_border; pnd->x = x; pnd->y = y; pnd->w = w; pnd->h = h; pnd->serial = serial; bd->pending_move_resize = eina_list_append(bd->pending_move_resize, pnd); } static void _e_border_move_internal(E_Border *bd, int x, int y, Eina_Bool without_border) { E_Event_Border_Move *ev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (bd->new_client) { _e_border_pending_move_resize_add(bd, 1, 0, x, y, 0, 0, without_border, 0); return; } if (bd->maximized) { if ((bd->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_BOTH) { if (e_config->allow_manip) bd->maximized = 0; if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL) { x = bd->x; } else if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL) { y = bd->y; } } else if (e_config->allow_manip) bd->maximized = 0; else return; } if (without_border) { x -= bd->client_inset.l; y -= bd->client_inset.t; } if (bd->move_intercept_cb) { int px, py; px = bd->x, py = bd->y; bd->move_intercept_cb(bd, x, y); if ((bd->x == px) && (bd->y == py)) return; } else if ((x == bd->x) && (y == bd->y)) return; bd->pre_res_change.valid = 0; bd->x = x; bd->y = y; BD_CHANGED(bd); bd->changes.pos = 1; #if 0 if (bd->client.netwm.sync.request) { bd->client.netwm.sync.wait++; ecore_x_netwm_sync_request_send(bd->client.win, bd->client.netwm.sync.serial++); } #endif _e_border_client_move_resize_send(bd); _e_border_move_update(bd); ev = E_NEW(E_Event_Border_Move, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_move_event"); ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL); _e_border_zone_update(bd); } /** * Move window to coordinates that already account border decorations. * * This call will consider given position already accounts border * decorations, so it will not be considered later. This will just * work properly with borders that have being evaluated and border * decorations are known (border->client_inset). * * @parm x horizontal position to place window. * @parm y vertical position to place window. * * @see e_border_move_without_border() */ EAPI void e_border_move(E_Border *bd, int x, int y) { if (bd->fullscreen) return; _e_border_move_internal(bd, x, y, 0); } /** * Set a callback which will be called just prior to updating the * move coordinates for a border */ EAPI void e_border_move_intercept_cb_set(E_Border *bd, E_Border_Move_Intercept_Cb cb) { bd->move_intercept_cb = cb; } /** * Move window to coordinates that do not account border decorations yet. * * This call will consider given position does not account border * decoration, so these values (border->client_inset) will be * accounted automatically. This is specially useful when it is a new * client and has not be evaluated yet, in this case * border->client_inset will be zeroed and no information is known. It * will mark pending requests so border will be accounted on * evalutation phase. * * @parm x horizontal position to place window. * @parm y vertical position to place window. * * @see e_border_move() */ EAPI void e_border_move_without_border(E_Border *bd, int x, int y) { if (bd->fullscreen) return; _e_border_move_internal(bd, x, y, 1); } EAPI void e_border_center(E_Border *bd) { int x, y, w, h; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h); e_border_move(bd, x + (w - bd->w) / 2, y + (h - bd->h) / 2); } EAPI void e_border_center_pos_get(E_Border *bd, int *x, int *y) { int zx, zy, zw, zh; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh); if (x) *x = zx + (zw - bd->w) / 2; if (y) *y = zy + (zh - bd->h) / 2; } static void _e_border_move_resize_internal(E_Border *bd, int x, int y, int w, int h, Eina_Bool without_border, Eina_Bool move) { E_Event_Border_Move *mev; E_Event_Border_Resize *rev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (bd->new_client) { _e_border_pending_move_resize_add(bd, move, 1, x, y, w, h, without_border, 0); return; } if (bd->maximized) { if ((bd->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_BOTH) { if (e_config->allow_manip) bd->maximized = 0; if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL) { x = bd->x; w = bd->w; } else if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL) { y = bd->y; h = bd->h; } } else if (e_config->allow_manip) bd->maximized = 0; else return; } if (without_border) { x -= bd->client_inset.l; y -= bd->client_inset.t; w += e_border_inset_width_get(bd); h += e_border_inset_height_get(bd); } if ((!move || ((x == bd->x) && (y == bd->y))) && (w == bd->w) && (h == bd->h)) return; bd->pre_res_change.valid = 0; if (move) { bd->changes.pos = 1; bd->x = x; bd->y = y; } bd->w = w; bd->h = h; bd->client.w = bd->w - e_border_inset_width_get(bd); bd->client.h = bd->h - e_border_inset_height_get(bd); if (bd->client.shaped) { bd->need_shape_merge = 1; bd->need_shape_export = 1; } if (bd->shaped_input) { bd->need_shape_merge = 1; } if (bd->internal_ecore_evas) { BD_CHANGED(bd); bd->changes.size = 1; } else { if (bdresize && bd->client.netwm.sync.request) { bd->client.netwm.sync.wait++; /* Don't use x and y as supplied to this function, as it is called with 0, 0 * when no move is intended. The border geometry is set above anyways. */ _e_border_pending_move_resize_add(bd, move, 1, bd->x, bd->y, bd->w, bd->h, without_border, bd->client.netwm.sync.serial); ecore_x_netwm_sync_request_send(bd->client.win, bd->client.netwm.sync.serial++); } else { BD_CHANGED(bd); bd->changes.size = 1; } } _e_border_client_move_resize_send(bd); _e_border_resize_update(bd); if (move) { mev = E_NEW(E_Event_Border_Move, 1); mev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_move_event"); ecore_event_add(E_EVENT_BORDER_MOVE, mev, _e_border_event_border_move_free, NULL); } rev = E_NEW(E_Event_Border_Resize, 1); rev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event"); ecore_event_add(E_EVENT_BORDER_RESIZE, rev, _e_border_event_border_resize_free, NULL); _e_border_zone_update(bd); } /** * Move and resize window to values that already account border decorations. * * This call will consider given values already accounts border * decorations, so it will not be considered later. This will just * work properly with borders that have being evaluated and border * decorations are known (border->client_inset). * * @parm x horizontal position to place window. * @parm y vertical position to place window. * @parm w horizontal window size. * @parm h vertical window size. * * @see e_border_move_resize_without_border() */ EAPI void e_border_move_resize(E_Border *bd, int x, int y, int w, int h) { if (bd->fullscreen) return; _e_border_move_resize_internal(bd, x, y, w, h, 0, 1); } /** * Move and resize window to values that do not account border decorations yet. * * This call will consider given values already accounts border * decorations, so it will not be considered later. This will just * work properly with borders that have being evaluated and border * decorations are known (border->client_inset). * * @parm x horizontal position to place window. * @parm y vertical position to place window. * @parm w horizontal window size. * @parm h vertical window size. * * @see e_border_move_resize() */ EAPI void e_border_move_resize_without_border(E_Border *bd, int x, int y, int w, int h) { if (bd->fullscreen) return; _e_border_move_resize_internal(bd, x, y, w, h, 1, 1); } /** * Resize window to values that already account border decorations. * * This call will consider given size already accounts border * decorations, so it will not be considered later. This will just * work properly with borders that have being evaluated and border * decorations are known (border->client_inset). * * @parm w horizontal window size. * @parm h vertical window size. * * @see e_border_resize_without_border() */ EAPI void e_border_resize(E_Border *bd, int w, int h) { if (bd->fullscreen) return; _e_border_move_resize_internal(bd, 0, 0, w, h, 0, 0); } /** * Resize window to values that do not account border decorations yet. * * This call will consider given size does not account border * decoration, so these values (border->client_inset) will be * accounted automatically. This is specially useful when it is a new * client and has not be evaluated yet, in this case * border->client_inset will be zeroed and no information is known. It * will mark pending requests so border will be accounted on * evalutation phase. * * @parm w horizontal window size. * @parm h vertical window size. * * @see e_border_resize() */ EAPI void e_border_resize_without_border(E_Border *bd, int w, int h) { if (bd->fullscreen) return; _e_border_move_resize_internal(bd, 0, 0, w, h, 1, 0); } EAPI void e_border_layer_set(E_Border *bd, E_Layer layer) { int oldraise; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); oldraise = e_config->transient.raise; if (bd->fullscreen) { bd->saved.layer = layer; return; } bd->layer = layer; if (e_config->transient.layer) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); /* We need to set raise to one, else the child wont * follow to the new layer. It should be like this, * even if the user usually doesn't want to raise * the transients. */ e_config->transient.raise = 1; EINA_LIST_FREE(list, child) e_border_layer_set(child, layer); } if ((!bd->modal) || (bd->modal->layer > bd->layer)) e_border_raise(bd); else e_border_stack_below(bd, bd->modal); if (layer == E_LAYER_BELOW) e_hints_window_stacking_set(bd, E_STACKING_BELOW); else if (layer == E_LAYER_ABOVE) e_hints_window_stacking_set(bd, E_STACKING_ABOVE); else e_hints_window_stacking_set(bd, E_STACKING_NONE); e_config->transient.raise = oldraise; } EAPI void e_border_raise(E_Border *bd) { E_Event_Border_Stack *ev; E_Border *last = NULL, *child; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (e_config->transient.raise) { Eina_List *l, *l_prev; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child) { /* Don't stack iconic transients. If the user wants these shown, * thats another option. */ if (!child->iconic) { if (last) e_border_stack_below(child, last); else { E_Border *above; /* First raise the border to find out which border we will end up above */ above = e_container_border_raise(child); if (above) { /* We ended up above a border, now we must stack this border to * generate the stacking event, and to check if this transient * has other transients etc. */ e_border_stack_above(child, above); } else { /* If we didn't end up above any border, we are on the bottom! */ e_border_lower(child); } } last = child; } list = eina_list_remove_list(list, l); } } ev = E_NEW(E_Event_Border_Stack, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); if (last) { e_container_border_stack_below(bd, last); ev->stack = last; e_object_ref(E_OBJECT(last)); ev->type = E_STACKING_BELOW; } else { E_Border *above; /* If we don't have any children, raise this border */ above = e_container_border_raise(bd); e_border_raise_latest_set(bd); if (above) { /* We ended up above a border */ ev->stack = above; e_object_ref(E_OBJECT(above)); ev->type = E_STACKING_ABOVE; } else { /* No border to raise above, same as a lower! */ ev->stack = NULL; ev->type = E_STACKING_ABOVE; } } ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL); e_remember_update(bd); } EAPI void e_border_lower(E_Border *bd) { E_Event_Border_Stack *ev; E_Border *last = NULL, *child; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (e_config->transient.lower) { Eina_List *l, *l_prev; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child) { /* Don't stack iconic transients. If the user wants these shown, * thats another option. */ if (!child->iconic) { if (last) e_border_stack_below(child, last); else { E_Border *below; /* First lower the border to find out which border we will end up below */ below = e_container_border_lower(child); if (below) { /* We ended up below a border, now we must stack this border to * generate the stacking event, and to check if this transient * has other transients etc. */ e_border_stack_below(child, below); } else { /* If we didn't end up below any border, we are on top! */ e_border_raise(child); } } last = child; } list = eina_list_remove_list(list, l); } } ev = E_NEW(E_Event_Border_Stack, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); if (last) { e_container_border_stack_below(bd, last); ev->stack = last; e_object_ref(E_OBJECT(last)); ev->type = E_STACKING_BELOW; } else { E_Border *below; /* If we don't have any children, lower this border */ below = e_container_border_lower(bd); if (below) { /* We ended up below a border */ ev->stack = below; e_object_ref(E_OBJECT(below)); ev->type = E_STACKING_BELOW; } else { /* No border to hide under, same as a raise! */ ev->stack = NULL; ev->type = E_STACKING_BELOW; } } ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL); e_remember_update(bd); } EAPI void e_border_stack_above(E_Border *bd, E_Border *above) { /* TODO: Should stack above allow the border to change level */ E_Event_Border_Stack *ev; E_Border *last = NULL, *child; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (e_config->transient.raise) { Eina_List *l, *l_prev; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child) { /* Don't stack iconic transients. If the user wants these shown, * thats another option. */ if (!child->iconic) { if (last) e_border_stack_below(child, last); else e_border_stack_above(child, above); last = child; } list = eina_list_remove_list(list, l); } } ev = E_NEW(E_Event_Border_Stack, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); if (last) { e_container_border_stack_below(bd, last); ev->stack = last; e_object_ref(E_OBJECT(last)); ev->type = E_STACKING_BELOW; } else { e_container_border_stack_above(bd, above); ev->stack = above; e_object_ref(E_OBJECT(above)); ev->type = E_STACKING_ABOVE; } ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL); e_remember_update(bd); } EAPI void e_border_stack_below(E_Border *bd, E_Border *below) { /* TODO: Should stack below allow the border to change level */ E_Event_Border_Stack *ev; E_Border *last = NULL, *child; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); ecore_x_window_shadow_tree_flush(); if (e_config->transient.lower) { Eina_List *l, *l_prev; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child) { /* Don't stack iconic transients. If the user wants these shown, * thats another option. */ if (!child->iconic) { if (last) e_border_stack_below(child, last); else e_border_stack_below(child, below); last = child; } list = eina_list_remove_list(list, l); } } ev = E_NEW(E_Event_Border_Stack, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); if (last) { e_container_border_stack_below(bd, last); ev->stack = last; e_object_ref(E_OBJECT(last)); ev->type = E_STACKING_BELOW; } else { e_container_border_stack_below(bd, below); ev->stack = below; e_object_ref(E_OBJECT(below)); ev->type = E_STACKING_BELOW; } ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL); e_remember_update(bd); } EAPI void e_border_focus_latest_set(E_Border *bd) { focus_stack = eina_list_remove(focus_stack, bd); focus_stack = eina_list_prepend(focus_stack, bd); } EAPI void e_border_raise_latest_set(E_Border *bd) { raise_stack = eina_list_remove(raise_stack, bd); raise_stack = eina_list_prepend(raise_stack, bd); } /* * Sets the focus to the given border if necessary * There are 3 cases of different focus_policy-configurations: * * - E_FOCUS_CLICK: just set the focus, the most simple one * * - E_FOCUS_MOUSE: focus is where the mouse is, so try to * warp the pointer to the window. If this fails (because * the pointer is already in the window), just set the focus. * * - E_FOCUS_SLOPPY: focus is where the mouse is or on the * last window which was focused, if the mouse is on the * desktop. So, we need to look if there is another window * under the pointer and warp to pointer to the right * one if so (also, we set the focus afterwards). In case * there is no window under pointer, the pointer is on the * desktop and so we just set the focus. * * * This function is to be called when setting the focus was not * explicitly triggered by the user (by moving the mouse or * clicking for example), but implicitly (by closing a window, * the last focused window should get focus). * */ EAPI void e_border_focus_set_with_pointer(E_Border *bd) { #ifdef PRINT_LOTS_OF_DEBUG E_PRINT_BORDER_INFO(bd); #endif /* note: this is here as it seems there are enough apps that do not even * expect us to emulate a look of focus but not actually set x input * focus as we do - so simply abort any focuse set on such windows */ /* be strict about accepting focus hint */ if ((!bd->client.icccm.accepts_focus) && (!bd->client.icccm.take_focus)) return; if (bd->lock_focus_out) return; if (bd == focused) return; e_border_focus_set(bd, 1, 1); if (e_config->focus_policy == E_FOCUS_CLICK) return; if (!bd->visible) return; if (e_config->focus_policy == E_FOCUS_SLOPPY) { E_Border *pbd; int ret = 0; pbd = e_border_under_pointer_get(bd->desk, bd); /* Do not slide pointer when disabled (probably breaks focus * on sloppy/mouse focus but requested by users). */ if (e_config->pointer_slide && pbd && (pbd != bd)) ret = e_border_pointer_warp_to_center(bd); if (!ret) e_border_focus_set(bd, 1, 0); } else { if (e_config->pointer_slide && (!e_border_pointer_warp_to_center(bd))) e_border_focus_set(bd, 1, 0); } } EAPI void e_border_focus_set(E_Border *bd, int focus, int set) { E_Border *bd_unfocus = NULL; Eina_Bool focus_changed = EINA_FALSE; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); /* note: this is here as it seems there are enough apps that do not even * expect us to emulate a look of focus but not actually set x input * focus as we do - so simply abort any focuse set on such windows */ /* be strict about accepting focus hint */ if ((!bd->client.icccm.accepts_focus) && (!bd->client.icccm.take_focus)) return; if ((set) && (focus) && (bd->lock_focus_out)) return; /* dont focus an iconified window. that's silly! */ if (focus) { if ((bd->iconic) && (!bd->deskshow)) { e_border_uniconify(bd); if (!focus_track_frozen) e_border_focus_latest_set(bd); return; } else if (!bd->visible) { return; } /* FIXME: hack for deskflip animation: * dont update focus when sliding previous desk */ else if ((!bd->sticky) && (bd->desk != e_desk_current_get(bd->desk->zone))) { return; } } if ((bd->modal) && (bd->modal != bd) && (bd->modal->visible)) { e_border_focus_set(bd->modal, focus, set); return; } else if ((bd->leader) && (bd->leader->modal) && (bd->leader->modal != bd)) { e_border_focus_set(bd->leader->modal, focus, set); return; } if (focus) { if (set) { if (bd->visible && bd->changes.visible) { bd->want_focus = 1; BD_CHANGED(bd); } else if ((!bd->focused) || (focus_next && (bd != eina_list_data_get(focus_next)))) { Eina_List *l; if ((l = eina_list_data_find_list(focus_next, bd))) focus_next = eina_list_promote_list(focus_next, l); else focus_next = eina_list_prepend(focus_next, bd); } if ((bd->client.icccm.take_focus) && (bd->client.icccm.accepts_focus)) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_LOCALLY_ACTIVE); /* TODO what if the client didn't take focus ? */ } else if (!bd->client.icccm.accepts_focus) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_GLOBALLY_ACTIVE); } else if (!bd->client.icccm.take_focus) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_PASSIVE); /* e_border_focus_set(bd, 1, 0); */ } return; } if (!bd->focused) { if (focused) bd_unfocus = focused; if (focusing == bd) focusing = NULL; bd->focused = 1; focused = bd; if ((!e_config->allow_above_fullscreen) && (!bd_unfocus)) { Eina_List *l; E_Border *bd2; EINA_LIST_FOREACH(e_border_client_list(), l, bd2) { if ((bd2->fullscreen) && (bd2 != bd) && (bd2->zone == bd->zone) && ((bd2->desk == bd->desk) || (bd2->sticky) || (bd->sticky))) { Eina_Bool unfocus_is_parent = EINA_FALSE; E_Border *bd_parent; bd_parent = bd->parent; while (bd_parent) { if (bd_parent == bd2) { unfocus_is_parent = EINA_TRUE; break; } bd_parent = bd->parent; } if (!unfocus_is_parent) e_border_unfullscreen(bd2); } } } focus_changed = EINA_TRUE; } } else { bd->want_focus = 0; focus_next = eina_list_remove(focus_next, bd); if (bd == focusing) focusing = NULL; if (bd->focused) { Eina_Bool wasfocused = EINA_FALSE; bd_unfocus = bd; /* should always be the case. anyway */ if (bd == focused) { focused = NULL; wasfocused = EINA_TRUE; } if ((set) && (!focus_next) && (!focusing)) { e_grabinput_focus(bd->zone->container->bg_win, E_FOCUS_METHOD_PASSIVE); } if ((!e_config->allow_above_fullscreen) && (bd->fullscreen) && (wasfocused) && ((bd->desk == e_desk_current_get(bd->zone)) || (bd->sticky))) { Eina_Bool have_vis_child = EINA_FALSE; Eina_List *l; E_Border *bd2; EINA_LIST_FOREACH(e_border_client_list(), l, bd2) { if ((bd2 != bd) && (bd2->zone == bd->zone) && ((bd2->desk == bd->desk) || (bd2->sticky) || (bd->sticky))) { if (bd2->parent == bd) { have_vis_child = EINA_TRUE; break; } } } if (!have_vis_child) e_border_unfullscreen(bd); } } } if ((bd_unfocus) && (!e_object_is_del(E_OBJECT(bd_unfocus)) && (e_object_ref_get(E_OBJECT(bd_unfocus)) > 0))) { E_Event_Border_Focus_Out *ev; bd_unfocus->focused = 0; e_focus_event_focus_out(bd_unfocus); if (bd_unfocus->raise_timer) ecore_timer_del(bd_unfocus->raise_timer); bd_unfocus->raise_timer = NULL; edje_object_signal_emit(bd_unfocus->bg_object, "e,state,unfocused", "e"); if (bd_unfocus->icon_object) edje_object_signal_emit(bd_unfocus->icon_object, "e,state,unfocused", "e"); ev = E_NEW(E_Event_Border_Focus_Out, 1); ev->border = bd_unfocus; e_object_ref(E_OBJECT(bd_unfocus)); ecore_event_add(E_EVENT_BORDER_FOCUS_OUT, ev, _e_border_event_border_focus_out_free, NULL); if ((!e_config->allow_above_fullscreen) && (bd_unfocus->fullscreen) && (bd != bd_unfocus) && (bd->zone == bd_unfocus->zone) && ((bd->desk == bd_unfocus->desk) || (bd->sticky) || (bd_unfocus->sticky))) { Eina_Bool unfocus_is_parent = EINA_FALSE; E_Border *bd_parent; bd_parent = bd->parent; while (bd_parent) { if (bd_parent == bd_unfocus) { unfocus_is_parent = EINA_TRUE; break; } bd_parent = bd->parent; } if (!unfocus_is_parent) e_border_unfullscreen(bd_unfocus); } } if (focus_changed) { E_Event_Border_Focus_In *ev; e_focus_event_focus_in(bd); if (!focus_track_frozen) e_border_focus_latest_set(bd); e_hints_active_window_set(bd->zone->container->manager, bd); edje_object_signal_emit(bd->bg_object, "e,state,focused", "e"); if (bd->icon_object) edje_object_signal_emit(bd->icon_object, "e,state,focused", "e"); ev = E_NEW(E_Event_Border_Focus_In, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_FOCUS_IN, ev, _e_border_event_border_focus_in_free, NULL); } } EAPI void e_border_shade(E_Border *bd, E_Direction dir) { E_Event_Border_Simple *ev; Eina_List *l; E_Border *tmp; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->shaded) || (bd->shading) || (bd->fullscreen) || ((bd->maximized) && (!e_config->allow_manip))) return; if ((bd->client.border.name) && (!strcmp("borderless", bd->client.border.name))) return; EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_hide(tmp->win); ecore_x_window_shadow_tree_flush(); bd->shade.x = bd->x; bd->shade.y = bd->y; bd->shade.dir = dir; e_hints_window_shaded_set(bd, 1); e_hints_window_shade_direction_set(bd, dir); if (e_config->border_shade_animate && (!bd->new_client)) { bd->shade.start = ecore_loop_time_get(); bd->shading = 1; bd->changes.shading = 1; BD_CHANGED(bd); bd->shade.anim = ecore_animator_add(_e_border_shade_animator, bd); edje_object_signal_emit(bd->bg_object, "e,state,shading", "e"); } else { Eina_Bool move = EINA_FALSE; if (bd->shade.dir == E_DIRECTION_UP) { bd->h = bd->client_inset.t; } else if (bd->shade.dir == E_DIRECTION_DOWN) { bd->h = bd->client_inset.t; bd->y = bd->y + bd->client.h; move = EINA_TRUE; } else if (bd->shade.dir == E_DIRECTION_LEFT) { bd->w = bd->client_inset.t; } else if (bd->shade.dir == E_DIRECTION_RIGHT) { bd->w = bd->client_inset.t; bd->x = bd->x + bd->client.w; move = EINA_TRUE; } if (bd->client.shaped) { bd->need_shape_merge = 1; bd->need_shape_export = 1; } if (bd->shaped_input) { bd->need_shape_merge = 1; } bd->shaded = 1; bd->changes.shaded = 1; BD_CHANGED(bd); edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e"); e_border_frame_recalc(bd); if (move) { ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL); e_container_shape_move(bd->shape, bd->x, bd->y); } e_container_shape_resize(bd->shape, bd->w, bd->h); e_border_comp_hidden_set(bd, EINA_TRUE); ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; /* The resize is added in the animator when animation complete */ /* For non-animated, we add it immediately with the new size */ e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event"); ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL); } e_remember_update(bd); } EAPI void e_border_unshade(E_Border *bd, E_Direction dir) { E_Event_Border_Simple *ev; Eina_List *l; E_Border *tmp; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((!bd->shaded) || (bd->shading)) return; EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_show(tmp->win); ecore_x_window_shadow_tree_flush(); bd->shade.dir = dir; e_hints_window_shaded_set(bd, 0); e_hints_window_shade_direction_set(bd, dir); if (bd->shade.dir == E_DIRECTION_UP || bd->shade.dir == E_DIRECTION_LEFT) { bd->shade.x = bd->x; bd->shade.y = bd->y; } else { bd->shade.x = bd->x - bd->client.w; bd->shade.y = bd->y - bd->client.h; } if (e_config->border_shade_animate) { bd->shade.start = ecore_loop_time_get(); bd->shading = 1; bd->changes.shading = 1; BD_CHANGED(bd); bd->shade.anim = ecore_animator_add(_e_border_shade_animator, bd); edje_object_signal_emit(bd->bg_object, "e,state,unshading", "e"); } else { Eina_Bool move = EINA_FALSE; if (bd->shade.dir == E_DIRECTION_UP) { bd->h = bd->client_inset.t + bd->client.h + bd->client_inset.b; } else if (bd->shade.dir == E_DIRECTION_DOWN) { bd->h = bd->client_inset.t + bd->client.h + bd->client_inset.b; bd->y = bd->y - bd->client.h; move = EINA_TRUE; } else if (bd->shade.dir == E_DIRECTION_LEFT) { bd->w = bd->client_inset.l + bd->client.w + bd->client_inset.r; } else if (bd->shade.dir == E_DIRECTION_RIGHT) { bd->w = bd->client_inset.l + bd->client.w + bd->client_inset.r; bd->x = bd->x - bd->client.w; move = EINA_TRUE; } if (bd->client.shaped) { bd->need_shape_merge = 1; bd->need_shape_export = 1; } if (bd->shaped_input) { bd->need_shape_merge = 1; } bd->shaded = 0; bd->changes.shaded = 1; BD_CHANGED(bd); edje_object_signal_emit(bd->bg_object, "e,state,unshaded", "e"); e_border_frame_recalc(bd); if (move) { ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL); e_container_shape_move(bd->shape, bd->x, bd->y); } e_container_shape_resize(bd->shape, bd->w, bd->h); e_border_comp_hidden_set(bd, EINA_FALSE); ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; /* The resize is added in the animator when animation complete */ /* For non-animated, we add it immediately with the new size */ e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event"); ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL); } e_remember_update(bd); } static void _e_border_client_inset_calc(E_Border *bd) { int w, h, cx, cy, cw, ch; if (bd->bg_object) { Evas_Object *layout; layout = e_comp_get(bd)->layout; if (layout) e_layout_freeze(layout); evas_object_geometry_get(bd->bg_object, NULL, NULL, &w, &h); evas_object_resize(bd->bg_object, MAX(w, 50), MAX(h, 50)); edje_object_message_signal_process(bd->bg_object); edje_object_calc_force(bd->bg_object); edje_object_part_geometry_get(bd->bg_object, "e.swallow.client", &cx, &cy, &cw, &ch); bd->client_inset.l = cx; bd->client_inset.r = MAX(w, 50) - (cx + cw); bd->client_inset.t = cy; bd->client_inset.b = MAX(h, 50) - (cy + ch); evas_object_resize(bd->bg_object, w, h); if (layout) e_layout_thaw(layout); } else { bd->client_inset.l = 0; bd->client_inset.r = 0; bd->client_inset.t = 0; bd->client_inset.b = 0; } ecore_x_netwm_frame_size_set(bd->client.win, bd->client_inset.l, bd->client_inset.r, bd->client_inset.t, bd->client_inset.b); ecore_x_e_frame_size_set(bd->client.win, bd->client_inset.l, bd->client_inset.r, bd->client_inset.t, bd->client_inset.b); bd->client_inset.calc = 1; } static void _e_border_maximize(E_Border *bd, E_Maximize max) { int x1, yy1, x2, y2; int w, h, pw, ph; int zx, zy, zw, zh; zx = zy = zw = zh = 0; switch (max & E_MAXIMIZE_TYPE) { case E_MAXIMIZE_NONE: /* Ignore */ break; case E_MAXIMIZE_FULLSCREEN: w = bd->zone->w; h = bd->zone->h; if (bd->bg_object) { edje_object_signal_emit(bd->bg_object, "e,action,maximize,fullscreen", "e"); _e_border_client_inset_calc(bd); } e_border_resize_limit(bd, &w, &h); /* center x-direction */ x1 = bd->zone->x + (bd->zone->w - w) / 2; /* center y-direction */ yy1 = bd->zone->y + (bd->zone->h - h) / 2; switch (max & E_MAXIMIZE_DIRECTION) { case E_MAXIMIZE_BOTH: e_border_move_resize(bd, x1, yy1, w, h); break; case E_MAXIMIZE_VERTICAL: e_border_move_resize(bd, bd->x, yy1, bd->w, h); break; case E_MAXIMIZE_HORIZONTAL: e_border_move_resize(bd, x1, bd->y, w, bd->h); break; case E_MAXIMIZE_LEFT: e_border_move_resize(bd, bd->zone->x, bd->zone->y, w / 2, h); break; case E_MAXIMIZE_RIGHT: e_border_move_resize(bd, x1, bd->zone->y, w / 2, h); break; } break; case E_MAXIMIZE_SMART: case E_MAXIMIZE_EXPAND: if (bd->zone) e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh); w = zw, h = zh; if (bd->bg_object) { edje_object_signal_emit(bd->bg_object, "e,action,maximize", "e"); _e_border_client_inset_calc(bd); } e_border_resize_limit(bd, &w, &h); if (bd->w < zw) w = bd->w; else w = zw; if (bd->h < zh) h = bd->h; else h = zh; if (bd->x < zx) // window left not useful coordinates x1 = zx; else if (bd->x + bd->w > zx + zw) // window right not useful coordinates x1 = zx + zw - bd->w; else // window normal position x1 = bd->x; if (bd->y < zy) // window top not useful coordinates yy1 = zy; else if (bd->y + bd->h > zy + zh) // window bottom not useful coordinates yy1 = zy + zh - bd->h; else // window normal position yy1 = bd->y; switch (max & E_MAXIMIZE_DIRECTION) { case E_MAXIMIZE_BOTH: e_border_move_resize(bd, zx, zy, zw, zh); break; case E_MAXIMIZE_VERTICAL: e_border_move_resize(bd, x1, zy, w, zh); break; case E_MAXIMIZE_HORIZONTAL: e_border_move_resize(bd, zx, yy1, zw, h); break; case E_MAXIMIZE_LEFT: e_border_move_resize(bd, zx, zy, zw / 2, zh); break; case E_MAXIMIZE_RIGHT: e_border_move_resize(bd, zx + zw / 2, zy, zw / 2, zh); break; } break; case E_MAXIMIZE_FILL: x1 = bd->zone->x; yy1 = bd->zone->y; x2 = bd->zone->x + bd->zone->w; y2 = bd->zone->y + bd->zone->h; /* walk through all shelves */ e_maximize_border_shelf_fill(bd, &x1, &yy1, &x2, &y2, max); /* walk through all windows */ e_maximize_border_border_fill(bd, &x1, &yy1, &x2, &y2, max); w = x2 - x1; h = y2 - yy1; pw = w; ph = h; e_border_resize_limit(bd, &w, &h); /* center x-direction */ x1 = x1 + (pw - w) / 2; /* center y-direction */ yy1 = yy1 + (ph - h) / 2; switch (max & E_MAXIMIZE_DIRECTION) { case E_MAXIMIZE_BOTH: e_border_move_resize(bd, x1, yy1, w, h); break; case E_MAXIMIZE_VERTICAL: e_border_move_resize(bd, bd->x, yy1, bd->w, h); break; case E_MAXIMIZE_HORIZONTAL: e_border_move_resize(bd, x1, bd->y, w, bd->h); break; case E_MAXIMIZE_LEFT: e_border_move_resize(bd, bd->zone->x, bd->zone->y, w / 2, h); break; case E_MAXIMIZE_RIGHT: e_border_move_resize(bd, x1, bd->zone->y, w / 2, h); break; } break; } } EAPI void e_border_maximize(E_Border *bd, E_Maximize max) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH; if ((bd->shaded) || (bd->shading)) return; ecore_x_window_shadow_tree_flush(); if (bd->fullscreen) e_border_unfullscreen(bd); /* Only allow changes in vertical/ horizontal maximization */ if (((bd->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION)) || ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return; if (bd->new_client) { bd->need_maximize = 1; bd->maximized &= ~E_MAXIMIZE_TYPE; bd->maximized |= max; return; } bd->pre_res_change.valid = 0; if (!(bd->maximized & E_MAXIMIZE_HORIZONTAL)) { /* Horizontal hasn't been set */ bd->saved.x = bd->x - bd->zone->x; bd->saved.w = bd->w; } if (!(bd->maximized & E_MAXIMIZE_VERTICAL)) { /* Vertical hasn't been set */ bd->saved.y = bd->y - bd->zone->y; bd->saved.h = bd->h; } bd->saved.zone = bd->zone->num; e_hints_window_size_set(bd); e_border_raise(bd); _e_border_maximize(bd, max); /* Remove previous type */ bd->maximized &= ~E_MAXIMIZE_TYPE; /* Add new maximization. It must be added, so that VERTICAL + HORIZONTAL == BOTH */ bd->maximized |= max; if ((bd->maximized & E_MAXIMIZE_DIRECTION) > E_MAXIMIZE_BOTH) /* left/right maximize */ e_hints_window_maximized_set(bd, 0, ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_LEFT) || ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_RIGHT)); else e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL, bd->maximized & E_MAXIMIZE_VERTICAL); e_remember_update(bd); } EAPI void e_border_unmaximize(E_Border *bd, E_Maximize max) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!(max & E_MAXIMIZE_DIRECTION)) { CRI("BUG: Unmaximize call without direction!"); return; } if ((bd->shaded) || (bd->shading)) return; ecore_x_window_shadow_tree_flush(); /* Remove directions not used */ max &= (bd->maximized & E_MAXIMIZE_DIRECTION); /* Can only remove existing maximization directions */ if (!max) return; if (bd->maximized & E_MAXIMIZE_TYPE) { bd->pre_res_change.valid = 0; bd->need_maximize = 0; if ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN) { if (bd->bg_object) { edje_object_signal_emit(bd->bg_object, "e,action,unmaximize,fullscreen", "e"); _e_border_client_inset_calc(bd); } bd->maximized = E_MAXIMIZE_NONE; _e_border_move_resize_internal(bd, bd->zone->x + bd->saved.x, bd->zone->y + bd->saved.y, bd->saved.w, bd->saved.h, 0, 1); bd->saved.x = bd->saved.y = bd->saved.w = bd->saved.h = 0; e_hints_window_size_unset(bd); } else { int w, h, x, y; w = bd->w; h = bd->h; x = bd->x; y = bd->y; if (((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_SMART) || ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_EXPAND)) { if (bd->bg_object) { edje_object_signal_emit(bd->bg_object, "e,action,unmaximize,fullscreen", "e"); _e_border_client_inset_calc(bd); } } if (max & E_MAXIMIZE_VERTICAL) { /* Remove vertical */ h = bd->saved.h; y = bd->saved.y + bd->zone->y; bd->saved.h = bd->saved.y = 0; bd->maximized &= ~E_MAXIMIZE_VERTICAL; bd->maximized &= ~E_MAXIMIZE_LEFT; bd->maximized &= ~E_MAXIMIZE_RIGHT; } if (max & E_MAXIMIZE_HORIZONTAL) { /* Remove horizontal */ w = bd->saved.w; x = bd->saved.x + bd->zone->x; bd->saved.w = bd->saved.x = 0; bd->maximized &= ~E_MAXIMIZE_HORIZONTAL; } e_border_resize_limit(bd, &w, &h); if (!(bd->maximized & E_MAXIMIZE_DIRECTION)) { bd->maximized = E_MAXIMIZE_NONE; _e_border_move_resize_internal(bd, x, y, w, h, 0, 1); e_hints_window_size_unset(bd); edje_object_signal_emit(bd->bg_object, "e,action,unmaximize", "e"); } else { _e_border_move_resize_internal(bd, x, y, w, h, 0, 1); e_hints_window_size_set(bd); } } e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL, bd->maximized & E_MAXIMIZE_VERTICAL); } e_remember_update(bd); } EAPI void e_border_fullscreen(E_Border *bd, E_Fullscreen policy) { E_Event_Border_Fullscreen *ev; int x, y, w, h; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->shaded) || (bd->shading)) return; ecore_x_window_shadow_tree_flush(); if (bd->new_client) { bd->need_fullscreen = 1; return; } if (!bd->fullscreen) { bd->pre_res_change.valid = 0; if (bd->maximized) { x = bd->saved.x; y = bd->saved.y; w = bd->saved.w; h = bd->saved.h; } else { bd->saved.x = bd->x - bd->zone->x; bd->saved.y = bd->y - bd->zone->y; bd->saved.w = bd->client.w; bd->saved.h = bd->client.h; } bd->saved.maximized = bd->maximized; bd->saved.zone = bd->zone->num; if (bd->maximized) { e_border_unmaximize(bd, E_MAXIMIZE_BOTH); bd->saved.x = x; bd->saved.y = y; bd->saved.w = w; bd->saved.h = h; } e_hints_window_size_set(bd); bd->client_inset.l = 0; bd->client_inset.r = 0; bd->client_inset.t = 0; bd->client_inset.b = 0; bd->desk->fullscreen_borders++; /* e_zone_fullscreen_set(bd->zone, 1); */ bd->saved.layer = bd->layer; if (!e_config->allow_above_fullscreen) e_border_layer_set(bd, E_LAYER_FULLSCREEN); else if (e_config->mode.presentation) e_border_layer_set(bd, E_LAYER_TOP); if ((eina_list_count(bd->zone->container->zones) > 1) || (policy == E_FULLSCREEN_RESIZE) || (!ecore_x_randr_query())) { e_border_move_resize(bd, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h); } else if (policy == E_FULLSCREEN_ZOOM) { Ecore_X_Randr_Screen_Size_MM *sizes; int num_sizes, i, best_size_index = 0; ecore_x_randr_screen_primary_output_current_size_get(bd->zone->container->manager->root, &screen_size.width, &screen_size.height, NULL, NULL, NULL); sizes = ecore_x_randr_screen_primary_output_sizes_get(bd->zone->container->manager->root, &num_sizes); if (sizes) { Ecore_X_Randr_Screen_Size best_size = { -1, -1 }; int best_dist = INT_MAX, dist; for (i = 0; i < num_sizes; i++) { if ((sizes[i].width > bd->w) && (sizes[i].height > bd->h)) { dist = (sizes[i].width * sizes[i].height) - (bd->w * bd->h); if (dist < best_dist) { best_size.width = sizes[i].width; best_size.height = sizes[i].height; best_dist = dist; best_size_index = i; } } } if (((best_size.width != -1) && (best_size.height != -1)) && ((best_size.width != screen_size.width) || (best_size.height != screen_size.height))) { if (ecore_x_randr_screen_primary_output_size_set(bd->zone->container->manager->root, best_size_index)) screen_size_index = best_size_index; e_border_move_resize(bd, 0, 0, best_size.width, best_size.height); } else { screen_size.width = -1; screen_size.height = -1; e_border_move_resize(bd, 0, 0, bd->zone->w, bd->zone->h); } free(sizes); } else e_border_move_resize(bd, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h); } bd->fullscreen = 1; e_hints_window_fullscreen_set(bd, 1); e_hints_window_size_unset(bd); bd->client.border.changed = 1; BD_CHANGED(bd); } bd->fullscreen_policy = policy; _e_border_shadow(bd); ev = E_NEW(E_Event_Border_Fullscreen, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_fullscreen_event"); ecore_event_add(E_EVENT_BORDER_FULLSCREEN, ev, _e_border_event_border_fullscreen_free, NULL); e_remember_update(bd); } EAPI void e_border_unfullscreen(E_Border *bd) { E_Event_Border_Unfullscreen *ev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->shaded) || (bd->shading)) return; ecore_x_window_shadow_tree_flush(); if (bd->fullscreen) { bd->pre_res_change.valid = 0; bd->fullscreen = 0; bd->need_fullscreen = 0; bd->desk->fullscreen_borders--; if ((screen_size.width != -1) && (screen_size.height != -1)) { ecore_x_randr_screen_primary_output_size_set(bd->zone->container->manager->root, screen_size_index); screen_size.width = -1; screen_size.height = -1; } _e_border_move_resize_internal(bd, bd->zone->x + bd->saved.x, bd->zone->y + bd->saved.y, bd->saved.w, bd->saved.h, 0, 1); if (bd->saved.maximized) e_border_maximize(bd, (e_config->maximize_policy & E_MAXIMIZE_TYPE) | bd->saved.maximized); e_border_layer_set(bd, bd->saved.layer); e_hints_window_fullscreen_set(bd, 0); bd->client.border.changed = 1; BD_CHANGED(bd); } bd->fullscreen_policy = 0; _e_border_shadow(bd); ev = E_NEW(E_Event_Border_Unfullscreen, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_unfullscreen_event"); ecore_event_add(E_EVENT_BORDER_UNFULLSCREEN, ev, _e_border_event_border_unfullscreen_free, NULL); e_remember_update(bd); } EAPI void e_border_iconify(E_Border *bd) { E_Event_Border_Iconify *ev; unsigned int iconic; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->shading) return; ecore_x_window_shadow_tree_flush(); if (!bd->iconic) { bd->iconic = 1; e_border_hide(bd, 1); if (bd->fullscreen) bd->desk->fullscreen_borders--; edje_object_signal_emit(bd->bg_object, "e,action,iconify", "e"); } iconic = 1; e_hints_window_iconic_set(bd); ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &iconic, 1); ev = E_NEW(E_Event_Border_Iconify, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_iconify_event"); ecore_event_add(E_EVENT_BORDER_ICONIFY, ev, _e_border_event_border_iconify_free, NULL); if (e_config->transient.iconify) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_FREE(list, child) e_border_iconify(child); } e_remember_update(bd); } EAPI void e_border_uniconify(E_Border *bd) { E_Desk *desk; E_Event_Border_Uniconify *ev; unsigned int iconic; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->shading) return; ecore_x_window_shadow_tree_flush(); e_border_show(bd); if (bd->iconic) { bd->iconic = 0; if (bd->fullscreen) bd->desk->fullscreen_borders++; desk = e_desk_current_get(bd->desk->zone); e_border_desk_set(bd, desk); e_border_raise(bd); edje_object_signal_emit(bd->bg_object, "e,action,uniconify", "e"); } iconic = 0; ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &iconic, 1); ev = E_NEW(E_Event_Border_Uniconify, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_uniconify_event"); ecore_event_add(E_EVENT_BORDER_UNICONIFY, ev, _e_border_event_border_uniconify_free, NULL); if (e_config->transient.iconify) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_FREE(list, child) e_border_uniconify(child); } e_remember_update(bd); } EAPI void e_border_stick(E_Border *bd) { E_Event_Border_Stick *ev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->sticky) return; bd->sticky = 1; e_hints_window_sticky_set(bd, 1); e_border_show(bd); if (e_config->transient.desktop) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_FREE(list, child) { child->sticky = 1; e_hints_window_sticky_set(child, 1); e_border_show(child); } } edje_object_signal_emit(bd->bg_object, "e,state,sticky", "e"); ev = E_NEW(E_Event_Border_Stick, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_stick_event"); ecore_event_add(E_EVENT_BORDER_STICK, ev, _e_border_event_border_stick_free, NULL); e_remember_update(bd); } EAPI void e_border_unstick(E_Border *bd) { E_Event_Border_Unstick *ev; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); /* Set the desk before we unstick the border */ if (!bd->sticky) return; bd->sticky = 0; e_hints_window_sticky_set(bd, 0); if (e_config->transient.desktop) { E_Border *child; Eina_List *list = _e_border_sub_borders_new(bd); EINA_LIST_FREE(list, child) { child->sticky = 0; e_hints_window_sticky_set(child, 0); } } edje_object_signal_emit(bd->bg_object, "e,state,unsticky", "e"); ev = E_NEW(E_Event_Border_Unstick, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_unstick_event"); ecore_event_add(E_EVENT_BORDER_UNSTICK, ev, _e_border_event_border_unstick_free, NULL); e_border_desk_set(bd, e_desk_current_get(bd->zone)); e_remember_update(bd); } EAPI void e_border_pinned_set(E_Border *bd, int set) { E_Layer layer; if (bd) { bd->borderless = set; bd->user_skip_winlist = set; if (set) layer = E_LAYER_BELOW; else layer = E_LAYER_NORMAL; e_border_layer_set(bd, layer); bd->client.border.changed = 1; BD_CHANGED(bd); } } EAPI E_Border * e_border_find_by_client_window(Ecore_X_Window win) { E_Border *bd; bd = eina_hash_find(borders_hash, e_util_winid_str_get(win)); if ((bd) && (!e_object_is_del(E_OBJECT(bd))) && (bd->client.win == win)) return bd; return NULL; } EAPI E_Border * e_border_find_all_by_client_window(Ecore_X_Window win) { E_Border *bd; bd = eina_hash_find(borders_hash, e_util_winid_str_get(win)); if ((bd) && (bd->client.win == win)) return bd; return NULL; } EAPI E_Border * e_border_find_by_window(Ecore_X_Window win) { E_Border *bd; bd = eina_hash_find(borders_hash, e_util_winid_str_get(win)); if ((bd) && (!e_object_is_del(E_OBJECT(bd))) && ((bd->win == win) || (bd->client.lock_win == win))) return bd; return NULL; } EAPI E_Border * e_border_find_by_alarm(Ecore_X_Sync_Alarm al) { Eina_List *l; E_Border *bd; EINA_LIST_FOREACH(borders, l, bd) { if ((bd) && (!e_object_is_del(E_OBJECT(bd))) && (bd->client.netwm.sync.alarm == al)) return bd; } return NULL; } EAPI E_Border * e_border_focused_get(void) { return focused; } static void _e_border_shape_input_rectangle_set(E_Border *bd) { if (!bd) return; if ((!bd->visible) || (!bd->shaped_input)) { if (bd->visible) // not shaped input { if (!((bd->comp_hidden) || (bd->tmp_input_hidden > 0))) ecore_x_composite_window_events_enable(bd->win); else ecore_x_composite_window_events_disable(bd->win); } else { if (!e_comp_evas_exists(bd)) ecore_x_composite_window_events_enable(bd->win); else ecore_x_composite_window_events_disable(bd->win); } } } EAPI void e_border_idler_before(void) { Eina_List *ml, *cl; E_Manager *man; E_Container *con; if (!borders) return; EINA_LIST_FOREACH(e_manager_list(), ml, man) { EINA_LIST_FOREACH(man->containers, cl, con) { E_Border_List *bl; E_Border *bd; // pass 1 - eval0. fetch properties on new or on change and // call hooks to decide what to do - maybe move/resize bl = e_container_border_list_last(con); while ((bd = e_container_border_list_prev(bl))) { if (bd->changed) _e_border_eval0(bd); } e_container_border_list_free(bl); // layout hook - this is where a hook gets to figure out what to // do if anything. _e_border_container_layout_hook(con); // pass 2 - show windows needing show bl = e_container_border_list_last(con); while ((bd = e_container_border_list_prev(bl))) { if ((bd->changes.visible) && (bd->visible) && (!bd->new_client) && (!bd->changes.pos) && (!bd->changes.size)) { _e_border_show(bd); bd->changes.visible = 0; } if (bd->zone && (!bd->new_client) && (!E_INSIDE(bd->x, bd->y, 0, 0, bd->zone->w - 5, bd->zone->h - 5)) && (!E_INSIDE(bd->x, bd->y, 0 - bd->w + 5, 0 - bd->h + 5, bd->zone->w - 5, bd->zone->h - 5)) ) { if (e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY) _e_border_move_lost_window_to_center(bd); } } e_container_border_list_free(bl); // pass 3 - hide windows needing hide and eval (main eval) bl = e_container_border_list_first(con); while ((bd = e_container_border_list_next(bl))) { if (e_object_is_del(E_OBJECT(bd))) continue; if ((bd->changes.visible) && (!bd->visible)) { _e_border_hide(bd); bd->changes.visible = 0; } if (bd->changed) _e_border_eval(bd); if ((bd->changes.visible) && (bd->visible)) { _e_border_show(bd); bd->changes.visible = 0; } } e_container_border_list_free(bl); } } if (focus_next) { E_Border *bd = NULL, *bd2; EINA_LIST_FREE(focus_next, bd2) if ((!bd) && (bd2->visible)) bd = bd2; if (!bd) { /* TODO revert focus when lost here ? */ return; } #if 0 if (bd == focused) { /* already focused. but anyway dont be so strict, this fcks up illume setting focus on internal windows */ return; } #endif focus_time = ecore_x_current_time_get(); focusing = bd; if ((bd->client.icccm.take_focus) && (bd->client.icccm.accepts_focus)) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_LOCALLY_ACTIVE); /* TODO what if the client didn't take focus ? */ } else if (!bd->client.icccm.accepts_focus) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_GLOBALLY_ACTIVE); } else if (!bd->client.icccm.take_focus) { e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_PASSIVE); /* e_border_focus_set(bd, 1, 0); */ } } } EAPI Eina_List * e_border_client_list(void) { /* FIXME: This should be a somewhat ordered list */ return borders; } static void _e_border_show(E_Border *bd) { Eina_List *l; E_Border *tmp; if (bd->post_job) { bd->post_show = 1; return; } if (!((bd->comp_hidden) || (bd->tmp_input_hidden > 0))) { _e_border_shape_input_rectangle_set(bd); // not anymore // ecore_x_composite_window_events_enable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_FALSE); } ecore_x_window_show(bd->win); EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_show(tmp->win); } static void _e_border_hide(E_Border *bd) { E_Border *tmp; Eina_List *l; if (!e_comp_evas_exists(bd)) { ecore_x_window_hide(bd->win); EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_hide(tmp->win); } else { ecore_x_composite_window_events_disable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_TRUE); } } static int _e_border_action_input_win_del(void) { if (!action_input_win) return 0; e_grabinput_release(action_input_win, action_input_win); action_input_win = 0; return 1; } static int _e_border_action_input_win_new(E_Border *bd) { if (!action_input_win) action_input_win = e_comp_get(bd)->ee_win; if (e_grabinput_get(action_input_win, 0, action_input_win)) return 1; _e_border_action_input_win_del(); return 0; } static void _e_border_action_finish(void) { _e_border_action_input_win_del(); if (action_timer) { ecore_timer_del(action_timer); action_timer = NULL; } if (action_handler_key) { ecore_event_handler_del(action_handler_key); action_handler_key = NULL; } if (action_handler_mouse) { ecore_event_handler_del(action_handler_mouse); action_handler_mouse = NULL; } action_border = NULL; } static void _e_border_action_init(E_Border *bd) { action_orig.x = bd->x; action_orig.y = bd->y; action_orig.width = bd->w; action_orig.height = bd->h; action_border = bd; } static void _e_border_action_restore_orig(E_Border *bd) { if (action_border != bd) return; e_border_move_resize(bd, action_orig.x, action_orig.y, action_orig.width, action_orig.height); } static int _e_border_key_down_modifier_apply(int modifier, int value) { if (modifier & ECORE_EVENT_MODIFIER_CTRL) return value * 2; else if (modifier & ECORE_EVENT_MODIFIER_ALT) { value /= 2; if (value) return value; else return 1; } return value; } static Eina_Bool _e_border_action_move_timeout(void *data __UNUSED__) { _e_border_move_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_CANCEL; } static void _e_border_action_move_timeout_add(void) { E_FREE_FUNC(action_timer, ecore_timer_del); if (e_config->border_keyboard.timeout) action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_border_action_move_timeout, NULL); } static Eina_Bool _e_border_move_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Event_Key *ev = event; int x, y; if (ev->event_window != action_input_win) return ECORE_CALLBACK_PASS_ON; if (!action_border) { fputs("ERROR: no action_border!\n", stderr); goto stop; } x = action_border->x; y = action_border->y; if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0)) y -= _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1)); else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0)) y += _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1)); else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0)) x -= _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1)); else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0)) x += _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1)); else if (strcmp(ev->key, "Return") == 0) goto stop; else if (strcmp(ev->key, "Escape") == 0) { _e_border_action_restore_orig(action_border); goto stop; } else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) && (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0)) goto stop; e_border_move(action_border, x, y); _e_border_action_move_timeout_add(); return ECORE_CALLBACK_PASS_ON; stop: _e_border_move_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_DONE; } static Eina_Bool _e_border_move_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Event_Mouse_Button *ev = event; if (ev->event_window != action_input_win) return ECORE_CALLBACK_PASS_ON; if (!action_border) fputs("ERROR: no action_border!\n", stderr); _e_border_move_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_DONE; } EAPI void e_border_act_move_keyboard(E_Border *bd) { if (!bd) return; if (!_e_border_move_begin(bd)) return; if (!_e_border_action_input_win_new(bd)) { _e_border_move_end(bd); return; } _e_border_action_init(bd); _e_border_action_move_timeout_add(); _e_border_move_update(bd); if (action_handler_key) ecore_event_handler_del(action_handler_key); action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_border_move_key_down, NULL); if (action_handler_mouse) ecore_event_handler_del(action_handler_mouse); action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_border_move_mouse_down, NULL); } static Eina_Bool _e_border_action_resize_timeout(void *data __UNUSED__) { _e_border_resize_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_CANCEL; } static void _e_border_action_resize_timeout_add(void) { E_FREE_FUNC(action_timer, ecore_timer_del); if (e_config->border_keyboard.timeout) action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_border_action_resize_timeout, NULL); } static Eina_Bool _e_border_resize_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Event_Key *ev = event; int w, h, dx, dy; if (ev->event_window != action_input_win) return ECORE_CALLBACK_PASS_ON; if (!action_border) { fputs("ERROR: no action_border!\n", stderr); goto stop; } w = action_border->w; h = action_border->h; dx = e_config->border_keyboard.resize.dx; if (dx < action_border->client.icccm.step_w) dx = action_border->client.icccm.step_w; dx = _e_border_key_down_modifier_apply(ev->modifiers, dx); if (dx < action_border->client.icccm.step_w) dx = action_border->client.icccm.step_w; dy = e_config->border_keyboard.resize.dy; if (dy < action_border->client.icccm.step_h) dy = action_border->client.icccm.step_h; dy = _e_border_key_down_modifier_apply(ev->modifiers, dy); if (dy < action_border->client.icccm.step_h) dy = action_border->client.icccm.step_h; if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0)) h -= dy; else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0)) h += dy; else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0)) w -= dx; else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0)) w += dx; else if (strcmp(ev->key, "Return") == 0) goto stop; else if (strcmp(ev->key, "Escape") == 0) { _e_border_action_restore_orig(action_border); goto stop; } else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) && (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0)) goto stop; e_border_resize_limit(action_border, &w, &h); e_border_resize(action_border, w, h); _e_border_action_resize_timeout_add(); return ECORE_CALLBACK_PASS_ON; stop: _e_border_resize_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_DONE; } static Eina_Bool _e_border_resize_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Event_Mouse_Button *ev = event; if (ev->event_window != action_input_win) return ECORE_CALLBACK_PASS_ON; if (!action_border) fputs("ERROR: no action_border!\n", stderr); _e_border_resize_end(action_border); _e_border_action_finish(); return ECORE_CALLBACK_DONE; } EAPI void e_border_act_resize_keyboard(E_Border *bd) { if (!bd) return; if (!_e_border_resize_begin(bd)) return; if (!_e_border_action_input_win_new(bd)) { _e_border_resize_end(bd); return; } _e_border_action_init(bd); _e_border_action_resize_timeout_add(); _e_border_resize_update(bd); if (action_handler_key) ecore_event_handler_del(action_handler_key); action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_border_resize_key_down, NULL); if (action_handler_mouse) ecore_event_handler_del(action_handler_mouse); action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_border_resize_mouse_down, NULL); } EAPI void e_border_act_move_begin(E_Border *bd, E_Binding_Event_Mouse_Button *ev) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return; if (!_e_border_move_begin(bd)) return; if (!_e_border_action_input_win_new(bd)) { _e_border_move_end(bd); return; } _e_border_action_init(bd); e_zone_edge_disable(); bd->moving = 1; e_pointer_mode_push(bd, E_POINTER_MOVE); if (ev) { char source[256]; snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button); _e_border_moveinfo_gather(bd, source); } } EAPI void e_border_act_move_end(E_Border *bd, E_Binding_Event_Mouse_Button *ev __UNUSED__) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!bd->moving) return; e_zone_edge_enable(); _e_border_move_end(bd); e_zone_flip_coords_handle(bd->zone, -1, -1); _e_border_action_finish(); } EAPI void e_border_act_resize_begin(E_Border *bd, E_Binding_Event_Mouse_Button *ev) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->lock_user_size || bd->shaded || bd->shading) return; if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return; if (!_e_border_resize_begin(bd)) return; if (!_e_border_action_input_win_new(bd)) { _e_border_resize_end(bd); return; } _e_border_action_init(bd); if (bd->mouse.current.mx < (bd->x + bd->w / 2)) { if (bd->mouse.current.my < (bd->y + bd->h / 2)) { bd->resize_mode = E_POINTER_RESIZE_TL; GRAV_SET(bd, ECORE_X_GRAVITY_SE); } else { bd->resize_mode = E_POINTER_RESIZE_BL; GRAV_SET(bd, ECORE_X_GRAVITY_NE); } } else { if (bd->mouse.current.my < (bd->y + bd->h / 2)) { bd->resize_mode = E_POINTER_RESIZE_TR; GRAV_SET(bd, ECORE_X_GRAVITY_SW); } else { bd->resize_mode = E_POINTER_RESIZE_BR; GRAV_SET(bd, ECORE_X_GRAVITY_NW); } } e_pointer_mode_push(bd, bd->resize_mode); if (ev) { char source[256]; snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button); _e_border_moveinfo_gather(bd, source); } } EAPI void e_border_act_resize_end(E_Border *bd, E_Binding_Event_Mouse_Button *ev __UNUSED__) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->resize_mode != E_POINTER_RESIZE_NONE) { _e_border_resize_end(bd); bd->changes.reset_gravity = 1; BD_CHANGED(bd); } _e_border_action_finish(); } EAPI void e_border_act_menu_begin(E_Border *bd, E_Binding_Event_Mouse_Button *ev, int key) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (ev) e_int_border_menu_show(bd, ev->canvas.x, ev->canvas.y, key, ev->timestamp); else { int x, y; ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y); e_int_border_menu_show(bd, x, y, key, 0); } } EAPI void e_border_act_close_begin(E_Border *bd) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->lock_close) return; if (bd->client.icccm.delete_request) { bd->delete_requested = 1; ecore_x_window_delete_request_send(bd->client.win); if (bd->client.netwm.ping) e_border_ping(bd); } else if (e_config->kill_if_close_not_possible) { e_border_act_kill_begin(bd); } } EAPI void e_border_act_kill_begin(E_Border *bd) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->internal) return; if (bd->lock_close) return; if ((bd->client.netwm.pid > 1) && (e_config->kill_process)) { kill(bd->client.netwm.pid, SIGINT); bd->kill_timer = ecore_timer_add(e_config->kill_timer_wait, _e_border_cb_kill_timer, bd); } else { if (!bd->internal) ecore_x_kill(bd->client.win); } } EAPI Evas_Object * e_border_icon_add(E_Border *bd, Evas *evas) { Evas_Object *o; E_OBJECT_CHECK_RETURN(bd, NULL); E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, NULL); o = NULL; if (bd->internal) { if (!bd->internal_icon) { o = e_icon_add(evas); e_util_icon_theme_set(o, "enlightenment"); } else { if (!bd->internal_icon_key) { char *ext; ext = strrchr(bd->internal_icon, '.'); if ((ext) && ((!strcmp(ext, ".edj")))) { o = edje_object_add(evas); if (!edje_object_file_set(o, bd->internal_icon, "icon")) e_util_icon_theme_set(o, "enlightenment"); } else if (ext) { o = e_icon_add(evas); e_icon_file_set(o, bd->internal_icon); } else { o = e_icon_add(evas); if (!e_util_icon_theme_set(o, bd->internal_icon)) e_util_icon_theme_set(o, "enlightenment"); } } else { o = edje_object_add(evas); edje_object_file_set(o, bd->internal_icon, bd->internal_icon_key); } } return o; } if ((e_config->use_app_icon) && (bd->icon_preference != E_ICON_PREF_USER)) { if (bd->client.netwm.icons) { o = e_icon_add(evas); e_icon_data_set(o, bd->client.netwm.icons[0].data, bd->client.netwm.icons[0].width, bd->client.netwm.icons[0].height); e_icon_alpha_set(o, 1); return o; } } if (!o) { if ((bd->desktop) && (bd->icon_preference != E_ICON_PREF_NETWM)) { o = e_icon_add(evas); if (o) { e_icon_fdo_icon_set(o, bd->desktop->icon); return o; } } else if (bd->client.netwm.icons) { o = e_icon_add(evas); e_icon_data_set(o, bd->client.netwm.icons[0].data, bd->client.netwm.icons[0].width, bd->client.netwm.icons[0].height); e_icon_alpha_set(o, 1); return o; } } o = e_icon_add(evas); e_util_icon_theme_set(o, "unknown"); return o; } EAPI void e_border_button_bindings_ungrab_all(void) { Eina_List *l; E_Border *bd; EINA_LIST_FOREACH(borders, l, bd) { e_focus_setdown(bd); e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); } } EAPI void e_border_button_bindings_grab_all(void) { Eina_List *l; E_Border *bd; EINA_LIST_FOREACH(borders, l, bd) { e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, bd->win); e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, bd->win); e_focus_setup(bd); } } EAPI Eina_List * e_border_focus_stack_get(void) { return focus_stack; } EAPI Eina_List * e_border_raise_stack_get(void) { return raise_stack; } EAPI Eina_List * e_border_lost_windows_get(E_Zone *zone) { Eina_List *list = NULL, *l; E_Border *bd; int loss_overlap = 5; E_OBJECT_CHECK_RETURN(zone, NULL); E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL); EINA_LIST_FOREACH(borders, l, bd) { if (!bd->zone) continue; if ((bd->zone != zone) || (bd->zone->container != zone->container)) continue; if (!E_INTERSECTS(bd->zone->x + loss_overlap, bd->zone->y + loss_overlap, bd->zone->w - (2 * loss_overlap), bd->zone->h - (2 * loss_overlap), bd->x, bd->y, bd->w, bd->h)) { list = eina_list_append(list, bd); } } return list; } static void _e_border_zones_layout_calc(E_Border *bd, int *zx, int *zy, int *zw, int *zh) { int x, y, w, h; E_Zone *zone_above, *zone_below, *zone_left, *zone_right; x = bd->zone->x; y = bd->zone->y; w = bd->zone->w; h = bd->zone->h; if (eina_list_count(bd->zone->container->zones) == 1) { if (zx) *zx = x; if (zy) *zy = y; if (zw) *zw = w; if (zh) *zh = h; return; } zone_left = e_container_zone_at_point_get(bd->zone->container, (x - w + 5), y); zone_right = e_container_zone_at_point_get(bd->zone->container, (x + w + 5), y); zone_above = e_container_zone_at_point_get(bd->zone->container, x, (y - h + 5)); zone_below = e_container_zone_at_point_get(bd->zone->container, x, (y + h + 5)); if (!(zone_above) && (y)) zone_above = e_container_zone_at_point_get(bd->zone->container, x, (h - 5)); if (!(zone_left) && (x)) zone_left = e_container_zone_at_point_get(bd->zone->container, (x - 5), y); if (zone_right) w = zone_right->x + zone_right->w; if (zone_left) w = bd->zone->x + bd->zone->w; if (zone_below) h = zone_below->y + zone_below->h; if (zone_above) h = bd->zone->y + bd->zone->h; if ((zone_left) && (zone_right)) w = bd->zone->w + zone_right->x; if ((zone_above) && (zone_below)) h = bd->zone->h + zone_below->y; if (x) x -= bd->zone->w; if (y) y -= bd->zone->h; if (zx) *zx = x > 0 ? x : 0; if (zy) *zy = y > 0 ? y : 0; if (zw) *zw = w; if (zh) *zh = h; } static void _e_border_move_lost_window_to_center(E_Border *bd) { int loss_overlap = 5; int zw, zh, zx, zy; if (bd->during_lost) return; if (!(bd->zone)) return; _e_border_zones_layout_calc(bd, &zx, &zy, &zw, &zh); if (!E_INTERSECTS(zx + loss_overlap, zy + loss_overlap, zw - (2 * loss_overlap), zh - (2 * loss_overlap), bd->x, bd->y, bd->w, bd->h)) { if (e_config->edge_flip_dragging) { Eina_Bool lf, rf, tf, bf; lf = rf = tf = bf = EINA_TRUE; if (bd->zone->desk_x_count <= 1) lf = rf = EINA_FALSE; else if (!e_config->desk_flip_wrap) { if (bd->zone->desk_x_current == 0) lf = EINA_FALSE; if (bd->zone->desk_x_current == (bd->zone->desk_x_count - 1)) rf = EINA_FALSE; } if (bd->zone->desk_y_count <= 1) tf = bf = EINA_FALSE; else if (!e_config->desk_flip_wrap) { if (bd->zone->desk_y_current == 0) tf = EINA_FALSE; if (bd->zone->desk_y_current == (bd->zone->desk_y_count - 1)) bf = EINA_FALSE; } if (!(lf) && (bd->x <= loss_overlap) && !(bd->zone->flip.switching)) _e_border_reset_lost_window(bd); if (!(rf) && (bd->x >= (bd->zone->w - loss_overlap)) && !(bd->zone->flip.switching)) _e_border_reset_lost_window(bd); if (!(tf) && (bd->y <= loss_overlap) && !(bd->zone->flip.switching)) _e_border_reset_lost_window(bd); if (!(bf) && (bd->y >= (bd->zone->h - loss_overlap)) && !(bd->zone->flip.switching)) _e_border_reset_lost_window(bd); } if (!e_config->edge_flip_dragging) _e_border_reset_lost_window(bd); } } static void _e_border_reset_lost_window(E_Border *bd) { E_OBJECT_CHECK(bd); if (bd->during_lost) return; bd->during_lost = EINA_TRUE; if (bd->iconic) e_border_uniconify(bd); if (!bd->moving) e_border_center(bd); e_border_raise(bd); if (!bd->lock_focus_out) e_border_focus_set(bd, 1, 1); e_border_pointer_warp_to_center(bd); bd->during_lost = EINA_FALSE; } EAPI void e_border_ping(E_Border *bd) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!e_config->ping_clients) return; bd->ping_ok = 0; ecore_x_netwm_ping_send(bd->client.win); bd->ping = ecore_loop_time_get(); if (bd->ping_poller) ecore_poller_del(bd->ping_poller); bd->ping_poller = ecore_poller_add(ECORE_POLLER_CORE, e_config->ping_clients_interval, _e_border_cb_ping_poller, bd); } EAPI void e_border_move_cancel(void) { if (bdmove) { if (bdmove->cur_mouse_action) { E_Border *bd; bd = bdmove; e_object_ref(E_OBJECT(bd)); if (bd->cur_mouse_action->func.end_mouse) bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", NULL); else if (bd->cur_mouse_action->func.end) bd->cur_mouse_action->func.end(E_OBJECT(bd), ""); e_object_unref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action = NULL; e_object_unref(E_OBJECT(bd)); } else _e_border_move_end(bdmove); } } EAPI void e_border_resize_cancel(void) { if (bdresize) { if (bdresize->cur_mouse_action) { E_Border *bd; bd = bdresize; e_object_ref(E_OBJECT(bd)); if (bd->cur_mouse_action->func.end_mouse) bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", NULL); else if (bd->cur_mouse_action->func.end) bd->cur_mouse_action->func.end(E_OBJECT(bd), ""); e_object_unref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action = NULL; e_object_unref(E_OBJECT(bd)); } else { _e_border_resize_end(bdresize); } } } EAPI void e_border_frame_recalc(E_Border *bd) { int w, h; if (!bd->bg_object) return; w = bd->w, h = bd->h; bd->w -= e_border_inset_width_get(bd); bd->h -= e_border_inset_height_get(bd); _e_border_client_inset_calc(bd); bd->w += e_border_inset_width_get(bd); bd->h += e_border_inset_height_get(bd); if (bd->changes.shading || bd->changes.shaded) return; if ((w != bd->w) || (h != bd->h)) { BD_CHANGED(bd); bd->changes.size = 1; if (bd->client.shaped) { bd->need_shape_merge = 1; bd->need_shape_export = 1; } if (bd->shaped_input) { bd->need_shape_merge = 1; } _e_border_client_move_resize_send(bd); } } EAPI Eina_List * e_border_immortal_windows_get(void) { Eina_List *list = NULL, *l; E_Border *bd; EINA_LIST_FOREACH(borders, l, bd) { if (bd->lock_life) list = eina_list_append(list, bd); } return list; } EAPI const char * e_border_name_get(const E_Border *bd) { E_OBJECT_CHECK_RETURN(bd, ""); E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, ""); if (bd->client.netwm.name) return bd->client.netwm.name; else if (bd->client.icccm.title) return bd->client.icccm.title; return ""; } EAPI void e_border_signal_move_begin(E_Border *bd, const char *sig, const char *src __UNUSED__) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return; if (!_e_border_move_begin(bd)) return; bd->moving = 1; e_pointer_mode_push(bd, E_POINTER_MOVE); e_zone_edge_disable(); _e_border_moveinfo_gather(bd, sig); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; else e_object_unref(E_OBJECT(bd->cur_mouse_action)); } bd->cur_mouse_action = e_action_find("window_move"); if (bd->cur_mouse_action) e_object_ref(E_OBJECT(bd->cur_mouse_action)); } EAPI void e_border_signal_move_end(E_Border *bd, const char *sig __UNUSED__, const char *src __UNUSED__) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (!bd->moving) return; e_zone_edge_enable(); _e_border_move_end(bd); e_zone_flip_coords_handle(bd->zone, -1, -1); } EAPI int e_border_resizing_get(E_Border *bd) { E_OBJECT_CHECK_RETURN(bd, 0); E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, 0); if (bd->resize_mode == E_POINTER_RESIZE_NONE) return 0; return 1; } EAPI void e_border_signal_resize_begin(E_Border *bd, const char *dir, const char *sig, const char *src __UNUSED__) { Ecore_X_Gravity grav = ECORE_X_GRAVITY_NW; int resize_mode = E_POINTER_RESIZE_BR; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return; if (!_e_border_resize_begin(bd)) return; if (!strcmp(dir, "tl")) { resize_mode = E_POINTER_RESIZE_TL; grav = ECORE_X_GRAVITY_SE; } else if (!strcmp(dir, "t")) { resize_mode = E_POINTER_RESIZE_T; grav = ECORE_X_GRAVITY_S; } else if (!strcmp(dir, "tr")) { resize_mode = E_POINTER_RESIZE_TR; grav = ECORE_X_GRAVITY_SW; } else if (!strcmp(dir, "r")) { resize_mode = E_POINTER_RESIZE_R; grav = ECORE_X_GRAVITY_W; } else if (!strcmp(dir, "br")) { resize_mode = E_POINTER_RESIZE_BR; grav = ECORE_X_GRAVITY_NW; } else if (!strcmp(dir, "b")) { resize_mode = E_POINTER_RESIZE_B; grav = ECORE_X_GRAVITY_N; } else if (!strcmp(dir, "bl")) { resize_mode = E_POINTER_RESIZE_BL; grav = ECORE_X_GRAVITY_NE; } else if (!strcmp(dir, "l")) { resize_mode = E_POINTER_RESIZE_L; grav = ECORE_X_GRAVITY_E; } bd->resize_mode = resize_mode; e_pointer_mode_push(bd, bd->resize_mode); _e_border_moveinfo_gather(bd, sig); GRAV_SET(bd, grav); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; else e_object_unref(E_OBJECT(bd->cur_mouse_action)); } bd->cur_mouse_action = e_action_find("window_resize"); if (bd->cur_mouse_action) e_object_ref(E_OBJECT(bd->cur_mouse_action)); } EAPI void e_border_signal_resize_end(E_Border *bd, const char *dir __UNUSED__, const char *sig __UNUSED__, const char *src __UNUSED__) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); if (bd->resize_mode == E_POINTER_RESIZE_NONE) return; _e_border_resize_handle(bd); _e_border_resize_end(bd); bd->changes.reset_gravity = 1; BD_CHANGED(bd); } EAPI void e_border_resize_limit(E_Border *bd, int *w, int *h) { double a; Eina_Bool inc_h; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); inc_h = (*h - bd->h > 0); *w -= e_border_inset_width_get(bd); *h -= e_border_inset_height_get(bd); if (*h < 1) *h = 1; if (*w < 1) *w = 1; if ((bd->client.icccm.base_w >= 0) && (bd->client.icccm.base_h >= 0)) { int tw, th; tw = *w - bd->client.icccm.base_w; th = *h - bd->client.icccm.base_h; if (tw < 1) tw = 1; if (th < 1) th = 1; a = (double)(tw) / (double)(th); if ((bd->client.icccm.min_aspect != 0.0) && (a < bd->client.icccm.min_aspect)) { if (inc_h) tw = th * bd->client.icccm.min_aspect; else th = tw / bd->client.icccm.max_aspect; *w = tw + bd->client.icccm.base_w; *h = th + bd->client.icccm.base_h; } else if ((bd->client.icccm.max_aspect != 0.0) && (a > bd->client.icccm.max_aspect)) { tw = th * bd->client.icccm.max_aspect; *w = tw + bd->client.icccm.base_w; } } else { a = (double)*w / (double)*h; if ((bd->client.icccm.min_aspect != 0.0) && (a < bd->client.icccm.min_aspect)) { if (inc_h) *w = *h * bd->client.icccm.min_aspect; else *h = *w / bd->client.icccm.min_aspect; } else if ((bd->client.icccm.max_aspect != 0.0) && (a > bd->client.icccm.max_aspect)) *w = *h * bd->client.icccm.max_aspect; } if (bd->client.icccm.step_w > 0) { if (bd->client.icccm.base_w >= 0) *w = bd->client.icccm.base_w + (((*w - bd->client.icccm.base_w) / bd->client.icccm.step_w) * bd->client.icccm.step_w); else *w = bd->client.icccm.min_w + (((*w - bd->client.icccm.min_w) / bd->client.icccm.step_w) * bd->client.icccm.step_w); } if (bd->client.icccm.step_h > 0) { if (bd->client.icccm.base_h >= 0) *h = bd->client.icccm.base_h + (((*h - bd->client.icccm.base_h) / bd->client.icccm.step_h) * bd->client.icccm.step_h); else *h = bd->client.icccm.min_h + (((*h - bd->client.icccm.min_h) / bd->client.icccm.step_h) * bd->client.icccm.step_h); } if (*h < 1) *h = 1; if (*w < 1) *w = 1; if (*w > bd->client.icccm.max_w) *w = bd->client.icccm.max_w; else if (*w < bd->client.icccm.min_w) *w = bd->client.icccm.min_w; if (*h > bd->client.icccm.max_h) *h = bd->client.icccm.max_h; else if (*h < bd->client.icccm.min_h) *h = bd->client.icccm.min_h; *w += e_border_inset_width_get(bd); *h += e_border_inset_height_get(bd); } EAPI void e_border_input_object_set(E_Border *bd, Evas_Object *input_obj) { E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); bd->input_object = input_obj; if (!bd->input_object) return; evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_IN, _e_border_cb_mouse_in, bd); evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_MOVE, _e_border_cb_mouse_move, bd); evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_OUT, _e_border_cb_mouse_out, bd); evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_DOWN, _e_border_cb_mouse_down, bd); evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_UP, _e_border_cb_mouse_up, bd); evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_WHEEL, _e_border_cb_mouse_wheel, bd); bd->callbacks_set = EINA_TRUE; } /* local subsystem functions */ static void _e_border_free(E_Border *bd) { #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) if (bd->client.e.state.profile.use) { if (bd->client.e.state.profile.available_list) { int i; for (i = 0; i < bd->client.e.state.profile.num; i++) { if (bd->client.e.state.profile.available_list[i]) { eina_stringshare_del(bd->client.e.state.profile.available_list[i]); bd->client.e.state.profile.available_list[i] = NULL; } } E_FREE(bd->client.e.state.profile.available_list); bd->client.e.state.profile.available_list = NULL; } bd->client.e.state.profile.num = 0; if (bd->client.e.state.profile.name) { eina_stringshare_del(bd->client.e.state.profile.name); bd->client.e.state.profile.name = NULL; } bd->client.e.state.profile.wait_for_done = 0; bd->client.e.state.profile.use = 0; } #endif if (bd->client.e.state.video_parent && bd->client.e.state.video_parent_border) { bd->client.e.state.video_parent_border->client.e.state.video_child = eina_list_remove (bd->client.e.state.video_parent_border->client.e.state.video_child, bd); } if (bd->client.e.state.video_child) { E_Border *tmp; EINA_LIST_FREE(bd->client.e.state.video_child, tmp) { tmp->client.e.state.video_parent_border = NULL; } } if (bd->internal_ecore_evas) { e_canvas_del(bd->internal_ecore_evas); ecore_evas_free(bd->internal_ecore_evas); bd->internal_ecore_evas = NULL; } if (bd->desktop) { efreet_desktop_free(bd->desktop); bd->desktop = NULL; } if (bd->post_job) { ecore_idle_enterer_del(bd->post_job); bd->post_job = NULL; } if ((bdresize == bd) || (bd->resize_mode != E_POINTER_RESIZE_NONE)) _e_border_resize_end(bd); if (bdmove == bd) _e_border_move_end(bd); /* TODO: Other states to end before dying? */ if (bd->cur_mouse_action) { e_object_unref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action = NULL; } /* if (bd->dangling_ref_check) { ecore_timer_del(bd->dangling_ref_check); bd->dangling_ref_check = NULL; } */ if (bd->kill_timer) { ecore_timer_del(bd->kill_timer); bd->kill_timer = NULL; } if (bd->ping_poller) { ecore_poller_del(bd->ping_poller); bd->ping_poller = NULL; } E_FREE_LIST(bd->pending_move_resize, free); if (bd->shade.anim) ecore_animator_del(bd->shade.anim); if (bd->border_menu) e_menu_deactivate(bd->border_menu); if (bd->border_locks_dialog) { e_object_del(E_OBJECT(bd->border_locks_dialog)); bd->border_locks_dialog = NULL; } if (bd->border_remember_dialog) { e_object_del(E_OBJECT(bd->border_remember_dialog)); bd->border_remember_dialog = NULL; } if (bd->border_border_dialog) { e_object_del(E_OBJECT(bd->border_border_dialog)); bd->border_border_dialog = NULL; } if (bd->border_prop_dialog) { e_object_del(E_OBJECT(bd->border_prop_dialog)); bd->border_prop_dialog = NULL; } e_int_border_menu_del(bd); if (focusing == bd) focusing = NULL; focus_next = eina_list_remove(focus_next, bd); if ((focused == bd) || (e_grabinput_last_focus_win_get() == bd->client.win)) { if ((!focus_next) && (!focusing)) { e_grabinput_focus(bd->zone->container->bg_win, E_FOCUS_METHOD_PASSIVE); e_hints_active_window_set(bd->zone->container->manager, NULL); } focused = NULL; } if (bd->remember) { E_Remember *rem; rem = bd->remember; bd->remember = NULL; e_remember_unuse(rem); } if (!bd->already_unparented) { ecore_x_window_reparent(bd->client.win, bd->zone->container->manager->root, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t); ecore_x_window_save_set_del(bd->client.win); bd->already_unparented = 1; } if (bd->group) eina_list_free(bd->group); bd->group = NULL; if (bd->transients) eina_list_free(bd->transients); bd->transients = NULL; if (bd->stick_desks) eina_list_free(bd->stick_desks); bd->stick_desks = NULL; if (bd->client.netwm.icons) { int i; for (i = 0; i < bd->client.netwm.num_icons; i++) free(bd->client.netwm.icons[i].data); free(bd->client.netwm.icons); bd->client.netwm.icons = NULL; } free(bd->client.netwm.extra_types); bd->client.netwm.extra_types = NULL; if (bd->client.border.name) eina_stringshare_del(bd->client.border.name); bd->client.border.name = NULL; if (bd->bordername) eina_stringshare_del(bd->bordername); bd->bordername = NULL; if (bd->client.icccm.name) eina_stringshare_del(bd->client.icccm.name); bd->client.icccm.name = NULL; if (bd->client.icccm.class) { if (bd->client.hacks.mapping_change) e_bindings_mapping_change_enable(EINA_TRUE); eina_stringshare_del(bd->client.icccm.class); bd->client.icccm.class = NULL; } if (bd->client.icccm.title) eina_stringshare_del(bd->client.icccm.title); bd->client.icccm.title = NULL; if (bd->client.icccm.icon_name) eina_stringshare_del(bd->client.icccm.icon_name); bd->client.icccm.icon_name = NULL; if (bd->client.icccm.machine) eina_stringshare_del(bd->client.icccm.machine); bd->client.icccm.machine = NULL; if (bd->client.icccm.window_role) eina_stringshare_del(bd->client.icccm.window_role); bd->client.icccm.window_role = NULL; if ((bd->client.icccm.command.argc > 0) && (bd->client.icccm.command.argv)) { int i; for (i = 0; i < bd->client.icccm.command.argc; i++) free(bd->client.icccm.command.argv[i]); free(bd->client.icccm.command.argv); bd->client.icccm.command.argv = NULL; } if (bd->client.netwm.name) eina_stringshare_del(bd->client.netwm.name); bd->client.netwm.name = NULL; if (bd->client.netwm.icon_name) eina_stringshare_del(bd->client.netwm.icon_name); bd->client.netwm.icon_name = NULL; if (bd->shape) e_object_del(E_OBJECT(bd->shape)); bd->shape = NULL; if (bd->internal_icon) eina_stringshare_del(bd->internal_icon); bd->internal_icon = NULL; if (bd->internal_icon_key) eina_stringshare_del(bd->internal_icon_key); bd->internal_icon_key = NULL; if (bd->icon_object) evas_object_del(bd->icon_object); bd->icon_object = NULL; evas_object_del(bd->bg_object); bd->bg_object = NULL; e_focus_setdown(bd); e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win); eina_hash_del(borders_hash, e_util_winid_str_get(bd->client.win), bd); eina_hash_del(borders_hash, e_util_winid_str_get(bd->win), bd); ecore_x_window_free(bd->win); bd->win = 0; borders = eina_list_remove(borders, bd); focus_stack = eina_list_remove(focus_stack, bd); raise_stack = eina_list_remove(raise_stack, bd); e_container_border_remove(bd); free(bd); } /* static int _e_border_del_dangling_ref_check(void *data) { E_Border *bd; bd = data; printf("---\n"); printf("EEK EEK border still around 1 second after being deleted!\n"); printf("%p, %i, \"%s\" [\"%s\" \"%s\"]\n", bd, e_object_ref_get(E_OBJECT(bd)), bd->client.icccm.title, bd->client.icccm.name, bd->client.icccm.class); // e_object_breadcrumb_debug(E_OBJECT(bd)); printf("---\n"); return 1; } */ static void _e_border_shadow(E_Border *bd) { if (!bd->bg_object) return; if (e_util_border_shadow_state_get(bd)) edje_object_signal_emit(bd->bg_object, "e,state,shadow,on", "e"); else edje_object_signal_emit(bd->bg_object, "e,state,shadow,off", "e"); } static void _e_border_del(E_Border *bd) { E_Event_Border_Remove *ev; E_Border *child; if (bd == focused) { focused = NULL; } if (bd == focusing) focusing = NULL; focus_next = eina_list_remove(focus_next, bd); bd->changed = 0; if (bd->exe_inst) { if (bd->exe_inst->phony) e_exec_phony_del(bd->exe_inst); else bd->exe_inst->bd = NULL; bd->exe_inst = NULL; } if (bd->fullscreen) bd->desk->fullscreen_borders--; if (bd->cur_mouse_action) { if (bd->cur_mouse_action->func.end) bd->cur_mouse_action->func.end(E_OBJECT(bd), ""); } if (action_border == bd) _e_border_action_finish(); e_pointer_type_pop(e_comp_get(bd)->pointer, bd, NULL); if (warp_timer_border == bd) { if (warp_timer) ecore_timer_del(warp_timer); warp_timer = NULL; warp_timer_border = NULL; e_border_focus_lock_set(EINA_FALSE); } if ((drag_border) && (drag_border->data == bd)) { e_object_del(E_OBJECT(drag_border)); drag_border = NULL; } if (bd->border_menu) e_menu_deactivate(bd->border_menu); if (bd->border_locks_dialog) { e_object_del(E_OBJECT(bd->border_locks_dialog)); bd->border_locks_dialog = NULL; } if (bd->border_remember_dialog) { e_object_del(E_OBJECT(bd->border_remember_dialog)); bd->border_remember_dialog = NULL; } if (bd->border_border_dialog) { e_object_del(E_OBJECT(bd->border_border_dialog)); bd->border_border_dialog = NULL; } if (bd->border_prop_dialog) { e_object_del(E_OBJECT(bd->border_prop_dialog)); bd->border_prop_dialog = NULL; } e_int_border_menu_del(bd); if (bd->raise_timer) { ecore_timer_del(bd->raise_timer); bd->raise_timer = NULL; } if (!bd->already_unparented) { ecore_x_window_reparent(bd->client.win, bd->zone->container->manager->root, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t); ecore_x_window_save_set_del(bd->client.win); // bd->client.win = 0; } bd->already_unparented = 1; if ((!bd->new_client) && (!stopping)) { ev = E_NEW(E_Event_Border_Remove, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_remove_event"); ecore_event_add(E_EVENT_BORDER_REMOVE, ev, _e_border_event_border_remove_free, NULL); } if (bd->parent) { bd->parent->transients = eina_list_remove(bd->parent->transients, bd); if (bd->parent->modal == bd) { if (bd->parent->client.lock_win) { eina_hash_del_by_key(borders_hash, e_util_winid_str_get(bd->parent->client.lock_win)); ecore_x_window_hide(bd->parent->client.lock_win); ecore_x_window_free(bd->parent->client.lock_win); bd->parent->client.lock_win = 0; } bd->parent->lock_close = 0; bd->parent->modal = NULL; } bd->parent = NULL; } EINA_LIST_FREE(bd->transients, child) { child->parent = NULL; } if (bd->leader) { bd->leader->group = eina_list_remove(bd->leader->group, bd); if (bd->leader->modal == bd) bd->leader->modal = NULL; bd->leader = NULL; } EINA_LIST_FREE(bd->group, child) { child->leader = NULL; } } #ifdef PRINT_LOTS_OF_DEBUG static void _e_border_print(E_Border *bd, const char *func) { if (!bd) return; DBG("*Window Info*" "\tPointer: %p\n" "\tName: %s\n" "\tTitle: %s\n" "\tBorderless: %s\n", bd, bd->client.icccm.name, bd->client.icccm.title, bd->borderless ? "TRUE" : "FALSE"); } #endif static Eina_Bool _e_border_cb_window_show_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Show_Request *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; if (bd->iconic) { if (!bd->lock_client_iconify) e_border_uniconify(bd); } else { /* FIXME: make border "urgent" for a bit - it wants attention */ /* e_border_show(bd); */ if (!bd->lock_client_stacking) e_border_raise(bd); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_destroy(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Destroy *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; e_border_hide(bd, 0); e_object_del(E_OBJECT(bd)); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_hide(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd = NULL; Ecore_X_Event_Window_Hide *e; e = ev; // printf("HIDE: %x, event %x send: %i\n", e->win, e->event_win, e->send_event); // not interested in hide events from windows other than the window in question if (e->win != e->event_win) { #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; if (!e->send_event) return ECORE_CALLBACK_PASS_ON; else { if (!((bd->zone) && (bd->zone->container->manager->root == e->event_win))) return ECORE_CALLBACK_PASS_ON; } #else return ECORE_CALLBACK_PASS_ON; #endif } if (!bd) bd = e_border_find_by_client_window(e->win); // printf(" bd = %p\n", bd); if (!bd) return ECORE_CALLBACK_PASS_ON; // printf(" bd->ignore_first_unmap = %i\n", bd->ignore_first_unmap); if (bd->ignore_first_unmap > 0) { bd->ignore_first_unmap--; return ECORE_CALLBACK_PASS_ON; } /* Don't delete hidden or iconified windows */ if ((bd->iconic) || (bd->await_hide_event > 0)) { // printf(" Don't delete hidden or iconified windows\n"); // printf(" bd->iconic = %i, bd->visible = %i, bd->new_client = %i, bd->await_hide_event = %i\n", // bd->iconic, bd->visible, bd->new_client, bd->await_hide_event); if (bd->await_hide_event > 0) { bd->await_hide_event--; } else { // printf(" hide really\n"); /* Only hide the border if it is visible */ if (bd->visible) e_border_hide(bd, 1); } } else { // printf(" hide2\n"); e_border_hide(bd, 0); e_object_del(E_OBJECT(bd)); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_reparent(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { #if 0 E_Border *bd; Ecore_X_Event_Window_Reparent *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return 1; if (e->parent == bd->win) return 1; if (ecore_x_window_parent_get(e->win) == bd->win) { return 1; } e_border_hide(bd, 0); e_object_del(E_OBJECT(bd)); #endif return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_configure_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Configure_Request *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) { if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON; if (!e_util_container_window_find(e->win)) ecore_x_window_configure(e->win, e->value_mask, e->x, e->y, e->w, e->h, e->border, e->abovewin, e->detail); return ECORE_CALLBACK_PASS_ON; } if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) || (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y)) { int x, y; x = bd->x; y = bd->y; if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) x = e->x; if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y) y = e->y; if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) || (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)) { int w, h; h = bd->h; w = bd->w; if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) w = e->w + e_border_inset_width_get(bd); if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H) h = e->h + e_border_inset_height_get(bd); if ((!bd->lock_client_location) && (!bd->lock_client_size)) { if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE) { bd->saved.x = x - bd->zone->x; bd->saved.y = y - bd->zone->y; bd->saved.w = w; bd->saved.h = h; } else e_border_move_resize(bd, x, y, w, h); } else if (!bd->lock_client_location) { if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE) { bd->saved.x = x - bd->zone->x; bd->saved.y = y - bd->zone->y; } else e_border_move(bd, x, y); } else if (!bd->lock_client_size) { if ((bd->shaded) || (bd->shading)) { int pw, ph; pw = bd->client.w; ph = bd->client.h; if ((bd->shade.dir == E_DIRECTION_UP) || (bd->shade.dir == E_DIRECTION_DOWN)) { e_border_resize(bd, w, bd->h); bd->client.h = ph; } else { e_border_resize(bd, bd->w, h); bd->client.w = pw; } } else { if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE) { bd->saved.w = w; bd->saved.h = h; } else e_border_resize(bd, w, h); } } } else { if (!bd->lock_client_location) { if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE) { bd->saved.x = x - bd->zone->x; bd->saved.y = y - bd->zone->y; } else { if ((e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY) && bd->zone && (!E_INSIDE(x, y, 0, 0, bd->zone->w - 5, bd->zone->h - 5)) && (!E_INSIDE(x, y, 0 - bd->w + 5, 0 - bd->h + 5, bd->zone->w - 5, bd->zone->h - 5)) ) _e_border_move_lost_window_to_center(bd); else e_border_move(bd, x, y); } } } } else if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) || (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)) { int w, h; h = bd->h; w = bd->w; if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) w = e->w + e_border_inset_width_get(bd); if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H) h = e->h + e_border_inset_height_get(bd); if (!bd->lock_client_size) { if ((bd->shaded) || (bd->shading)) { int pw, ph; pw = bd->client.w; ph = bd->client.h; if ((bd->shade.dir == E_DIRECTION_UP) || (bd->shade.dir == E_DIRECTION_DOWN)) { e_border_resize(bd, w, bd->h); bd->client.h = ph; } else { e_border_resize(bd, bd->w, h); bd->client.w = pw; } } else { if ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_NONE) { int zx, zy, zw, zh; int rx = bd->x; int ry = bd->y; zx = zy = zw = zh = 0; /* * This code does resize and move a window on a * X configure request into an useful geometry. * This is really useful for size jumping file dialogs. */ if (bd->zone) { e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh); if (e_config->geometry_auto_resize_limit == 1) { if (w > zw) w = zw; if (h > zh) h = zh; } } e_border_resize(bd, w, h); if (e_config->geometry_auto_move == 1) { /* z{x,y,w,h} are only set here; FIXME! */ if (bd->zone) { // move window horizontal if resize to not useful geometry if (bd->x + bd->w > zx + zw) rx = zx + zw - bd->w; else if (bd->x < zx) rx = zx; // move window vertical if resize to not useful geometry if (bd->y + bd->h > zy + zh) ry = zy + zh - bd->h; else if (bd->y < zy) ry = zy; } e_border_move(bd, rx, ry); } } } } } if (!bd->lock_client_stacking) { if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE) && (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING)) { E_Border *obd; if (e->detail == ECORE_X_WINDOW_STACK_ABOVE) { obd = e_border_find_by_client_window(e->abovewin); if (obd) { e_border_stack_above(bd, obd); } else { ecore_x_window_configure(bd->win, ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, 0, 0, 0, 0, 0, e->abovewin, ECORE_X_WINDOW_STACK_ABOVE); /* FIXME: need to rebuiuld border list from current stacking */ } } else if (e->detail == ECORE_X_WINDOW_STACK_BELOW) { obd = e_border_find_by_client_window(e->abovewin); if (obd) { e_border_stack_below(bd, obd); } else { ecore_x_window_configure(bd->win, ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING | ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE, 0, 0, 0, 0, 0, e->abovewin, ECORE_X_WINDOW_STACK_BELOW); /* FIXME: need to rebuiuld border list from current stacking */ } } else if (e->detail == ECORE_X_WINDOW_STACK_TOP_IF) { /* FIXME: do */ } else if (e->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF) { /* FIXME: do */ } else if (e->detail == ECORE_X_WINDOW_STACK_OPPOSITE) { /* FIXME: do */ } } else if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE) { if (e->detail == ECORE_X_WINDOW_STACK_ABOVE) { e_border_raise(bd); } else if (e->detail == ECORE_X_WINDOW_STACK_BELOW) { e_border_lower(bd); } else if (e->detail == ECORE_X_WINDOW_STACK_TOP_IF) { /* FIXME: do */ } else if (e->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF) { /* FIXME: do */ } else if (e->detail == ECORE_X_WINDOW_STACK_OPPOSITE) { /* FIXME: do */ } } } /* FIXME: need to send synthetic stacking event too as well as move/resize */ _e_border_client_move_resize_send(bd); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_resize_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Resize_Request *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) { if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON; ecore_x_window_resize(e->win, e->w, e->h); return ECORE_CALLBACK_PASS_ON; } { int w, h; w = e->w + e_border_inset_width_get(bd); h = e->h + e_border_inset_height_get(bd); if ((bd->shaded) || (bd->shading)) { int pw, ph; pw = bd->client.w; ph = bd->client.h; if ((bd->shade.dir == E_DIRECTION_UP) || (bd->shade.dir == E_DIRECTION_DOWN)) { e_border_resize(bd, w, bd->h); bd->client.h = ph; } else { e_border_resize(bd, bd->w, h); bd->client.w = pw; } } else e_border_resize(bd, w, h); } _e_border_client_move_resize_send(bd); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_gravity(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { // E_Border *bd; // Ecore_X_Event_Window_Gravity *e; // e = ev; // bd = e_border_find_by_client_window(e->win); // if (!bd) return 1; return 1; } static Eina_Bool _e_border_cb_window_stack_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Stack_Request *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) { if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON; if (!e_util_container_window_find(e->win)) { if (e->detail == ECORE_X_WINDOW_STACK_ABOVE) ecore_x_window_raise(e->win); else if (e->detail == ECORE_X_WINDOW_STACK_BELOW) ecore_x_window_lower(e->win); } return ECORE_CALLBACK_PASS_ON; } if (e->detail == ECORE_X_WINDOW_STACK_ABOVE) e_border_raise(bd); else if (e->detail == ECORE_X_WINDOW_STACK_BELOW) e_border_lower(bd); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_property(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Property *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; if (e->atom == ECORE_X_ATOM_WM_NAME) { if ((!bd->client.netwm.name) && (!bd->client.netwm.fetch.name)) { bd->client.icccm.fetch.title = 1; BD_CHANGED(bd); } } else if (e->atom == ECORE_X_ATOM_NET_WM_NAME) { bd->client.netwm.fetch.name = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_CLASS) { bd->client.icccm.fetch.name_class = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_ICON_NAME) { if ((!bd->client.netwm.icon_name) && (!bd->client.netwm.fetch.icon_name)) { bd->client.icccm.fetch.icon_name = 1; BD_CHANGED(bd); } } else if (e->atom == ECORE_X_ATOM_NET_WM_ICON_NAME) { bd->client.netwm.fetch.icon_name = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_CLIENT_MACHINE) { bd->client.icccm.fetch.machine = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_PROTOCOLS) { bd->client.icccm.fetch.protocol = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_HINTS) { bd->client.icccm.fetch.hints = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_NORMAL_HINTS) { bd->client.icccm.fetch.size_pos_hints = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_MOTIF_WM_HINTS) { /* if ((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_UNKNOWN) && (!bd->client.netwm.fetch.type)) { */ bd->client.mwm.fetch.hints = 1; BD_CHANGED(bd); /* } */ } else if (e->atom == ECORE_X_ATOM_WM_TRANSIENT_FOR) { bd->client.icccm.fetch.transient_for = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_CLIENT_LEADER) { bd->client.icccm.fetch.client_leader = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_WM_WINDOW_ROLE) { bd->client.icccm.fetch.window_role = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_NET_WM_ICON) { bd->client.netwm.fetch.icon = 1; BD_CHANGED(bd); } else if (e->atom == ATM__QTOPIA_SOFT_MENU) { bd->client.qtopia.fetch.soft_menu = 1; BD_CHANGED(bd); } else if (e->atom == ATM__QTOPIA_SOFT_MENUS) { bd->client.qtopia.fetch.soft_menus = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE) { bd->client.vkbd.fetch.state = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD) { bd->client.vkbd.fetch.vkbd = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_CONFORMANT) { bd->client.illume.conformant.fetch.conformant = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE) { bd->client.illume.quickpanel.fetch.state = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL) { bd->client.illume.quickpanel.fetch.quickpanel = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR) { bd->client.illume.quickpanel.fetch.priority.major = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR) { bd->client.illume.quickpanel.fetch.priority.minor = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE) { bd->client.illume.quickpanel.fetch.zone = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED) { bd->client.illume.drag.fetch.locked = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_DRAG) { bd->client.illume.drag.fetch.drag = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE) { bd->client.illume.win_state.fetch.state = 1; BD_CHANGED(bd); } /* else if (e->atom == ECORE_X_ATOM_NET_WM_USER_TIME) { bd->client.netwm.fetch.user_time = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_NET_WM_STRUT) { bd->client.netwm.fetch.strut = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL) { bd->client.netwm.fetch.strut = 1; BD_CHANGED(bd); } */ else if (e->atom == ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER) { //printf("ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER\n"); } else if (e->atom == ECORE_X_ATOM_E_VIDEO_POSITION) { bd->client.e.fetch.video_position = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_VIDEO_PARENT) { bd->client.e.fetch.video_parent = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_NET_WM_STATE) { bd->client.netwm.fetch.state = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY) { if (bd->client.netwm.opacity_changed) bd->client.netwm.opacity_changed = 0; else { bd->client.netwm.fetch.opacity = 1; BD_CHANGED(bd); } } #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) else if (e->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED) { bd->client.e.fetch.profile = 1; BD_CHANGED(bd); } else if (e->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_AVAILABLE_LIST) { bd->client.e.fetch.profile = 1; BD_CHANGED(bd); } #endif return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_colormap(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Colormap *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Shape *e; e = ev; bd = e_border_find_by_client_window(e->win); if (e->type == ECORE_X_SHAPE_INPUT) { if (bd) { bd->need_shape_merge = 1; // YYY bd->shaped_input = 1; bd->changes.shape_input = 1; BD_CHANGED(bd); } return ECORE_CALLBACK_PASS_ON; } if (bd) { bd->changes.shape = 1; BD_CHANGED(bd); return ECORE_CALLBACK_PASS_ON; } bd = e_border_find_by_window(e->win); if (bd) { bd->need_shape_export = 1; BD_CHANGED(bd); return ECORE_CALLBACK_PASS_ON; } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_focus_in(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Focus_In *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; /* block refocus attempts on iconic windows * these result from iconifying a window during a grab */ if (bd->iconic) return ECORE_CALLBACK_RENEW; #ifdef INOUTDEBUG_FOCUS { time_t t; char *ct; const char *modes[] = { "MODE_NORMAL", "MODE_WHILE_GRABBED", "MODE_GRAB", "MODE_UNGRAB" }; const char *details[] = { "DETAIL_ANCESTOR", "DETAIL_VIRTUAL", "DETAIL_INFERIOR", "DETAIL_NON_LINEAR", "DETAIL_NON_LINEAR_VIRTUAL", "DETAIL_POINTER", "DETAIL_POINTER_ROOT", "DETAIL_DETAIL_NONE" }; t = time(NULL); ct = ctime(&t); ct[strlen(ct) - 1] = 0; DBG("FF ->IN %i 0x%x %s md=%s dt=%s\n", e->time, e->win, ct, modes[e->mode], details[e->detail]); DBG("%s cb focus in %d %d\n", e_border_name_get(bd), bd->client.icccm.accepts_focus, bd->client.icccm.take_focus); } #endif _e_border_pri_raise(bd); if (e->mode == ECORE_X_EVENT_MODE_GRAB) { if (e->detail == ECORE_X_EVENT_DETAIL_POINTER) return ECORE_CALLBACK_PASS_ON; } else if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) { /* this seems to break winlist... if (e->detail == ECORE_X_EVENT_DETAIL_POINTER) */ return ECORE_CALLBACK_PASS_ON; } /* ignore focus in from !take_focus windows, we just gave it em */ /* if (!bd->client.icccm.take_focus) * return ECORE_CALLBACK_PASS_ON; */ /* should be equal, maybe some clients dont reply with the proper timestamp ? */ if (e->time >= focus_time) e_border_focus_set(bd, 1, 0); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_focus_out(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Focus_Out *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; #ifdef INOUTDEBUG_FOCUS { time_t t; char *ct; const char *modes[] = { "MODE_NORMAL", "MODE_WHILE_GRABBED", "MODE_GRAB", "MODE_UNGRAB" }; const char *details[] = { "DETAIL_ANCESTOR", "DETAIL_VIRTUAL", "DETAIL_INFERIOR", "DETAIL_NON_LINEAR", "DETAIL_NON_LINEAR_VIRTUAL", "DETAIL_POINTER", "DETAIL_POINTER_ROOT", "DETAIL_DETAIL_NONE" }; t = time(NULL); ct = ctime(&t); ct[strlen(ct) - 1] = 0; DBG("FF <-OUT %i 0x%x %s md=%s dt=%s", e->time, e->win, ct, modes[e->mode], details[e->detail]); DBG("%s cb focus out %d %d", e_border_name_get(bd), bd->client.icccm.accepts_focus, bd->client.icccm.take_focus); } #endif _e_border_pri_norm(bd); if (e->mode == ECORE_X_EVENT_MODE_NORMAL) { if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL) return ECORE_CALLBACK_PASS_ON; } else if (e->mode == ECORE_X_EVENT_MODE_GRAB) { if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_VIRTUAL) return ECORE_CALLBACK_PASS_ON; } else if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) { /* for firefox/thunderbird (xul) menu walking */ /* NB: why did i disable this before? */ if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_POINTER) return ECORE_CALLBACK_PASS_ON; } else if (e->mode == ECORE_X_EVENT_MODE_WHILE_GRABBED) { if (e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR) return ECORE_CALLBACK_PASS_ON; else if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR) return ECORE_CALLBACK_PASS_ON; } e_border_focus_set(bd, 0, 0); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_client_message(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Client_Message *e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; if (e->message_type == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY) { bd->client.netwm.fetch.opacity = 1; BD_CHANGED(bd); } #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) else if (e->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE) { if (bd->client.e.state.profile.use) { char *profile; profile = ecore_x_atom_name_get(e->data.l[1]); ecore_x_e_window_profile_change_request_send(bd->client.win, profile); bd->client.e.state.profile.wait_for_done = 1; free(profile); } } else if (e->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE_DONE) { if ((bd->client.e.state.profile.use) && (bd->client.e.state.profile.wait_for_done)) { E_Container *con = bd->zone->container; E_Desk *desk = NULL; char *profile; profile = ecore_x_atom_name_get(e->data.l[1]); if (profile) eina_stringshare_replace(&bd->client.e.state.profile.name, profile); bd->client.e.state.profile.wait_for_done = 0; desk = e_container_desk_window_profile_get(con, profile); if ((desk) && (bd->desk != desk)) e_border_desk_set(bd, desk); free(profile); } } #endif return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_state_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_State_Request *e; int i; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; for (i = 0; i < 2; i++) e_hints_window_state_update(bd, e->state[i], e->action); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_window_move_resize_request(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Window_Move_Resize_Request *e; e = ev; bd = e_border_find_by_client_window(e->win); if (!bd) return ECORE_CALLBACK_PASS_ON; if ((bd->shaded) || (bd->shading) || (bd->fullscreen) || (bd->moving) || (bd->resize_mode != E_POINTER_RESIZE_NONE)) return ECORE_CALLBACK_PASS_ON; if ((e->button >= 1) && (e->button <= 3)) { bd->mouse.last_down[e->button - 1].mx = e->x; bd->mouse.last_down[e->button - 1].my = e->y; bd->mouse.last_down[e->button - 1].x = bd->x; bd->mouse.last_down[e->button - 1].y = bd->y; bd->mouse.last_down[e->button - 1].w = bd->w; bd->mouse.last_down[e->button - 1].h = bd->h; } else { bd->moveinfo.down.x = bd->x; bd->moveinfo.down.y = bd->y; bd->moveinfo.down.w = bd->w; bd->moveinfo.down.h = bd->h; } bd->mouse.current.mx = e->x; bd->mouse.current.my = e->y; bd->moveinfo.down.button = e->button; bd->moveinfo.down.mx = e->x; bd->moveinfo.down.my = e->y; grabbed = 1; if (!bd->lock_user_stacking) e_border_raise(bd); if (e->direction == E_POINTER_MOVE) { bd->cur_mouse_action = e_action_find("window_move"); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; if (bd->cur_mouse_action) { e_object_ref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action->func.go(E_OBJECT(bd), NULL); } } return ECORE_CALLBACK_PASS_ON; } if (!_e_border_resize_begin(bd)) return ECORE_CALLBACK_PASS_ON; switch (e->direction) { case E_POINTER_RESIZE_TL: bd->resize_mode = E_POINTER_RESIZE_TL; GRAV_SET(bd, ECORE_X_GRAVITY_SE); break; case E_POINTER_RESIZE_T: bd->resize_mode = E_POINTER_RESIZE_T; GRAV_SET(bd, ECORE_X_GRAVITY_S); break; case E_POINTER_RESIZE_TR: bd->resize_mode = E_POINTER_RESIZE_TR; GRAV_SET(bd, ECORE_X_GRAVITY_SW); break; case E_POINTER_RESIZE_R: bd->resize_mode = E_POINTER_RESIZE_R; GRAV_SET(bd, ECORE_X_GRAVITY_W); break; case E_POINTER_RESIZE_BR: bd->resize_mode = E_POINTER_RESIZE_BR; GRAV_SET(bd, ECORE_X_GRAVITY_NW); break; case E_POINTER_RESIZE_B: bd->resize_mode = E_POINTER_RESIZE_B; GRAV_SET(bd, ECORE_X_GRAVITY_N); break; case E_POINTER_RESIZE_BL: bd->resize_mode = E_POINTER_RESIZE_BL; GRAV_SET(bd, ECORE_X_GRAVITY_NE); break; case E_POINTER_RESIZE_L: bd->resize_mode = E_POINTER_RESIZE_L; GRAV_SET(bd, ECORE_X_GRAVITY_E); break; default: return ECORE_CALLBACK_PASS_ON; } bd->cur_mouse_action = e_action_find("window_resize"); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; } if (bd->cur_mouse_action) e_object_ref(E_OBJECT(bd->cur_mouse_action)); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_desktop_change(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Desktop_Change *e; e = ev; bd = e_border_find_by_client_window(e->win); if (bd) { if (e->desk == 0xffffffff) e_border_stick(bd); else if ((int)e->desk < (bd->zone->desk_x_count * bd->zone->desk_y_count)) { E_Desk *desk; desk = e_desk_at_pos_get(bd->zone, e->desk); if (desk) e_border_desk_set(bd, desk); } } else { ecore_x_netwm_desktop_set(e->win, e->desk); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_sync_alarm(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Border *bd; Ecore_X_Event_Sync_Alarm *e; unsigned int serial; e = ev; bd = e_border_find_by_alarm(e->alarm); if (!bd) return ECORE_CALLBACK_PASS_ON; if (bd->client.netwm.sync.wait) bd->client.netwm.sync.wait--; if (ecore_x_sync_counter_query(bd->client.netwm.sync.counter, &serial)) { E_Border_Pending_Move_Resize *pnd = NULL; /* skip pending for which we didn't get a reply */ while (bd->pending_move_resize) { pnd = bd->pending_move_resize->data; bd->pending_move_resize = eina_list_remove(bd->pending_move_resize, pnd); if (serial == pnd->serial) break; E_FREE(pnd); } if (pnd) { bd->x = pnd->x; bd->y = pnd->y; bd->w = pnd->w; bd->h = pnd->h; bd->client.w = bd->w - (e_border_inset_width_get(bd)); bd->client.h = bd->h - (e_border_inset_height_get(bd)); E_FREE(pnd); } } bd->changes.size = 1; bd->changes.pos = 1; _e_border_eval(bd); ecore_x_pointer_xy_get(e_manager_current_get()->root, &bd->mouse.current.mx, &bd->mouse.current.my); bd->client.netwm.sync.send_time = ecore_loop_time_get(); _e_border_resize_handle(bd); return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_efreet_cache_update(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { Eina_List *l; E_Border *bd; /* mark all borders for desktop/icon updates */ EINA_LIST_FOREACH(borders, l, bd) { if (e_object_is_del(E_OBJECT(bd))) continue; if (bd->desktop) { efreet_desktop_free(bd->desktop); bd->desktop = NULL; } bd->changes.icon = 1; BD_CHANGED(bd); } /* e_init_status_set(_("Desktop files scan done")); e_init_done(); */ return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_config_icon_theme(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { Eina_List *l; E_Border *bd; /* mark all borders for desktop/icon updates */ EINA_LIST_FOREACH(borders, l, bd) { bd->changes.icon = 1; BD_CHANGED(bd); } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_config_mode(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { Eina_List *l; E_Border *bd; /* move fullscreen borders above everything */ if (e_config->mode.presentation) { EINA_LIST_FOREACH(borders, l, bd) { if ((bd->fullscreen) || (bd->need_fullscreen)) { bd->fullscreen = 0; e_border_layer_set(bd, E_LAYER_TOP); bd->fullscreen = 1; } } } else if (!e_config->allow_above_fullscreen) { EINA_LIST_FOREACH(borders, l, bd) { if ((bd->fullscreen) || (bd->need_fullscreen)) { bd->fullscreen = 0; e_border_layer_set(bd, E_LAYER_FULLSCREEN); bd->fullscreen = 1; } } } return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _e_border_cb_pointer_warp(void *data __UNUSED__, int ev_type __UNUSED__, void *ev) { E_Event_Pointer_Warp *e; e = ev; if (!bdmove) return ECORE_CALLBACK_PASS_ON; e_border_move(bdmove, bdmove->x + (e->curr.x - e->prev.x), bdmove->y + (e->curr.y - e->prev.y)); return ECORE_CALLBACK_PASS_ON; } static void _e_border_cb_signal_bind(void *data, Evas_Object *obj __UNUSED__, const char *emission, const char *source) { E_Border *bd; bd = data; if (e_dnd_active()) return; e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd), emission, source); } static void _e_border_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_In *ev = event_info; E_Border *bd = data; if (grabbed) return; if ((bd == focusing) || (bd == focused)) return; if (focus_locked && (bd != warp_timer_border)) return; if (e_object_is_del(E_OBJECT(bd))) return; if (bd->desk && bd->desk->animate_count) return; bd->mouse.current.mx = ev->output.x; bd->mouse.current.my = ev->output.y; if (!bd->iconic) e_focus_event_mouse_in(bd); } static Eina_Bool _e_border_cb_mouse_x_in(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Mouse_In *ev) { E_Border *bd; if (grabbed) return ECORE_CALLBACK_RENEW; bd = e_border_find_by_window(ev->event_win); if (!bd) return ECORE_CALLBACK_RENEW; if (bd->input_object) return ECORE_CALLBACK_RENEW; if ((bd == focusing) || (bd == focused)) return ECORE_CALLBACK_RENEW; if (focus_locked && (bd != warp_timer_border)) return ECORE_CALLBACK_RENEW; if (e_object_is_del(E_OBJECT(bd))) return ECORE_CALLBACK_RENEW; if (bd->desk && bd->desk->animate_count) return ECORE_CALLBACK_RENEW; bd->mouse.current.mx = ev->root.x; bd->mouse.current.my = ev->root.y; if (!bd->iconic) e_focus_event_mouse_in(bd); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Out *ev = event_info; E_Border *bd = data; if (grabbed) return; if (bd->fullscreen) return; if ((bd != focused) && (bd == focusing)) return; if (e_object_is_del(E_OBJECT(bd))) return; if (bd->desk && bd->desk->animate_count) return; if (!bd->input_object) if (E_INSIDE(ev->output.x, ev->output.y, bd->x, bd->y, bd->w, bd->h)) return; bd->mouse.current.mx = ev->output.x; bd->mouse.current.my = ev->output.y; if (!bd->iconic) e_focus_event_mouse_out(bd); } static Eina_Bool _e_border_cb_mouse_x_out(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Mouse_Out *ev) { E_Border *bd; if (grabbed) return ECORE_CALLBACK_RENEW; bd = e_border_find_by_window(ev->event_win); if (!bd) return ECORE_CALLBACK_RENEW; if (bd->input_object) return ECORE_CALLBACK_RENEW; if (bd->fullscreen) return ECORE_CALLBACK_RENEW; if ((bd != focused) && (bd == focusing)) return ECORE_CALLBACK_RENEW; if (e_object_is_del(E_OBJECT(bd))) return ECORE_CALLBACK_RENEW; if (bd->desk && bd->desk->animate_count) return ECORE_CALLBACK_RENEW; if (E_INSIDE(ev->root.x, ev->root.y, bd->x, bd->y, bd->w, bd->h)) return ECORE_CALLBACK_RENEW; if ((ev->mode == ECORE_X_EVENT_MODE_UNGRAB) && (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)) return ECORE_CALLBACK_PASS_ON; if (ev->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON; if ((ev->mode == ECORE_X_EVENT_MODE_NORMAL) && (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)) return ECORE_CALLBACK_PASS_ON; bd->mouse.current.mx = ev->root.x; bd->mouse.current.my = ev->root.y; if (!bd->iconic) e_focus_event_mouse_out(bd); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_wheel_helper(E_Border *bd, Evas_Point *output, E_Binding_Event_Wheel *ev) { bd->mouse.current.mx = output->x; bd->mouse.current.my = output->y; if (!bd->cur_mouse_action) { e_bindings_wheel_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd), ev); } } static Eina_Bool _e_border_cb_mouse_x_wheel(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev) { E_Border *bd; E_Binding_Event_Wheel ev2; if (action_input_win) bd = action_border; else { bd = e_border_find_by_client_window(ev->window); if (!bd) bd = e_border_find_by_window(ev->window); if (!bd) return ECORE_CALLBACK_RENEW; /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */ if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window)) return ECORE_CALLBACK_RENEW; } e_bindings_ecore_event_mouse_wheel_convert(ev, &ev2); _e_border_cb_mouse_wheel_helper(bd, (Evas_Point*)&ev->root, &ev2); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Wheel *ev = event_info; E_Border *bd = data; E_Binding_Event_Wheel ev2; if (action_border) return; // already existing border doing something e_bindings_evas_event_mouse_wheel_convert(ev, &ev2); _e_border_cb_mouse_wheel_helper(bd, &ev->output, &ev2); } static void _e_border_cb_mouse_down_helper(E_Border *bd, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev) { if ((button >= 1) && (button <= 3)) { bd->mouse.last_down[button - 1].mx = output->x; bd->mouse.last_down[button - 1].my = output->y; bd->mouse.last_down[button - 1].x = bd->x; bd->mouse.last_down[button - 1].y = bd->y; bd->mouse.last_down[button - 1].w = bd->w; bd->mouse.last_down[button - 1].h = bd->h; } else { bd->moveinfo.down.x = bd->x; bd->moveinfo.down.y = bd->y; bd->moveinfo.down.w = bd->w; bd->moveinfo.down.h = bd->h; } bd->mouse.current.mx = output->x; bd->mouse.current.my = output->y; if (!bd->cur_mouse_action) { bd->cur_mouse_action = e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd), ev); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; if (bd->cur_mouse_action) e_object_ref(E_OBJECT(bd->cur_mouse_action)); } } e_focus_event_mouse_down(bd); if ((button >= 1) && (button <= 3)) { bd->mouse.last_down[button - 1].mx = output->x; bd->mouse.last_down[button - 1].my = output->y; bd->mouse.last_down[button - 1].x = bd->x; bd->mouse.last_down[button - 1].y = bd->y; bd->mouse.last_down[button - 1].w = bd->w; bd->mouse.last_down[button - 1].h = bd->h; } else { bd->moveinfo.down.x = bd->x; bd->moveinfo.down.y = bd->y; bd->moveinfo.down.w = bd->w; bd->moveinfo.down.h = bd->h; } bd->mouse.current.mx = output->x; bd->mouse.current.my = output->y; /* if (bd->moving) { } else if (bd->resize_mode != E_POINTER_RESIZE_NONE) { } else */ } static Eina_Bool _e_border_cb_mouse_x_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) { E_Border *bd; E_Binding_Event_Mouse_Button ev2; if (action_input_win) bd = action_border; else { bd = e_border_find_by_client_window(ev->window); if (!bd) bd = e_border_find_by_window(ev->window); if (!bd) return ECORE_CALLBACK_RENEW; /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */ if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window)) return ECORE_CALLBACK_RENEW; } e_bindings_ecore_event_mouse_button_convert(ev, &ev2); _e_border_cb_mouse_down_helper(bd, ev->buttons, (Evas_Point*)&ev->root, &ev2); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; E_Border *bd = data; E_Binding_Event_Mouse_Button ev2; if (action_border) return; // already existing border doing something e_bindings_evas_event_mouse_button_convert(ev, &ev2); _e_border_cb_mouse_down_helper(bd, ev->button, &ev->output, &ev2); } static void _e_border_cb_mouse_up_helper(E_Border *bd, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev) { if ((button >= 1) && (button <= 3)) { bd->mouse.last_up[button - 1].mx = output->x; bd->mouse.last_up[button - 1].my = output->y; bd->mouse.last_up[button - 1].x = bd->x; bd->mouse.last_up[button - 1].y = bd->y; } bd->mouse.current.mx = output->x; bd->mouse.current.my = output->y; /* also we dont pass the same params that went in - then again that */ /* should be ok as we are just ending the action if it has an end */ if (bd->cur_mouse_action) { if (bd->cur_mouse_action->func.end_mouse) bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", ev); else if (bd->cur_mouse_action->func.end) bd->cur_mouse_action->func.end(E_OBJECT(bd), ""); e_object_unref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action = NULL; } else { if (!e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd), ev)) e_focus_event_mouse_up(bd); } if ((button >= 1) && (button <= 3)) { bd->mouse.last_up[button - 1].mx = output->x; bd->mouse.last_up[button - 1].my = output->y; bd->mouse.last_up[button - 1].x = bd->x; bd->mouse.last_up[button - 1].y = bd->y; } bd->drag.start = 0; } static Eina_Bool _e_border_cb_mouse_x_up(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) { E_Border *bd; E_Binding_Event_Mouse_Button ev2; if (action_input_win) bd = action_border; else { bd = e_border_find_by_client_window(ev->window); if (!bd) bd = e_border_find_by_window(ev->window); if (!bd) return ECORE_CALLBACK_RENEW; /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */ if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window)) return ECORE_CALLBACK_RENEW; } e_bindings_ecore_event_mouse_button_convert(ev, &ev2); _e_border_cb_mouse_up_helper(bd, ev->buttons, (Evas_Point*)&ev->root, &ev2); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev = event_info; E_Border *bd = data; E_Binding_Event_Mouse_Button ev2; if (action_border) return; // already existing border doing something e_bindings_evas_event_mouse_button_convert(ev, &ev2); _e_border_cb_mouse_up_helper(bd, ev->button, &ev->output, &ev2); } static void _e_border_stay_within_container(E_Border *bd, int x, int y, int *new_x, int *new_y) { int new_x_max, new_y_max; int zw, zh; Eina_Bool lw, lh; if (!bd->zone) { if (new_x) *new_x = x; if (new_y) *new_y = y; return; } _e_border_zones_layout_calc(bd, NULL, NULL, &zw, &zh); new_x_max = zw - bd->w; new_y_max = zh - bd->h; lw = bd->w > zw ? EINA_TRUE : EINA_FALSE; lh = bd->h > zh ? EINA_TRUE : EINA_FALSE; if (lw) { if (x <= new_x_max) *new_x = new_x_max; else if (x >= 0) *new_x = 0; } else { if (x >= new_x_max) *new_x = new_x_max; else if (x <= 0) *new_x = 0; } if (lh) { if (y <= new_y_max) *new_y = new_y_max; else if (y >= 0) *new_y = 0; } else { if (y >= new_y_max) *new_y = new_y_max; else if (y <= 0) *new_y = 0; } } static void _e_border_cb_mouse_move_helper(E_Border *bd, Evas_Point *output) { bd->mouse.current.mx = output->x; bd->mouse.current.my = output->y; if (bd->moving) { int x, y, new_x, new_y; int new_w, new_h; Eina_List *skiplist = NULL; #if 0 // FIXME: remove? sync what for when only moving? if ((ecore_loop_time_get() - bd->client.netwm.sync.time) > 0.5) bd->client.netwm.sync.wait = 0; if ((bd->client.netwm.sync.request) && (bd->client.netwm.sync.alarm) && (bd->client.netwm.sync.wait > 1)) return; #endif if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) { x = bd->mouse.last_down[bd->moveinfo.down.button - 1].x + (bd->mouse.current.mx - bd->moveinfo.down.mx); y = bd->mouse.last_down[bd->moveinfo.down.button - 1].y + (bd->mouse.current.my - bd->moveinfo.down.my); } else { x = bd->moveinfo.down.x + (bd->mouse.current.mx - bd->moveinfo.down.mx); y = bd->moveinfo.down.y + (bd->mouse.current.my - bd->moveinfo.down.my); } new_x = x; new_y = y; skiplist = eina_list_append(skiplist, bd); e_resist_container_border_position(bd->zone->container, skiplist, bd->x, bd->y, bd->w, bd->h, x, y, bd->w, bd->h, &new_x, &new_y, &new_w, &new_h); eina_list_free(skiplist); if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN) _e_border_stay_within_container(bd, x, y, &new_x, &new_y); bd->shelf_fix.x = 0; bd->shelf_fix.y = 0; bd->shelf_fix.modified = 0; e_border_move(bd, new_x, new_y); e_zone_flip_coords_handle(bd->zone, output->x, output->y); } else if (bd->resize_mode != E_POINTER_RESIZE_NONE) { if ((bd->client.netwm.sync.request) && (bd->client.netwm.sync.alarm)) { if ((ecore_loop_time_get() - bd->client.netwm.sync.send_time) > 0.5) { E_Border_Pending_Move_Resize *pnd; if (bd->pending_move_resize) { bd->changes.pos = 1; bd->changes.size = 1; BD_CHANGED(bd); _e_border_client_move_resize_send(bd); } EINA_LIST_FREE(bd->pending_move_resize, pnd) E_FREE(pnd); bd->client.netwm.sync.wait = 0; } /* sync.wait is incremented when resize_handle sends * sync-request and decremented by sync-alarm cb. so * we resize here either on initial resize, timeout or * when no new resize-request was added by sync-alarm cb. */ if (!bd->client.netwm.sync.wait) _e_border_resize_handle(bd); } else _e_border_resize_handle(bd); } else if (bd->drag.start) { if ((bd->drag.x == -1) && (bd->drag.y == -1)) { bd->drag.x = output->x; bd->drag.y = output->y; } else { int dx, dy; dx = bd->drag.x - output->x; dy = bd->drag.y - output->y; if (((dx * dx) + (dy * dy)) > (e_config->drag_resist * e_config->drag_resist)) { /* start drag! */ if (bd->icon_object) { Evas_Object *o = NULL; Evas_Coord x, y, w, h; const char *drag_types[] = { "enlightenment/border" }; e_object_ref(E_OBJECT(bd)); evas_object_geometry_get(bd->icon_object, &x, &y, &w, &h); drag_border = e_drag_new(bd->zone->container, x, y, drag_types, 1, bd, -1, NULL, _e_border_cb_drag_finished); o = e_border_icon_add(bd, drag_border->evas); if (!o) { /* FIXME: fallback icon for drag */ o = evas_object_rectangle_add(drag_border->evas); evas_object_color_set(o, 255, 255, 255, 255); } e_drag_object_set(drag_border, o); e_drag_resize(drag_border, w, h); e_drag_start(drag_border, bd->drag.x, bd->drag.y); } bd->drag.start = 0; } } } } static Eina_Bool _e_border_cb_mouse_x_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) { if (!action_input_win) return ECORE_CALLBACK_RENEW; _e_border_cb_mouse_move_helper(action_border, (Evas_Point*)&ev->root); return ECORE_CALLBACK_RENEW; } static void _e_border_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Move *ev = event_info; E_Border *bd = data; if (action_border) return; // already existing border doing something _e_border_cb_mouse_move_helper(bd, &ev->cur.output); } static Eina_Bool _e_border_cb_grab_replay(void *data __UNUSED__, int type, void *event) { Ecore_Event_Mouse_Button *ev; if (type != ECORE_EVENT_MOUSE_BUTTON_DOWN) return ECORE_CALLBACK_DONE; ev = event; if ((e_config->pass_click_on) || (e_config->always_click_to_raise) // this works even if not on click-to-focus || (e_config->always_click_to_focus) // this works even if not on click-to-focus ) { E_Border *bd; bd = e_border_find_by_window(ev->event_window); if (bd) { if (bd->cur_mouse_action) return ECORE_CALLBACK_DONE; if (ev->event_window == bd->win) { E_Binding_Event_Mouse_Button ev2; e_bindings_ecore_event_mouse_button_convert(ev, &ev2); if (!e_bindings_mouse_button_find(E_BINDING_CONTEXT_WINDOW, &ev2, NULL)) return ECORE_CALLBACK_PASS_ON; } } } return ECORE_CALLBACK_DONE; } static void _e_border_cb_drag_finished(E_Drag *drag, int dropped __UNUSED__) { E_Border *bd; bd = drag->data; e_object_unref(E_OBJECT(bd)); drag_border = NULL; } #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) static Eina_Bool _e_border_cb_desk_window_profile_change(void *data __UNUSED__, int ev_type __UNUSED__, void *ev __UNUSED__) { // E_Event_Desk_Window_Profile_Change *e = ev; Eina_List *l = NULL; E_Border *bd; EINA_LIST_FOREACH(borders, l, bd) { if (!e_object_is_del(E_OBJECT(bd))) { bd->client.e.fetch.profile = 1; BD_CHANGED(bd); } } return ECORE_CALLBACK_PASS_ON; } #endif static Eina_Bool _e_border_post_move_resize_job(void *data) { E_Border *bd; bd = (E_Border *)data; if (bd->post_move) { E_Border *tmp; Eina_List *l; EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_move(tmp->win, bd->x + bd->client_inset.l + tmp->client.e.state.video_position.x, bd->y + bd->client_inset.t + tmp->client.e.state.video_position.y); } if (bd->client.e.state.video) { E_Border *parent; parent = bd->client.e.state.video_parent_border; ecore_x_window_move(bd->win, parent->x + parent->client_inset.l + bd->client.e.state.video_position.x, parent->y + parent->client_inset.t + bd->client.e.state.video_position.y); } else if ((bd->post_move) && (bd->post_resize)) { ecore_x_window_move_resize(bd->win, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t, bd->w - (e_border_inset_width_get(bd)), bd->h - (e_border_inset_height_get(bd))); } else if (bd->post_move) { ecore_x_window_move(bd->win, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t); } else if (bd->post_resize) { ecore_x_window_resize(bd->win, bd->w - (e_border_inset_width_get(bd)), bd->h - (e_border_inset_height_get(bd))); } if (bd->client.e.state.video) { fprintf(stderr, "%x: [%i, %i] [%i, %i]\n", bd->win, bd->client.e.state.video_parent_border->x + bd->client.e.state.video_parent_border->client_inset.l + bd->client.e.state.video_position.x, bd->client.e.state.video_parent_border->y + bd->client.e.state.video_parent_border->client_inset.t + bd->client.e.state.video_position.y, bd->w, bd->h); } if (bd->post_show) { if (bd->visible) { bd->post_job = NULL; _e_border_show(bd); } } bd->post_show = 0; bd->post_move = 0; bd->post_resize = 0; bd->post_job = NULL; return ECORE_CALLBACK_CANCEL; } static void _e_border_container_layout_hook(E_Container *con) { _e_border_hook_call(E_BORDER_HOOK_CONTAINER_LAYOUT, con); } static void _e_border_eval0(E_Border *bd) { int change_urgent = 0; int rem_change = 0; int title_change = 0; Eina_Bool new_cw = !bd->cw; #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) Eina_Bool need_desk_set = EINA_FALSE; #endif if (e_object_is_del(E_OBJECT(bd))) { CRI("_e_border_eval(%p) with deleted border!\n", bd); bd->changed = 0; return; } _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_FETCH, bd); bd->changes.border = 0; /* fetch any info queued to be fetched */ if (bd->changes.prop || bd->client.netwm.fetch.state) { e_hints_window_state_get(bd); bd->client.netwm.fetch.state = 0; rem_change = 1; } if (bd->client.icccm.fetch.client_leader) { /* TODO: What do to if the client leader isn't mapped yet? */ E_Border *bd_leader = NULL; bd->client.icccm.client_leader = ecore_x_icccm_client_leader_get(bd->client.win); if (bd->client.icccm.client_leader) bd_leader = e_border_find_by_client_window(bd->client.icccm.client_leader); if (bd->leader) { if (bd->leader != bd_leader) { bd->leader->group = eina_list_remove(bd->leader->group, bd); if (bd->leader->modal == bd) bd->leader->modal = NULL; bd->leader = NULL; } else bd_leader = NULL; } /* If this border is the leader of the group, don't register itself */ if ((bd_leader) && (bd_leader != bd)) { bd_leader->group = eina_list_append(bd_leader->group, bd); bd->leader = bd_leader; /* Only set the window modal to the leader it there is no parent */ if ((bd->client.netwm.state.modal) && ((!bd->parent) || (bd->parent->modal != bd))) { bd->leader->modal = bd; if (bd->leader->focused) e_border_focus_set(bd, 1, 1); else { Eina_List *l; E_Border *child; EINA_LIST_FOREACH(bd->leader->group, l, child) { if ((child != bd) && (child->focused)) e_border_focus_set(bd, 1, 1); } } } } bd->client.icccm.fetch.client_leader = 0; rem_change = 1; } if (bd->client.icccm.fetch.title) { char *title = ecore_x_icccm_title_get(bd->client.win); eina_stringshare_replace(&bd->client.icccm.title, title); free(title); if (bd->bg_object) edje_object_part_text_set(bd->bg_object, "e.text.title", bd->client.icccm.title); bd->client.icccm.fetch.title = 0; rem_change = 1; title_change = 1; } if (bd->client.netwm.fetch.name) { char *name; ecore_x_netwm_name_get(bd->client.win, &name); eina_stringshare_replace(&bd->client.netwm.name, name); free(name); bd->client.hacks.iconic_shading = ((bd->client.netwm.icon_name == bd->client.netwm.name) && (!e_util_strcmp(bd->client.netwm.name, "QEMU"))); if (bd->bg_object) edje_object_part_text_set(bd->bg_object, "e.text.title", bd->client.netwm.name); bd->client.netwm.fetch.name = 0; rem_change = 1; title_change = 1; } if (title_change) { E_Event_Border_Title_Change *ev; ev = E_NEW(E_Event_Border_Title_Change, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_TITLE_CHANGE, ev, _e_border_event_border_title_change_free, NULL); } if (bd->client.icccm.fetch.name_class) { const char *pname, *pclass; char *nname, *nclass; ecore_x_icccm_name_class_get(bd->client.win, &nname, &nclass); pname = bd->client.icccm.name; pclass = bd->client.icccm.class; bd->client.icccm.name = eina_stringshare_add(nname); bd->client.icccm.class = eina_stringshare_add(nclass); bd->client.hacks.mapping_change = ((!e_util_strcasecmp(bd->client.icccm.class, "vmplayer")) || (!e_util_strcasecmp(bd->client.icccm.class, "vmware"))); if (bd->client.hacks.mapping_change) e_bindings_mapping_change_enable(EINA_FALSE); free(nname); free(nclass); if (!((bd->client.icccm.name == pname) && (bd->client.icccm.class == pclass))) { bd->changes.icon = 1; rem_change = 1; } eina_stringshare_del(pname); eina_stringshare_del(pclass); bd->client.icccm.fetch.name_class = 0; } if (bd->changes.prop || bd->client.icccm.fetch.state) { bd->client.icccm.state = ecore_x_icccm_state_get(bd->client.win); bd->client.icccm.fetch.state = 0; rem_change = 1; } if (bd->changes.prop || bd->client.e.fetch.state) { e_hints_window_e_state_get(bd); bd->client.e.fetch.state = 0; rem_change = 1; } #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) if (bd->client.e.fetch.profile) { const char **list = NULL; int n, i, res; unsigned int use; if (bd->client.e.state.profile.name) { eina_stringshare_del(bd->client.e.state.profile.name); bd->client.e.state.profile.name = NULL; } if (bd->client.e.state.profile.available_list) { for (i = 0; i < bd->client.e.state.profile.num; i++) { if (bd->client.e.state.profile.available_list[i]) { eina_stringshare_del(bd->client.e.state.profile.available_list[i]); bd->client.e.state.profile.available_list[i] = NULL; } } E_FREE(bd->client.e.state.profile.available_list); bd->client.e.state.profile.available_list = NULL; } bd->client.e.state.profile.num = 0; res = ecore_x_window_prop_card32_get(bd->client.win, ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED, &use, 1); if ((res == 1) && (use == 1)) { Ecore_X_Atom val; res = ecore_x_window_prop_atom_get(bd->client.win, ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE, &val, 1); if (res == 1) { char *name = ecore_x_atom_name_get(val); if (name) { bd->client.e.state.profile.name = eina_stringshare_add(name); free(name); } } if (ecore_x_e_window_available_profiles_get(bd->client.win, &list, &n)) { bd->client.e.state.profile.available_list = E_NEW(const char *, n); for (i = 0; i < n; i++) bd->client.e.state.profile.available_list[i] = eina_stringshare_add(list[i]); bd->client.e.state.profile.num = n; } need_desk_set = EINA_TRUE; bd->client.e.state.profile.use = 1; free(list); } bd->client.e.fetch.profile = 0; } #endif if (bd->changes.prop || bd->client.netwm.fetch.type) { e_hints_window_type_get(bd); if ((!bd->lock_border) || (!bd->client.border.name)) bd->client.border.changed = 1; if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DOCK) { if (!bd->client.netwm.state.skip_pager) { bd->client.netwm.state.skip_pager = 1; bd->client.netwm.update.state = 1; } if (!bd->client.netwm.state.skip_taskbar) { bd->client.netwm.state.skip_taskbar = 1; bd->client.netwm.update.state = 1; } } bd->client.netwm.fetch.type = 0; } if (bd->client.icccm.fetch.machine) { char *machine = ecore_x_icccm_client_machine_get(bd->client.win); if ((!machine) && (bd->client.icccm.client_leader)) machine = ecore_x_icccm_client_machine_get(bd->client.icccm.client_leader); eina_stringshare_replace(&bd->client.icccm.machine, machine); free(machine); bd->client.icccm.fetch.machine = 0; rem_change = 1; } if (bd->client.icccm.fetch.command) { if ((bd->client.icccm.command.argc > 0) && (bd->client.icccm.command.argv)) { int i; for (i = 0; i < bd->client.icccm.command.argc; i++) free(bd->client.icccm.command.argv[i]); free(bd->client.icccm.command.argv); } bd->client.icccm.command.argc = 0; bd->client.icccm.command.argv = NULL; ecore_x_icccm_command_get(bd->client.win, &(bd->client.icccm.command.argc), &(bd->client.icccm.command.argv)); if ((bd->client.icccm.client_leader) && (!bd->client.icccm.command.argv)) ecore_x_icccm_command_get(bd->client.icccm.client_leader, &(bd->client.icccm.command.argc), &(bd->client.icccm.command.argv)); bd->client.icccm.fetch.command = 0; rem_change = 1; } if (bd->changes.prop || bd->client.icccm.fetch.hints) { Eina_Bool accepts_focus, is_urgent; accepts_focus = EINA_TRUE; is_urgent = EINA_FALSE; bd->client.icccm.initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; if (ecore_x_icccm_hints_get(bd->client.win, &accepts_focus, &bd->client.icccm.initial_state, &bd->client.icccm.icon_pixmap, &bd->client.icccm.icon_mask, &bd->client.icccm.icon_window, &bd->client.icccm.window_group, &is_urgent)) { bd->client.icccm.accepts_focus = accepts_focus; if ((bd->client.icccm.urgent != is_urgent) && ((!bd->focused) || (!is_urgent))) change_urgent = 1; bd->client.icccm.urgent = is_urgent; /* If this is a new window, set the state as requested. */ if ((bd->new_client) && (bd->client.icccm.initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)) { e_border_iconify(bd); e_border_hide(bd, 1); } } bd->client.icccm.fetch.hints = 0; rem_change = 1; } if (bd->changes.prop || bd->client.icccm.fetch.size_pos_hints) { Eina_Bool request_pos; request_pos = EINA_FALSE; if (ecore_x_icccm_size_pos_hints_get(bd->client.win, &request_pos, &bd->client.icccm.gravity, &bd->client.icccm.min_w, &bd->client.icccm.min_h, &bd->client.icccm.max_w, &bd->client.icccm.max_h, &bd->client.icccm.base_w, &bd->client.icccm.base_h, &bd->client.icccm.step_w, &bd->client.icccm.step_h, &bd->client.icccm.min_aspect, &bd->client.icccm.max_aspect)) { bd->client.icccm.request_pos = request_pos; } else { } if (bd->client.icccm.min_w > 32767) bd->client.icccm.min_w = 32767; if (bd->client.icccm.min_h > 32767) bd->client.icccm.min_h = 32767; if (bd->client.icccm.max_w > 32767) bd->client.icccm.max_w = 32767; if (bd->client.icccm.max_h > 32767) bd->client.icccm.max_h = 32767; if (bd->client.icccm.base_w > 32767) bd->client.icccm.base_w = 32767; if (bd->client.icccm.base_h > 32767) bd->client.icccm.base_h = 32767; // if (bd->client.icccm.step_w < 1) bd->client.icccm.step_w = 1; // if (bd->client.icccm.step_h < 1) bd->client.icccm.step_h = 1; // if doing a resize, fix it up if (bd->resize_mode != E_POINTER_RESIZE_NONE) { int x, y, w, h, new_w, new_h; x = bd->x; y = bd->y; w = bd->w; h = bd->h; new_w = w; new_h = h; e_border_resize_limit(bd, &new_w, &new_h); if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_L) || (bd->resize_mode == E_POINTER_RESIZE_BL)) x += (w - new_w); if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_T) || (bd->resize_mode == E_POINTER_RESIZE_TR)) y += (h - new_h); e_border_move_resize(bd, x, y, new_w, new_h); } bd->client.icccm.fetch.size_pos_hints = 0; rem_change = 1; } if (bd->client.icccm.fetch.protocol) { int i, num; Ecore_X_WM_Protocol *proto; proto = ecore_x_window_prop_protocol_list_get(bd->client.win, &num); if (proto) { for (i = 0; i < num; i++) { if (proto[i] == ECORE_X_WM_PROTOCOL_DELETE_REQUEST) bd->client.icccm.delete_request = 1; else if (proto[i] == ECORE_X_WM_PROTOCOL_TAKE_FOCUS) bd->client.icccm.take_focus = 1; else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_PING) bd->client.netwm.ping = 1; else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST) { bd->client.netwm.sync.request = 1; if (!ecore_x_netwm_sync_counter_get(bd->client.win, &bd->client.netwm.sync.counter)) bd->client.netwm.sync.request = 0; } } free(proto); } if (bd->client.netwm.ping) e_border_ping(bd); else { if (bd->ping_poller) ecore_poller_del(bd->ping_poller); bd->ping_poller = NULL; } bd->client.icccm.fetch.protocol = 0; } if (bd->client.icccm.fetch.transient_for) { /* TODO: What do to if the transient for isn't mapped yet? */ E_Border *bd_parent = NULL; bd->client.icccm.transient_for = ecore_x_icccm_transient_for_get(bd->client.win); if (bd->client.icccm.transient_for) bd_parent = e_border_find_by_client_window(bd->client.icccm.transient_for); /* If we already have a parent, remove it */ if (bd->parent) { if (bd_parent != bd->parent) { bd->parent->transients = eina_list_remove(bd->parent->transients, bd); if (bd->parent->modal == bd) bd->parent->modal = NULL; bd->parent = NULL; } else bd_parent = NULL; } if ((bd_parent) && (bd_parent != bd) && (eina_list_data_find(bd->transients, bd_parent) != bd_parent)) { bd_parent->transients = eina_list_append(bd_parent->transients, bd); bd->parent = bd_parent; } if (bd->parent) { e_border_layer_set(bd, bd->parent->layer); if (bd->client.netwm.state.modal) { bd->parent->modal = bd; bd->parent->lock_close = 1; if (!bd->parent->client.lock_win) { bd->parent->client.lock_win = ecore_x_window_input_new(bd->parent->win, 0, 0, bd->parent->client.w, bd->parent->client.h); e_comp_ignore_win_add(bd->parent->client.lock_win); eina_hash_add(borders_hash, e_util_winid_str_get(bd->parent->client.lock_win), bd->parent); ecore_x_window_show(bd->parent->client.lock_win); ecore_x_icccm_name_class_set(bd->parent->client.lock_win, "lock_win", "lock_win"); } } if (e_config->focus_setting == E_FOCUS_NEW_DIALOG || (bd->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED))) bd->take_focus = 1; } bd->client.icccm.fetch.transient_for = 0; rem_change = 1; } if (bd->client.icccm.fetch.window_role) { char *role = ecore_x_icccm_window_role_get(bd->client.win); eina_stringshare_replace(&bd->client.icccm.window_role, role); free(role); bd->client.icccm.fetch.window_role = 0; rem_change = 1; } if (bd->client.icccm.fetch.icon_name) { char *icon_name = ecore_x_icccm_icon_name_get(bd->client.win); eina_stringshare_replace(&bd->client.icccm.icon_name, icon_name); free(icon_name); bd->client.hacks.iconic_shading = ((bd->client.netwm.icon_name == bd->client.netwm.name) && (!e_util_strcmp(bd->client.netwm.icon_name, "QEMU"))); bd->client.icccm.fetch.icon_name = 0; rem_change = 1; } if (bd->client.netwm.fetch.icon_name) { char *icon_name; ecore_x_netwm_icon_name_get(bd->client.win, &icon_name); eina_stringshare_replace(&bd->client.netwm.icon_name, icon_name); free(icon_name); bd->client.netwm.fetch.icon_name = 0; rem_change = 1; } if (bd->client.netwm.fetch.opacity) { unsigned int val; if (ecore_x_window_prop_card32_get(bd->client.win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, &val, 1) > 0) bd->client.netwm.opacity = (val >> 24); } if (bd->client.netwm.fetch.icon) { int i; if (bd->client.netwm.icons) { for (i = 0; i < bd->client.netwm.num_icons; i++) { free(bd->client.netwm.icons[i].data); bd->client.netwm.icons[i].data = NULL; } free(bd->client.netwm.icons); } bd->client.netwm.icons = NULL; bd->client.netwm.num_icons = 0; if (ecore_x_netwm_icons_get(bd->client.win, &bd->client.netwm.icons, &bd->client.netwm.num_icons)) { // unless the rest of e17 uses border icons OTHER than icon #0 // then free the rest that we don't need anymore. for (i = 1; i < bd->client.netwm.num_icons; i++) { free(bd->client.netwm.icons[i].data); bd->client.netwm.icons[i].data = NULL; } bd->client.netwm.num_icons = 1; bd->changes.icon = 1; } bd->client.netwm.fetch.icon = 0; } if (bd->client.netwm.fetch.user_time) { ecore_x_netwm_user_time_get(bd->client.win, &bd->client.netwm.user_time); bd->client.netwm.fetch.user_time = 0; } if (bd->client.netwm.fetch.strut) { if (!ecore_x_netwm_strut_partial_get(bd->client.win, &bd->client.netwm.strut.left, &bd->client.netwm.strut.right, &bd->client.netwm.strut.top, &bd->client.netwm.strut.bottom, &bd->client.netwm.strut.left_start_y, &bd->client.netwm.strut.left_end_y, &bd->client.netwm.strut.right_start_y, &bd->client.netwm.strut.right_end_y, &bd->client.netwm.strut.top_start_x, &bd->client.netwm.strut.top_end_x, &bd->client.netwm.strut.bottom_start_x, &bd->client.netwm.strut.bottom_end_x)) { ecore_x_netwm_strut_get(bd->client.win, &bd->client.netwm.strut.left, &bd->client.netwm.strut.right, &bd->client.netwm.strut.top, &bd->client.netwm.strut.bottom); bd->client.netwm.strut.left_start_y = 0; bd->client.netwm.strut.left_end_y = 0; bd->client.netwm.strut.right_start_y = 0; bd->client.netwm.strut.right_end_y = 0; bd->client.netwm.strut.top_start_x = 0; bd->client.netwm.strut.top_end_x = 0; bd->client.netwm.strut.bottom_start_x = 0; bd->client.netwm.strut.bottom_end_x = 0; } bd->client.netwm.fetch.strut = 0; } if (bd->client.qtopia.fetch.soft_menu) { e_hints_window_qtopia_soft_menu_get(bd); bd->client.qtopia.fetch.soft_menu = 0; rem_change = 1; } if (bd->client.qtopia.fetch.soft_menus) { e_hints_window_qtopia_soft_menus_get(bd); bd->client.qtopia.fetch.soft_menus = 0; rem_change = 1; } if (bd->client.vkbd.fetch.state) { e_hints_window_virtual_keyboard_state_get(bd); bd->client.vkbd.fetch.state = 0; rem_change = 1; } if (bd->client.vkbd.fetch.vkbd) { e_hints_window_virtual_keyboard_get(bd); bd->client.vkbd.fetch.vkbd = 0; rem_change = 1; } if (bd->client.illume.conformant.fetch.conformant) { bd->client.illume.conformant.conformant = ecore_x_e_illume_conformant_get(bd->client.win); bd->client.illume.conformant.fetch.conformant = 0; } if (bd->client.illume.quickpanel.fetch.state) { bd->client.illume.quickpanel.state = ecore_x_e_illume_quickpanel_state_get(bd->client.win); bd->client.illume.quickpanel.fetch.state = 0; } if (bd->client.illume.quickpanel.fetch.quickpanel) { bd->client.illume.quickpanel.quickpanel = ecore_x_e_illume_quickpanel_get(bd->client.win); bd->client.illume.quickpanel.fetch.quickpanel = 0; } if (bd->client.illume.quickpanel.fetch.priority.major) { bd->client.illume.quickpanel.priority.major = ecore_x_e_illume_quickpanel_priority_major_get(bd->client.win); bd->client.illume.quickpanel.fetch.priority.major = 0; } if (bd->client.illume.quickpanel.fetch.priority.minor) { bd->client.illume.quickpanel.priority.minor = ecore_x_e_illume_quickpanel_priority_minor_get(bd->client.win); bd->client.illume.quickpanel.fetch.priority.minor = 0; } if (bd->client.illume.quickpanel.fetch.zone) { bd->client.illume.quickpanel.zone = ecore_x_e_illume_quickpanel_zone_get(bd->client.win); bd->client.illume.quickpanel.fetch.zone = 0; } if (bd->client.illume.drag.fetch.drag) { bd->client.illume.drag.drag = ecore_x_e_illume_drag_get(bd->client.win); bd->client.illume.drag.fetch.drag = 0; } if (bd->client.illume.drag.fetch.locked) { bd->client.illume.drag.locked = ecore_x_e_illume_drag_locked_get(bd->client.win); bd->client.illume.drag.fetch.locked = 0; } if (bd->client.illume.win_state.fetch.state) { bd->client.illume.win_state.state = ecore_x_e_illume_window_state_get(bd->client.win); bd->client.illume.win_state.fetch.state = 0; } if (bd->changes.shape) { Ecore_X_Rectangle *rects; int num; bd->changes.shape = 0; rects = ecore_x_window_shape_rectangles_get(bd->client.win, &num); if (rects) { int cw = 0, ch = 0; /* This doesn't fix the race, but makes it smaller. we detect * this and if cw and ch != client w/h then mark this as needing * a shape change again to fixup next event loop. */ ecore_x_window_size_get(bd->client.win, &cw, &ch); if ((cw != bd->client.w) || (ch != bd->client.h)) bd->changes.shape = 1; if ((num == 1) && (rects[0].x == 0) && (rects[0].y == 0) && ((int)rects[0].width == cw) && ((int)rects[0].height == ch)) { if (bd->client.shaped) { bd->client.shaped = 0; if (!bd->bordername) bd->client.border.changed = 1; } } else { if (!bd->client.shaped) { bd->client.shaped = 1; if (!bd->bordername) bd->client.border.changed = 1; } ecore_x_window_shape_rectangles_set(bd->win, rects, num); bd->changes.shape_input = 0; e_container_shape_input_rects_set(bd->shape, NULL, 0); } free(rects); } else { // FIXME: no rects i think can mean... totally empty window bd->client.shaped = 0; if (!bd->bordername) bd->client.border.changed = 1; } bd->need_shape_merge = 1; } if (bd->changes.shape_input) { Ecore_X_Rectangle *rects; int num; bd->changes.shape_input = 0; rects = ecore_x_window_shape_input_rectangles_get(bd->client.win, &num); if (rects) { int cw = 0, ch = 0; /* This doesn't fix the race, but makes it smaller. we detect * this and if cw and ch != client w/h then mark this as needing * a shape change again to fixup next event loop. */ ecore_x_window_size_get(bd->client.win, &cw, &ch); if ((cw != bd->client.w) || (ch != bd->client.h)) bd->changes.shape_input = 1; if ((num == 1) && (rects[0].x == 0) && (rects[0].y == 0) && ((int)rects[0].width == cw) && ((int)rects[0].height == ch)) { if (bd->shaped_input) { bd->shaped_input = 0; if (!bd->bordername) bd->client.border.changed = 1; } free(rects); } else { if (!bd->shaped_input) { bd->shaped_input = 1; if (!bd->bordername) bd->client.border.changed = 1; } ecore_x_window_shape_input_rectangles_set(bd->win, rects, num); e_container_shape_input_rects_set(bd->shape, (Eina_Rectangle *)rects, num); } } else { bd->shaped_input = 1; if (!bd->bordername) bd->client.border.changed = 1; } bd->need_shape_merge = 1; } if (bd->changes.prop || bd->client.mwm.fetch.hints) { int pb; bd->client.mwm.exists = ecore_x_mwm_hints_get(bd->client.win, &bd->client.mwm.func, &bd->client.mwm.decor, &bd->client.mwm.input); pb = bd->client.mwm.borderless; bd->client.mwm.borderless = 0; if (bd->client.mwm.exists) { if ((!(bd->client.mwm.decor & ECORE_X_MWM_HINT_DECOR_ALL)) && (!(bd->client.mwm.decor & ECORE_X_MWM_HINT_DECOR_TITLE)) && (!(bd->client.mwm.decor & ECORE_X_MWM_HINT_DECOR_BORDER))) bd->client.mwm.borderless = 1; } if (bd->client.mwm.borderless != pb) { if ((!bd->lock_border) || (!bd->client.border.name)) bd->client.border.changed = 1; } bd->client.mwm.fetch.hints = 0; rem_change = 1; } if (bd->client.e.fetch.video_parent) { /* unlinking child/parent */ if (bd->client.e.state.video_parent_border != NULL) { bd->client.e.state.video_parent_border->client.e.state.video_child = eina_list_remove (bd->client.e.state.video_parent_border->client.e.state.video_child, bd); } ecore_x_window_prop_card32_get(bd->client.win, ECORE_X_ATOM_E_VIDEO_PARENT, &bd->client.e.state.video_parent, 1); /* linking child/parent */ if (bd->client.e.state.video_parent != 0) { E_Border *tmp; Eina_List *l; EINA_LIST_FOREACH(borders, l, tmp) if (tmp->client.win == bd->client.e.state.video_parent) { /* fprintf(stderr, "child added to parent \\o/\n"); */ bd->client.e.state.video_parent_border = tmp; tmp->client.e.state.video_child = eina_list_append(tmp->client.e.state.video_child, bd); if (bd->desk != tmp->desk) e_border_desk_set(bd, tmp->desk); break; } } /* fprintf(stderr, "new parent %x => %p\n", bd->client.e.state.video_parent, bd->client.e.state.video_parent_border); */ if (bd->client.e.state.video_parent_border) bd->client.e.fetch.video_parent = 0; rem_change = 1; } if (bd->client.e.fetch.video_position && bd->client.e.fetch.video_parent == 0) { unsigned int xy[2]; ecore_x_window_prop_card32_get(bd->client.win, ECORE_X_ATOM_E_VIDEO_POSITION, xy, 2); bd->client.e.state.video_position.x = xy[0]; bd->client.e.state.video_position.y = xy[1]; bd->client.e.state.video_position.updated = 1; bd->client.e.fetch.video_position = 0; bd->x = bd->client.e.state.video_position.x; bd->y = bd->client.e.state.video_position.y; fprintf(stderr, "internal position has been updated [%i, %i]\n", bd->client.e.state.video_position.x, bd->client.e.state.video_position.y); } if (bd->changes.prop || bd->client.netwm.update.state) { e_hints_window_state_set(bd); /* Some stats might change the border, like modal */ if (((!bd->lock_border) || (!bd->client.border.name)) && (!(((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)))) { bd->client.border.changed = 1; } if (bd->parent) { if (bd->client.netwm.state.modal) { bd->parent->modal = bd; if (bd->parent->focused) e_border_focus_set(bd, 1, 1); } } else if (bd->leader) { if (bd->client.netwm.state.modal) { bd->leader->modal = bd; if (bd->leader->focused) e_border_focus_set(bd, 1, 1); else { Eina_List *l; E_Border *child; EINA_LIST_FOREACH(bd->leader->group, l, child) { if ((child != bd) && (child->focused)) e_border_focus_set(bd, 1, 1); } } } } bd->client.netwm.update.state = 0; } #if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8) if ((e_config->use_desktop_window_profile) && (need_desk_set)) { if (!(bd->client.e.state.profile.name) && (bd->client.e.state.profile.num >= 1)) { const char *p = NULL; int i; for (i = 0; i < bd->client.e.state.profile.num; i++) { if (!bd->client.e.state.profile.available_list[i]) continue; p = bd->client.e.state.profile.available_list[i]; if (strcmp(bd->desk->window_profile, p) == 0) { bd->client.e.state.profile.name = eina_stringshare_add(bd->desk->window_profile); break; } } if (!bd->client.e.state.profile.name) { E_Container *con = bd->zone->container; E_Desk *desk = NULL; for (i = 0; i < bd->client.e.state.profile.num; i++) { if (!bd->client.e.state.profile.available_list[i]) continue; p = bd->client.e.state.profile.available_list[i]; desk = e_container_desk_window_profile_get(con, p); if ((desk) && (bd->desk != desk)) { bd->client.e.state.profile.name = eina_stringshare_add(p); break; } } } } if (!bd->client.e.state.profile.name) { bd->client.e.state.profile.name = eina_stringshare_add(bd->desk->window_profile); } ecore_x_e_window_profile_change_request_send(bd->client.win, bd->client.e.state.profile.name); bd->client.e.state.profile.wait_for_done = 1; } #endif if (bd->new_client) { E_Event_Border_Add *ev; E_Exec_Instance *inst; ev = E_NEW(E_Event_Border_Add, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_add_event"); ecore_event_add(E_EVENT_BORDER_ADD, ev, _e_border_event_border_add_free, NULL); if ((!bd->lock_border) || (!bd->client.border.name)) bd->client.border.changed = 1; { char *str = NULL; if ((ecore_x_netwm_startup_id_get(bd->client.win, &str) && (str)) || ((bd->client.icccm.client_leader > 0) && ecore_x_netwm_startup_id_get(bd->client.icccm.client_leader, &str) && (str)) ) { if (!strncmp(str, "E_START|", 8)) { int id; id = atoi(str + 8); if (id > 0) bd->client.netwm.startup_id = id; } free(str); } } /* It's ok not to have fetch flag, should only be set on startup * * and not changed. */ if (!ecore_x_netwm_pid_get(bd->client.win, &bd->client.netwm.pid)) { if (bd->client.icccm.client_leader) { if (!ecore_x_netwm_pid_get(bd->client.icccm.client_leader, &bd->client.netwm.pid)) bd->client.netwm.pid = -1; } else bd->client.netwm.pid = -1; } if (bd->re_manage) e_exec_phony(bd); else { inst = e_exec_startup_id_pid_instance_find(bd->client.netwm.startup_id, bd->client.netwm.pid); if ((inst) && (inst->used == 0)) { E_Zone *zone; E_Desk *desk; inst->used++; zone = e_container_zone_number_get(bd->zone->container, inst->screen); if (zone) e_border_zone_set(bd, zone); desk = e_desk_at_xy_get(bd->zone, inst->desk_x, inst->desk_y); if (desk) e_border_desk_set(bd, desk); if (bd->client.netwm.pid != ecore_exe_pid_get(inst->exe)) { /* most likely what has happened here is that the .desktop launcher * has spawned a process which then created this border, meaning the * E_Exec instance will be deleted in a moment, and we will be unable to track it. * to prevent this, we convert our instance to a phony */ inst->phony = 1; } inst->bd = bd; bd->exe_inst = inst; e_exec_instance_found(inst); } else if (!inst) e_exec_phony(bd); if (e_config->window_grouping) // FIXME: We may want to make the border "urgent" so that the user knows it appeared. { E_Border *bdl = NULL; bdl = bd->parent; if (!bdl) { if (bd->leader) bdl = bd->leader; } if (!bdl) { E_Border *child; E_Border_List *bl; bl = e_container_border_list_first(bd->zone->container); while ((child = e_container_border_list_next(bl))) { if (child == bd) continue; if (e_object_is_del(E_OBJECT(child))) continue; if ((bd->client.icccm.client_leader) && (child->client.icccm.client_leader == bd->client.icccm.client_leader)) { bdl = child; break; } } e_container_border_list_free(bl); } if (bdl) { if (bdl->zone) e_border_zone_set(bd, bdl->zone); if (bdl->desk) e_border_desk_set(bd, bdl->desk); else e_border_stick(bd); } } } } /* PRE_POST_FETCH calls e_remember apply for new client */ _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_POST_FETCH, bd); _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_FETCH, bd); _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_BORDER_ASSIGN, bd); if (bd->need_reparent) { if (!bd->internal) ecore_x_window_save_set_add(bd->client.win); ecore_x_window_reparent(bd->client.win, bd->win, bd->client_inset.l, bd->client_inset.t); if (bd->visible) { if ((bd->new_client) && (bd->internal) && (bd->internal_ecore_evas)) ecore_evas_show(bd->internal_ecore_evas); } if (bd->new_client) { ecore_x_window_show(bd->client.win); _e_border_show(bd); } bd->need_reparent = 0; } if ((bd->client.border.changed) && (!bd->shaded) && (!(((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)))) { const char *bordername; if (bd->fullscreen || bd->borderless) bordername = "borderless"; else if (bd->bordername) bordername = bd->bordername; else if ((bd->client.mwm.borderless) || (bd->borderless)) bordername = "borderless"; else if (((bd->client.icccm.transient_for != 0) || (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)) && (bd->client.icccm.min_w == bd->client.icccm.max_w) && (bd->client.icccm.min_h == bd->client.icccm.max_h)) bordername = "noresize_dialog"; else if ((bd->client.icccm.min_w == bd->client.icccm.max_w) && (bd->client.icccm.min_h == bd->client.icccm.max_h)) bordername = "noresize"; else if (bd->client.shaped) bordername = "shaped"; else if ((!bd->client.icccm.accepts_focus) && (!bd->client.icccm.take_focus)) bordername = "nofocus"; else if (bd->client.icccm.urgent) bordername = "urgent"; else if ((bd->client.icccm.transient_for != 0) || (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)) bordername = "dialog"; else if (bd->client.netwm.state.modal) bordername = "modal"; else if ((bd->client.netwm.state.skip_taskbar) || (bd->client.netwm.state.skip_pager)) bordername = "skipped"; /* else if ((bd->internal) && (bd->client.icccm.class) && (!strncmp(bd->client.icccm.class, "e_fwin", 6))) bordername = "internal_fileman"; */ else bordername = e_config->theme_default_border_style; if (!bordername) bordername = "default"; if ((!bd->client.border.name) || (strcmp(bd->client.border.name, bordername))) { Evas_Object *o, *pbg = bd->bg_object; char buf[4096]; int ok; bd->changes.border = 1; eina_stringshare_replace(&bd->client.border.name, bordername); if (bd->bg_object) { int w, h; w = bd->w, h = bd->h; bd->w -= (e_border_inset_width_get(bd)); bd->h -= (e_border_inset_height_get(bd)); if ((bd->w != w) || (h != bd->h)) bd->changes.size = 1; evas_object_del(bd->bg_object); } o = edje_object_add(e_comp_get(bd)->evas); snprintf(buf, sizeof(buf), "e/widgets/border/%s/border", bd->client.border.name); ok = e_theme_edje_object_set(o, "base/theme/borders", buf); if ((!ok) && (strcmp(bd->client.border.name, "borderless"))) { if (bd->client.border.name != e_config->theme_default_border_style) { snprintf(buf, sizeof(buf), "e/widgets/border/%s/border", e_config->theme_default_border_style); ok = e_theme_edje_object_set(o, "base/theme/borders", buf); } if (!ok) { ok = e_theme_edje_object_set(o, "base/theme/borders", "e/widgets/border/default/border"); if (ok) { /* Reset default border style to default */ eina_stringshare_replace(&e_config->theme_default_border_style, "default"); e_config_save_queue(); } } } if (ok) { bd->bg_object = o; evas_object_name_set(o, "bd->bg_object"); if (bd->client.netwm.name) edje_object_part_text_set(o, "e.text.title", bd->client.netwm.name); else if (bd->client.icccm.title) edje_object_part_text_set(o, "e.text.title", bd->client.icccm.title); bd->theme_shadow = !!edje_object_data_get(o, "shadow"); _e_border_shadow(bd); if (pbg) { if (bd->icon_object) edje_object_part_swallow(bd->bg_object, "e.swallow.icon", bd->icon_object); } else bd->changes.icon = 1; } else { if (strcmp(bordername, "borderless")) /* it should never happen that a theme fails to set the edje * unless it's using borderless */ CRI("USER IS USING A SHITTY THEME! ABORT!!!!"); evas_object_del(o); bd->bg_object = NULL; E_FREE_FUNC(bd->icon_object, evas_object_del); o = bd->cw ? bd->cw->obj : NULL; } if (bd->cw) e_comp_win_reshadow(bd->cw); /* FIXME: it's theoretically possible that o is NULL here if first border eval occurs for a fullscreen * borderless window before its comp win has been set up; * E19 material imo */ { // previously calculated Eina_Bool calc = bd->client_inset.calc; // previously was borderless Eina_Bool inset, pinset = !!(e_border_inset_width_get(bd) + e_border_inset_height_get(bd)); _e_border_client_inset_calc(bd); inset = !!(e_border_inset_width_get(bd) + e_border_inset_height_get(bd)); if (calc && (inset != pinset) && (pbg || (!bd->bg_object))) { if (inset) bd->x -= bd->client_inset.l, bd->y -= bd->client_inset.t; else bd->x += bd->client_inset.l, bd->y += bd->client_inset.t; } } bd->w += (e_border_inset_width_get(bd)); bd->h += (e_border_inset_height_get(bd)); bd->changes.size = 1; if (bd->maximized != E_MAXIMIZE_NONE) { E_Maximize maximized = bd->maximized; /* to force possible resizes */ bd->maximized = E_MAXIMIZE_NONE; _e_border_maximize(bd, maximized); /* restore maximized state */ bd->maximized = maximized; e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL, bd->maximized & E_MAXIMIZE_VERTICAL); } if (bd->bg_object) { edje_object_signal_callback_add(bd->bg_object, "*", "*", _e_border_cb_signal_bind, bd); if (bd->focused) { edje_object_signal_emit(bd->bg_object, "e,state,focused", "e"); if (bd->icon_object) edje_object_signal_emit(bd->icon_object, "e,state,focused", "e"); } if (bd->shaded) edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e"); if (bd->sticky) edje_object_signal_emit(bd->bg_object, "e,state,sticky", "e"); if (bd->hung) edje_object_signal_emit(bd->bg_object, "e,state,hung", "e"); // FIXME: in eval -do differently // edje_object_message_signal_process(bd->bg_object); // e_border_frame_recalc(bd); } } bd->client.border.changed = 0; } bd->changes.prop = 0; if (rem_change) e_remember_update(bd); /* the below function updates the border's remember * and relevant netwm atom * ...eventually */ if (bd->cw) e_comp_win_opacity_set(bd->cw, bd->client.netwm.opacity); if (change_urgent) { E_Event_Border_Urgent_Change *ev; if (bd->client.icccm.urgent) edje_object_signal_emit(bd->bg_object, "e,state,urgent", "e"); else edje_object_signal_emit(bd->bg_object, "e,state,not_urgent", "e"); ev = E_NEW(E_Event_Border_Urgent_Change, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_URGENT_CHANGE, ev, _e_border_event_border_urgent_change_free, NULL); } _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN, bd); if (!new_cw) return; evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_IN, _e_border_cb_mouse_in, bd); evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_MOVE, _e_border_cb_mouse_move, bd); evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_OUT, _e_border_cb_mouse_out, bd); evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_DOWN, _e_border_cb_mouse_down, bd); evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_UP, _e_border_cb_mouse_up, bd); evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_WHEEL, _e_border_cb_mouse_wheel, bd); } static void _e_border_eval(E_Border *bd) { E_Event_Border_Property *event; E_Border_Pending_Move_Resize *pnd; int rem_change = 0; int send_event = 1; if (e_object_is_del(E_OBJECT(bd))) { CRI("_e_border_eval(%p) with deleted border! - %d\n", bd, bd->new_client); bd->changed = 0; return; } _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_NEW_BORDER, bd); if (bd->new_client) { int zx = 0, zy = 0, zw = 0, zh = 0; if (bd->zone) e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh); /* * Limit maximum size of windows to useful geometry */ // TODO: temoporary limited maximize algorithm // -> /*if (bd->w > zw) rw = zw; else rw = bd->w; if (bd->h > zh) rh = zh; else rh = bd->h; if ((rw != bd->w) || (rh != bd->h)) { bd->w = rw; bd->h = rh; e_border_resize (bd, bd->w, bd->h); }*/ // <- if (bd->re_manage) { int x = bd->x, y = bd->y; if (bd->x) bd->x -= bd->client_inset.l; if (bd->y) bd->y -= bd->client_inset.t; if ((x != bd->x) || (y != bd->y)) bd->changes.pos = 1; bd->placed = 1; } else if ((!bd->placed) && (bd->client.icccm.request_pos)) { Ecore_X_Window_Attributes *att; int bw; att = &bd->client.initial_attributes; bw = att->border * 2; switch (bd->client.icccm.gravity) { case ECORE_X_GRAVITY_N: bd->x = (att->x - (bw / 2)) - (bd->client_inset.l / 2); bd->y = att->y; break; case ECORE_X_GRAVITY_NE: bd->x = (att->x - (bw)) - (bd->client_inset.l); bd->y = att->y; break; case ECORE_X_GRAVITY_E: bd->x = (att->x - (bw)) - (bd->client_inset.l); bd->y = (att->y - (bw / 2)) - (bd->client_inset.t / 2); break; case ECORE_X_GRAVITY_SE: bd->x = (att->x - (bw)) - (bd->client_inset.l); bd->y = (att->y - (bw)) - (bd->client_inset.t); break; case ECORE_X_GRAVITY_S: bd->x = (att->x - (bw / 2)) - (bd->client_inset.l / 2); bd->y = (att->y - (bw)) - (bd->client_inset.t); break; case ECORE_X_GRAVITY_SW: bd->x = att->x; bd->y = (att->y - (bw)) - (bd->client_inset.t); break; case ECORE_X_GRAVITY_W: bd->x = att->x; bd->y = (att->y - (bw)) - (bd->client_inset.t); break; case ECORE_X_GRAVITY_CENTER: bd->x = (att->x - (bw / 2)) - (bd->client_inset.l / 2); bd->y = (att->y - (bw / 2)) - (bd->client_inset.t / 2); break; case ECORE_X_GRAVITY_NW: default: bd->x = att->x; bd->y = att->y; } /* * This ensures that windows that like to open with a x/y * position smaller than returned by e_zone_useful_geometry_get() * are moved to useful positions. */ // -> if (e_config->geometry_auto_move) { if (bd->x < zx) bd->x = zx; if (bd->y < zy) bd->y = zy; /* ensure we account for windows which already have client_inset; * fixes lots of wine placement issues */ if (bd->x - bd->client_inset.l >= zx) bd->x -= bd->client_inset.l; if (bd->y - bd->client_inset.t >= zy) bd->y -= bd->client_inset.t; if (bd->x + bd->w > zx + zw) bd->x = zx + zw - bd->w; if (bd->y + bd->h > zy + zh) bd->y = zy + zh - bd->h; // <-- if (bd->zone && e_container_zone_at_point_get(bd->zone->container, bd->x, bd->y)) { if (!E_INSIDE(bd->x, bd->y, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h)) { bd->x = E_CLAMP(bd->x, bd->zone->x, bd->zone->x + bd->zone->w); bd->y = E_CLAMP(bd->y, bd->zone->y, bd->zone->y + bd->zone->h); } /* some application failing to correctly center a window */ if (eina_list_count(bd->zone->container->zones) > 1) { if (((abs((bd->zone->container->w / 2) - bd->x) < 3) || //bd->x is center of container ((abs((bd->zone->container->w / 2) - bd->x - bd->w) < 3) || //bd->x - bd->w is center of container (abs((bd->zone->container->w / 2) - bd->x - (bd->w / 2)) < 3))) || //bd->x - bd->w/2 is center of container ((abs((bd->zone->container->h / 2) - bd->y) < 3) || //bd->y is center of container ((abs((bd->zone->container->h / 2) - bd->y - bd->h) < 3) || //bd->y - bd->h is center of container (abs((bd->zone->container->h / 2) - bd->y - (bd->h / 2)) < 3))) //bd->y - bd->h/2 is center of container ) e_border_center(bd); } bd->changes.pos = 1; bd->placed = 1; } } else { bd->changes.pos = 1; bd->placed = 1; } } if (!bd->placed) { /* FIXME: special placement for dialogs etc. etc. etc goes * here */ /* FIXME: what if parent is not on this desktop - or zone? */ if ((bd->parent) && (bd->parent->visible)) { bd->x = bd->parent->x + ((bd->parent->w - bd->w) / 2); bd->y = bd->parent->y + ((bd->parent->h - bd->h) / 2); bd->changes.pos = 1; bd->placed = 1; } #if 0 else if ((bd->leader) && (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)) { /* TODO: Place in center of group */ } #endif else if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG) { bd->x = zx + ((zw - bd->w) / 2); bd->y = zy + ((zh - bd->h) / 2); bd->changes.pos = 1; bd->placed = 1; } } if (!bd->placed) { Eina_List *skiplist = NULL; int new_x, new_y; if (zw > bd->w) new_x = zx + (rand() % (zw - bd->w)); else new_x = zx; if (zh > bd->h) new_y = zy + (rand() % (zh - bd->h)); else new_y = zy; if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET)) { skiplist = eina_list_append(skiplist, bd); if (bd->desk) e_place_desk_region_smart(bd->desk, skiplist, bd->x, bd->y, bd->w, bd->h, &new_x, &new_y); else e_place_zone_region_smart(bd->zone, skiplist, bd->x, bd->y, bd->w, bd->h, &new_x, &new_y); eina_list_free(skiplist); } else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) { e_place_zone_manual(bd->zone, bd->w, bd->client_inset.t, &new_x, &new_y); } else { e_place_zone_cursor(bd->zone, bd->x, bd->y, bd->w, bd->h, bd->client_inset.t, &new_x, &new_y); } bd->x = new_x; bd->y = new_y; bd->changes.pos = 1; } EINA_LIST_FREE(bd->pending_move_resize, pnd) { if ((!bd->lock_client_location) && (pnd->move)) { bd->x = pnd->x; bd->y = pnd->y; bd->changes.pos = 1; bd->placed = 1; if (pnd->without_border) { bd->x -= bd->client_inset.l; bd->y -= bd->client_inset.t; } } if ((!bd->lock_client_size) && (pnd->resize)) { bd->w = pnd->w + (e_border_inset_width_get(bd)); bd->h = pnd->h + (e_border_inset_height_get(bd)); bd->client.w = pnd->w; bd->client.h = pnd->h; bd->changes.size = 1; } free(pnd); } /* Recreate state */ e_hints_window_init(bd); if ((bd->client.e.state.centered) && ((!bd->remember) || ((bd->remember) && (!(bd->remember->apply & E_REMEMBER_APPLY_POS))))) { bd->x = zx + (zw - bd->w) / 2; bd->y = zy + (zh - bd->h) / 2; bd->changes.pos = 1; bd->placed = 1; } _e_border_client_move_resize_send(bd); /* if the explicit geometry request asks for the app to be * in another zone - well move it there */ { E_Zone *zone; zone = e_container_zone_at_point_get(bd->zone->container, bd->x + (bd->w / 2), bd->y + (bd->h / 2)); if (!zone) zone = e_container_zone_at_point_get(bd->zone->container, bd->x, bd->y); if (!zone) zone = e_container_zone_at_point_get(bd->zone->container, bd->x + bd->w - 1, bd->y); if (!zone) zone = e_container_zone_at_point_get(bd->zone->container, bd->x + bd->w - 1, bd->y + bd->h - 1); if (!zone) zone = e_container_zone_at_point_get(bd->zone->container, bd->x, bd->y + bd->h - 1); if ((zone) && (zone != bd->zone)) e_border_zone_set(bd, zone); } } _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_NEW_BORDER, bd); /* effect changes to the window border itself */ if ((bd->changes.shading)) { /* show at start of unshade (but don't hide until end of shade) */ //if (bd->shaded) //ecore_x_window_raise(bd->win); bd->changes.shading = 0; send_event = 0; rem_change = 1; } if (bd->changes.shaded) send_event = 0; if ((bd->changes.shaded) && (bd->changes.pos) && (bd->changes.size)) { //if (bd->shaded) //ecore_x_window_lower(bd->win); //else //ecore_x_window_raise(bd->win); bd->changes.shaded = 0; rem_change = 1; } else if ((bd->changes.shaded) && (bd->changes.pos)) { //if (bd->shaded) //ecore_x_window_lower(bd->win); //else //ecore_x_window_raise(bd->win); bd->changes.size = 1; bd->changes.shaded = 0; rem_change = 1; } else if ((bd->changes.shaded) && (bd->changes.size)) { //if (bd->shaded) //ecore_x_window_lower(bd->win); //else //ecore_x_window_raise(bd->win); bd->changes.shaded = 0; rem_change = 1; } else if (bd->changes.shaded) { //if (bd->shaded) //ecore_x_window_lower(bd->win); //else //ecore_x_window_raise(bd->win); bd->changes.shaded = 0; rem_change = 1; } if (bd->changes.size) { int x, y, w = 0, h = 0; x = bd->x + bd->client_inset.l; y = bd->y + bd->client_inset.t; if ((!bd->shaded) || (bd->shading)) { w = bd->w - (e_border_inset_width_get(bd)); h = bd->h - (e_border_inset_height_get(bd)); if (bd->shading) { if (bd->shade.dir == E_DIRECTION_UP) { y = h - bd->client.h; } else if (bd->shade.dir == E_DIRECTION_LEFT) { x = w - bd->client.w; } } } if (bd->client.e.state.video) { if (bd->client.e.state.video_position.updated) { ecore_x_window_move(bd->win, bd->client.e.state.video_parent_border->x + bd->client.e.state.video_parent_border->client_inset.l + bd->client.e.state.video_position.x, bd->client.e.state.video_parent_border->y + bd->client.e.state.video_parent_border->client_inset.t + bd->client.e.state.video_position.y); bd->client.e.state.video_position.updated = 0; } } else if (!bd->changes.pos) { if (bd->post_job) ecore_idle_enterer_del(bd->post_job); bd->post_job = ecore_idle_enterer_add(_e_border_post_move_resize_job, bd); bd->post_resize = 1; } else { E_Border *tmp; Eina_List *l; EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) ecore_x_window_move(tmp->win, bd->x + bd->client_inset.l + tmp->client.e.state.video_position.x, bd->y + bd->client_inset.t + tmp->client.e.state.video_position.y); } if ((!bd->shaded) && (!bd->shading)) { ecore_x_window_move_resize(bd->win, x, y, w, h); if (bd->internal_ecore_evas) ecore_evas_move_resize(bd->internal_ecore_evas, 0, 0, w, h); else if (!bd->client.e.state.video) { ecore_x_window_move_resize(bd->client.win, 0, 0, bd->client.w, bd->client.h); ecore_x_window_move_resize(bd->client.lock_win, 0, 0, bd->client.w, bd->client.h); } _e_border_client_move_resize_send(bd); } e_container_shape_resize(bd->shape, w, h); if (bd->changes.pos) e_container_shape_move(bd->shape, x, y); bd->changes.pos = 0; bd->changes.size = 0; rem_change = 1; } else if (bd->changes.pos) { if (bd->post_job) ecore_idle_enterer_del(bd->post_job); bd->post_job = ecore_idle_enterer_add(_e_border_post_move_resize_job, bd); bd->post_move = 1; e_container_shape_move(bd->shape, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t); _e_border_client_move_resize_send(bd); bd->changes.pos = 0; rem_change = 1; } if (bd->changes.reset_gravity) { GRAV_SET(bd, ECORE_X_GRAVITY_NW); bd->changes.reset_gravity = 0; rem_change = 1; } if (bd->need_shape_merge) { _e_border_shape_input_rectangle_set(bd); if (!bd->client.shaped) ecore_x_window_shape_mask_set(bd->win, 0); //bd->need_shape_export = 1; bd->need_shape_merge = 0; } if (bd->need_shape_export) { Ecore_X_Rectangle *rects, *orects; int num; rects = ecore_x_window_shape_rectangles_get(bd->client.win, &num); if (rects) { int changed; changed = 1; if ((num == bd->shape->shape_rects_num) && (bd->shape->shape_rects)) { int i; orects = (Ecore_X_Rectangle*)bd->shape->shape_rects; changed = 0; for (i = 0; i < num; i++) { if (rects[i].x < 0) { rects[i].width -= rects[i].x; rects[i].x = 0; } if ((rects[i].x + (int)rects[i].width) > bd->w) rects[i].width = rects[i].width - rects[i].x; if (rects[i].y < 0) { rects[i].height -= rects[i].y; rects[i].y = 0; } if ((rects[i].y + (int)rects[i].height) > bd->h) rects[i].height = rects[i].height - rects[i].y; if ((orects[i].x != rects[i].x) || (orects[i].y != rects[i].y) || (orects[i].width != rects[i].width) || (orects[i].height != rects[i].height)) { changed = 1; break; } } } if (changed) { if (bd->client.shaped) e_container_shape_solid_rect_set(bd->shape, 0, 0, 0, 0); e_container_shape_rects_set(bd->shape, (Eina_Rectangle*)rects, num); } else free(rects); } else { e_container_shape_rects_set(bd->shape, NULL, 0); } bd->need_shape_export = 0; } if ((bd->changes.visible) && (bd->visible) && (bd->new_client)) { int x, y; ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y); if ((!bd->placed) && (!bd->re_manage) && (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) && (!((bd->client.icccm.transient_for != 0) || (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG))) && (!bdmove) && (!bdresize)) { /* Set this window into moving state */ bd->cur_mouse_action = e_action_find("window_move"); if (bd->cur_mouse_action) { if ((!bd->cur_mouse_action->func.end_mouse) && (!bd->cur_mouse_action->func.end)) bd->cur_mouse_action = NULL; if (bd->cur_mouse_action) { bd->x = x - (bd->w >> 1); bd->y = y - (bd->client_inset.t >> 1); BD_CHANGED(bd); bd->changes.pos = 1; _e_border_client_move_resize_send(bd); } } } _e_border_show(bd); if (bd->cur_mouse_action) { bd->moveinfo.down.x = bd->x; bd->moveinfo.down.y = bd->y; bd->moveinfo.down.w = bd->w; bd->moveinfo.down.h = bd->h; bd->mouse.current.mx = x; bd->mouse.current.my = y; bd->moveinfo.down.button = 0; bd->moveinfo.down.mx = x; bd->moveinfo.down.my = y; grabbed = 1; e_object_ref(E_OBJECT(bd->cur_mouse_action)); bd->cur_mouse_action->func.go(E_OBJECT(bd), NULL); if (e_config->border_raise_on_mouse_action) e_border_raise(bd); e_border_focus_set(bd, 1, 1); } bd->changes.visible = 0; rem_change = 1; { E_Event_Border_Show *ev; ev = E_NEW(E_Event_Border_Show, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_show_event"); ecore_event_add(E_EVENT_BORDER_SHOW, ev, _e_border_event_border_show_free, NULL); } } else if ((bd->changes.visible) && (bd->new_client)) { bd->changes.visible = 0; { E_Event_Border_Hide *ev; ev = E_NEW(E_Event_Border_Hide, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_hide_event"); ecore_event_add(E_EVENT_BORDER_HIDE, ev, _e_border_event_border_hide_free, NULL); } } if (bd->changes.icon) { if (bd->desktop) { efreet_desktop_free(bd->desktop); bd->desktop = NULL; } if (bd->icon_object) { evas_object_del(bd->icon_object); bd->icon_object = NULL; } if (bd->remember && bd->remember->prop.desktop_file) { const char *desktop = bd->remember->prop.desktop_file; bd->desktop = efreet_desktop_get(desktop); if (!bd->desktop) bd->desktop = efreet_util_desktop_name_find(desktop); } if (!bd->desktop) { if ((bd->client.icccm.name) && (bd->client.icccm.class)) bd->desktop = efreet_util_desktop_wm_class_find(bd->client.icccm.name, bd->client.icccm.class); } if (!bd->desktop) { /* libreoffice and maybe others match window class with .desktop file name */ if (bd->client.icccm.class) { char buf[128]; snprintf(buf, sizeof(buf), "%s.desktop", bd->client.icccm.class); bd->desktop = efreet_util_desktop_file_id_find(buf); } } if (!bd->desktop) { bd->desktop = e_exec_startup_id_pid_find(bd->client.netwm.startup_id, bd->client.netwm.pid); if (bd->desktop) efreet_desktop_ref(bd->desktop); } if (!bd->desktop && bd->client.icccm.name) { /* this works for most cases as fallback. useful when app is run from a shell */ bd->desktop = efreet_util_desktop_exec_find(bd->client.icccm.name); } if (!bd->desktop && bd->client.icccm.transient_for) { E_Border *bd2 = e_border_find_by_client_window(bd->client.icccm.transient_for); if (bd2 && bd2->desktop) { efreet_desktop_ref(bd2->desktop); bd->desktop = bd2->desktop; } } if (bd->desktop) { ecore_x_window_prop_string_set(bd->client.win, E_ATOM_DESKTOP_FILE, bd->desktop->orig_path); } bd->icon_object = e_border_icon_add(bd, e_comp_get(bd)->evas); if ((bd->focused) && (bd->icon_object)) edje_object_signal_emit(bd->icon_object, "e,state,focused", "e"); if (bd->bg_object) { evas_object_show(bd->icon_object); edje_object_part_swallow(bd->bg_object, "e.swallow.icon", bd->icon_object); } else evas_object_hide(bd->icon_object); { E_Event_Border_Icon_Change *ev; ev = E_NEW(E_Event_Border_Icon_Change, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_icon_change_event"); ecore_event_add(E_EVENT_BORDER_ICON_CHANGE, ev, _e_border_event_border_icon_change_free, NULL); } bd->changes.icon = 0; } bd->new_client = 0; bd->changed = 0; bd->changes.stack = 0; if ((bd->take_focus) || (bd->want_focus)) { bd->take_focus = 0; if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || (bd->want_focus)) { bd->want_focus = 0; e_border_focus_set_with_pointer(bd); } else if ((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG) || (bd->parent && (bd->parent->modal == bd))) { if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) || ((e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED) && (e_border_find_by_client_window(bd->client.icccm.transient_for) == e_border_focused_get()))) { e_border_focus_set_with_pointer(bd); } } else { /* focus window by default when it is the only one on desk */ E_Border *bd2 = NULL; Eina_List *l; EINA_LIST_FOREACH(focus_stack, l, bd2) { if (bd == bd2) continue; if ((!bd2->iconic) && (bd2->visible) && ((bd->desk == bd2->desk) || bd2->sticky)) break; } if (!bd2) { e_border_focus_set_with_pointer(bd); } } } if (bd->need_maximize) { E_Maximize max; max = bd->maximized; bd->maximized = E_MAXIMIZE_NONE; e_border_maximize(bd, max); bd->need_maximize = 0; } if (bd->need_fullscreen) { e_border_fullscreen(bd, e_config->fullscreen_policy); bd->need_fullscreen = 0; } if (rem_change) e_remember_update(bd); if (send_event) // FIXME: send only if a property changed - above need to { // check on that. for now - always send. event = E_NEW(E_Event_Border_Property, 1); event->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_PROPERTY, event, _e_border_event_border_property_free, NULL); } _e_border_hook_call(E_BORDER_HOOK_EVAL_END, bd); } static void _e_border_moveinfo_gather(E_Border *bd, const char *source) { if (e_util_glob_match(source, "mouse,*,1")) bd->moveinfo.down.button = 1; else if (e_util_glob_match(source, "mouse,*,2")) bd->moveinfo.down.button = 2; else if (e_util_glob_match(source, "mouse,*,3")) bd->moveinfo.down.button = 3; else bd->moveinfo.down.button = 0; if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) { bd->moveinfo.down.mx = bd->mouse.last_down[bd->moveinfo.down.button - 1].mx; bd->moveinfo.down.my = bd->mouse.last_down[bd->moveinfo.down.button - 1].my; } else { bd->moveinfo.down.mx = bd->mouse.current.mx; bd->moveinfo.down.my = bd->mouse.current.my; } } static void _e_border_resize_handle(E_Border *bd) { int x, y, w, h; int new_x, new_y, new_w, new_h; int tw, th; Eina_List *skiplist = NULL; x = bd->x; y = bd->y; w = bd->w; h = bd->h; if ((bd->resize_mode == E_POINTER_RESIZE_TR) || (bd->resize_mode == E_POINTER_RESIZE_R) || (bd->resize_mode == E_POINTER_RESIZE_BR)) { if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) w = bd->mouse.last_down[bd->moveinfo.down.button - 1].w + (bd->mouse.current.mx - bd->moveinfo.down.mx); else w = bd->moveinfo.down.w + (bd->mouse.current.mx - bd->moveinfo.down.mx); } else if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_L) || (bd->resize_mode == E_POINTER_RESIZE_BL)) { if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) w = bd->mouse.last_down[bd->moveinfo.down.button - 1].w - (bd->mouse.current.mx - bd->moveinfo.down.mx); else w = bd->moveinfo.down.w - (bd->mouse.current.mx - bd->moveinfo.down.mx); } if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_T) || (bd->resize_mode == E_POINTER_RESIZE_TR)) { if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) h = bd->mouse.last_down[bd->moveinfo.down.button - 1].h - (bd->mouse.current.my - bd->moveinfo.down.my); else h = bd->moveinfo.down.h - (bd->mouse.current.my - bd->moveinfo.down.my); } else if ((bd->resize_mode == E_POINTER_RESIZE_BL) || (bd->resize_mode == E_POINTER_RESIZE_B) || (bd->resize_mode == E_POINTER_RESIZE_BR)) { if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3)) h = bd->mouse.last_down[bd->moveinfo.down.button - 1].h + (bd->mouse.current.my - bd->moveinfo.down.my); else h = bd->moveinfo.down.h + (bd->mouse.current.my - bd->moveinfo.down.my); } tw = bd->w; th = bd->h; if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_L) || (bd->resize_mode == E_POINTER_RESIZE_BL)) x += (tw - w); if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_T) || (bd->resize_mode == E_POINTER_RESIZE_TR)) y += (th - h); skiplist = eina_list_append(skiplist, bd); e_resist_container_border_position(bd->zone->container, skiplist, bd->x, bd->y, bd->w, bd->h, x, y, w, h, &new_x, &new_y, &new_w, &new_h); eina_list_free(skiplist); w = new_w; h = new_h; e_border_resize_limit(bd, &new_w, &new_h); if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_L) || (bd->resize_mode == E_POINTER_RESIZE_BL)) new_x += (w - new_w); if ((bd->resize_mode == E_POINTER_RESIZE_TL) || (bd->resize_mode == E_POINTER_RESIZE_T) || (bd->resize_mode == E_POINTER_RESIZE_TR)) new_y += (h - new_h); e_border_move_resize(bd, new_x, new_y, new_w, new_h); } static Eina_Bool _e_border_shade_animator(void *data) { E_Border *bd = data; E_Event_Border_Simple *ev; Eina_Bool move = EINA_FALSE; double dt, val; double dur = bd->client.h / e_config->border_shade_speed; dt = ecore_loop_time_get() - bd->shade.start; val = dt / dur; if (val < 0.0) val = 0.0; else if (val > 1.0) val = 1.0; if (e_config->border_shade_transition == E_TRANSITION_SINUSOIDAL) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL, 0.0, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE, 0.0, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_LINEAR) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE_LOTS) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE_FACTOR, 1.7, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE_LOTS) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE_FACTOR, 1.7, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_SINUSOIDAL_LOTS) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL_FACTOR, 1.7, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 3.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE_LOTS) { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 5.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } else { bd->shade.val = ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0); if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val; } /* due to M_PI's innacuracy, cos(M_PI/2) != 0.0, so we need this */ if (bd->shade.val < 0.001) bd->shade.val = 0.0; else if (bd->shade.val > .999) bd->shade.val = 1.0; if (bd->shade.dir == E_DIRECTION_UP) bd->h = bd->client_inset.t + bd->client.h * bd->shade.val; else if (bd->shade.dir == E_DIRECTION_DOWN) { bd->h = bd->client_inset.t + bd->client.h * bd->shade.val; bd->y = bd->shade.y + bd->client.h * (1 - bd->shade.val); move = EINA_TRUE; } else if (bd->shade.dir == E_DIRECTION_LEFT) bd->w = bd->client_inset.t + bd->client.w * bd->shade.val; else if (bd->shade.dir == E_DIRECTION_RIGHT) { bd->w = bd->client_inset.t + bd->client.w * bd->shade.val; bd->x = bd->shade.x + bd->client.w * (1 - bd->shade.val); move = EINA_TRUE; } if (bd->client.shaped) { bd->need_shape_merge = 1; bd->need_shape_export = 1; } if (bd->shaped_input) { bd->need_shape_merge = 1; } BD_CHANGED(bd); /* we're done */ if (val == 1) { bd->shading = 0; bd->shaded = !(bd->shaded); bd->changes.shaded = 1; bd->changes.shading = 1; bd->shade.anim = NULL; if (bd->shaded) edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e"); else edje_object_signal_emit(bd->bg_object, "e,state,unshaded", "e"); edje_object_message_signal_process(bd->bg_object); e_border_frame_recalc(bd); e_border_comp_hidden_set(bd, bd->shaded); } if (move) { ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL); e_container_shape_move(bd->shape, bd->x, bd->y); } e_container_shape_resize(bd->shape, bd->w, bd->h); ev = E_NEW(E_Event_Border_Simple, 1); ev->border = bd; e_object_ref(E_OBJECT(bd)); // e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event"); ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL); return (val != 1); } static void _e_border_event_border_resize_free(void *data __UNUSED__, void *ev) { E_Event_Border_Resize *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_resize_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_move_free(void *data __UNUSED__, void *ev) { E_Event_Border_Move *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_move_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_add_free(void *data __UNUSED__, void *ev) { E_Event_Border_Add *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_add_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_remove_free(void *data __UNUSED__, void *ev) { E_Event_Border_Remove *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_remove_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_show_free(void *data __UNUSED__, void *ev) { E_Event_Border_Show *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_show_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_hide_free(void *data __UNUSED__, void *ev) { E_Event_Border_Hide *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_hide_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_iconify_free(void *data __UNUSED__, void *ev) { E_Event_Border_Iconify *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_iconify_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_uniconify_free(void *data __UNUSED__, void *ev) { E_Event_Border_Uniconify *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_uniconify_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_stick_free(void *data __UNUSED__, void *ev) { E_Event_Border_Stick *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_stick_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_unstick_free(void *data __UNUSED__, void *ev) { E_Event_Border_Unstick *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_unstick_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_zone_set_free(void *data __UNUSED__, void *ev) { E_Event_Border_Zone_Set *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_zone_set_event"); e_object_unref(E_OBJECT(e->border)); e_object_unref(E_OBJECT(e->zone)); E_FREE(e); } static void _e_border_event_border_desk_set_free(void *data __UNUSED__, void *ev) { E_Event_Border_Desk_Set *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_desk_set_event"); e_object_unref(E_OBJECT(e->border)); e_object_unref(E_OBJECT(e->desk)); E_FREE(e); } static void _e_border_event_border_stack_free(void *data __UNUSED__, void *ev) { E_Event_Border_Stack *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_raise_event"); e_object_unref(E_OBJECT(e->border)); if (e->stack) { // e_object_breadcrumb_del(E_OBJECT(e->above), "border_raise_event.above"); e_object_unref(E_OBJECT(e->stack)); } E_FREE(e); } static void _e_border_event_border_icon_change_free(void *data __UNUSED__, void *ev) { E_Event_Border_Icon_Change *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_icon_change_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_title_change_free(void *data __UNUSED__, void *ev) { E_Event_Border_Title_Change *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_icon_change_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_urgent_change_free(void *data __UNUSED__, void *ev) { E_Event_Border_Urgent_Change *e; e = ev; e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_focus_in_free(void *data __UNUSED__, void *ev) { E_Event_Border_Focus_In *e; e = ev; e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_focus_out_free(void *data __UNUSED__, void *ev) { E_Event_Border_Focus_Out *e; e = ev; e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_property_free(void *data __UNUSED__, void *ev) { E_Event_Border_Property *e; e = ev; e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_fullscreen_free(void *data __UNUSED__, void *ev) { E_Event_Border_Fullscreen *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_fullscreen_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_event_border_unfullscreen_free(void *data __UNUSED__, void *ev) { E_Event_Border_Unfullscreen *e; e = ev; // e_object_breadcrumb_del(E_OBJECT(e->border), "border_unfullscreen_event"); e_object_unref(E_OBJECT(e->border)); E_FREE(e); } static void _e_border_zone_update(E_Border *bd) { E_Container *con; Eina_List *l; E_Zone *zone; /* still within old zone - leave it there */ if (E_INTERSECTS(bd->x, bd->y, bd->w, bd->h, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h)) return; /* find a new zone */ con = bd->zone->container; EINA_LIST_FOREACH(con->zones, l, zone) { if (E_INTERSECTS(bd->x, bd->y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h)) { e_border_zone_set(bd, zone); return; } } } static int _e_border_resize_begin(E_Border *bd) { if (!bd->lock_user_stacking) { if (e_config->border_raise_on_mouse_action) e_border_raise(bd); } if ((bd->shaded) || (bd->shading) || (bd->fullscreen) || (bd->lock_user_size)) return 0; if (grabbed && !e_grabinput_get(bd->win, 0, bd->win)) { grabbed = 0; return 0; } if (bd->client.netwm.sync.request) { bd->client.netwm.sync.alarm = ecore_x_sync_alarm_new(bd->client.netwm.sync.counter); bd->client.netwm.sync.serial = 1; bd->client.netwm.sync.wait = 0; bd->client.netwm.sync.send_time = ecore_loop_time_get(); } _e_border_hook_call(E_BORDER_HOOK_RESIZE_BEGIN, bd); bdresize = bd; return 1; } static int _e_border_resize_end(E_Border *bd) { if (grabbed) { e_grabinput_release(bd->win, bd->win); grabbed = 0; } if (bd->client.netwm.sync.alarm) { E_Border_Pending_Move_Resize *pnd; ecore_x_sync_alarm_free(bd->client.netwm.sync.alarm); bd->client.netwm.sync.alarm = 0; /* resize to last geometry if sync alarm for it was not yet handled */ if (bd->pending_move_resize) { BD_CHANGED(bd); bd->changes.pos = 1; bd->changes.size = 1; _e_border_client_move_resize_send(bd); } EINA_LIST_FREE(bd->pending_move_resize, pnd) E_FREE(pnd); } e_pointer_mode_pop(bd, bd->resize_mode); bd->resize_mode = E_POINTER_RESIZE_NONE; _e_border_hook_call(E_BORDER_HOOK_RESIZE_END, bd); bdresize = NULL; /* If this border was maximized, we need to unset Maximized state or * on restart, E still thinks it's maximized */ if (bd->maximized != E_MAXIMIZE_NONE) e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_NONE, bd->maximized & E_MAXIMIZE_NONE); return 1; } static void _e_border_resize_update(E_Border *bd) { _e_border_hook_call(E_BORDER_HOOK_RESIZE_UPDATE, bd); } static int _e_border_move_begin(E_Border *bd) { if (!bd->lock_user_stacking) { if (e_config->border_raise_on_mouse_action) e_border_raise(bd); } if ((bd->fullscreen) || (bd->lock_user_location)) return 0; if (grabbed && !e_grabinput_get(bd->win, 0, bd->win)) { grabbed = 0; return 0; } #if 0 if (bd->client.netwm.sync.request) { bd->client.netwm.sync.alarm = ecore_x_sync_alarm_new(bd->client.netwm.sync.counter); bd->client.netwm.sync.serial = 0; bd->client.netwm.sync.wait = 0; bd->client.netwm.sync.time = ecore_loop_time_get(); } #endif _e_border_hook_call(E_BORDER_HOOK_MOVE_BEGIN, bd); bdmove = bd; return 1; } static int _e_border_move_end(E_Border *bd) { if (grabbed) { e_grabinput_release(bd->win, bd->win); grabbed = 0; } #if 0 if (bd->client.netwm.sync.alarm) { ecore_x_sync_alarm_free(bd->client.netwm.sync.alarm); bd->client.netwm.sync.alarm = 0; } #endif e_pointer_mode_pop(bd, E_POINTER_MOVE); bd->moving = 0; _e_border_hook_call(E_BORDER_HOOK_MOVE_END, bd); bdmove = NULL; return 1; } static void _e_border_move_update(E_Border *bd) { _e_border_hook_call(E_BORDER_HOOK_MOVE_UPDATE, bd); } static Eina_Bool _e_border_cb_ping_poller(void *data) { E_Border *bd; bd = data; if (bd->ping_ok) { if (bd->hung) { bd->hung = 0; edje_object_signal_emit(bd->bg_object, "e,state,unhung", "e"); if (bd->kill_timer) { ecore_timer_del(bd->kill_timer); bd->kill_timer = NULL; } } } else { /* if time between last ping and now is greater * than half the ping interval... */ if ((ecore_loop_time_get() - bd->ping) > ((e_config->ping_clients_interval * ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0)) { if (!bd->hung) { bd->hung = 1; edje_object_signal_emit(bd->bg_object, "e,state,hung", "e"); /* FIXME: if below dialog is up - hide it now */ } if (bd->delete_requested) { /* FIXME: pop up dialog saying app is hung - kill client, or pid */ e_border_act_kill_begin(bd); } } } bd->ping_poller = NULL; e_border_ping(bd); return ECORE_CALLBACK_CANCEL; } static Eina_Bool _e_border_cb_kill_timer(void *data) { E_Border *bd; bd = data; // dont wait until it's hung - // if (bd->hung) // { if (bd->client.netwm.pid > 1) kill(bd->client.netwm.pid, SIGKILL); // } bd->kill_timer = NULL; return ECORE_CALLBACK_CANCEL; } static Eina_List *_e_border_hooks = NULL; static int _e_border_hooks_delete = 0; static int _e_border_hooks_walking = 0; static void _e_border_hooks_clean(void) { Eina_List *l, *ln; E_Border_Hook *bh; EINA_LIST_FOREACH_SAFE(_e_border_hooks, l, ln, bh) { if (bh->delete_me) { _e_border_hooks = eina_list_remove_list(_e_border_hooks, l); free(bh); } } } static void _e_border_hook_call(E_Border_Hook_Point hookpoint, void *bd) { Eina_List *l; E_Border_Hook *bh; _e_border_hooks_walking++; EINA_LIST_FOREACH(_e_border_hooks, l, bh) { if (bh->delete_me) continue; if (bh->hookpoint == hookpoint) bh->func(bh->data, bd); } _e_border_hooks_walking--; if ((_e_border_hooks_walking == 0) && (_e_border_hooks_delete > 0)) _e_border_hooks_clean(); } EAPI E_Border_Hook * e_border_hook_add(E_Border_Hook_Point hookpoint, void (*func)(void *data, void *bd), void *data) { E_Border_Hook *bh; bh = E_NEW(E_Border_Hook, 1); if (!bh) return NULL; bh->hookpoint = hookpoint; bh->func = func; bh->data = data; _e_border_hooks = eina_list_append(_e_border_hooks, bh); return bh; } EAPI void e_border_hook_del(E_Border_Hook *bh) { bh->delete_me = 1; if (_e_border_hooks_walking == 0) { _e_border_hooks = eina_list_remove(_e_border_hooks, bh); free(bh); } else _e_border_hooks_delete++; } EAPI void e_border_focus_track_freeze(void) { focus_track_frozen++; } EAPI void e_border_focus_track_thaw(void) { focus_track_frozen--; } static E_Border * _e_border_under_pointer_helper(E_Desk *desk, E_Border *exclude, int x, int y) { E_Border *bd = NULL, *cbd; Eina_List *l; EINA_LIST_FOREACH(e_border_raise_stack_get(), l, cbd) { if (!cbd) continue; /* If a border was specified which should be excluded from the list * (because it will be closed shortly for example), skip */ if ((exclude) && (cbd == exclude)) continue; if ((desk) && (cbd->desk != desk)) continue; if (!E_INSIDE(x, y, cbd->x, cbd->y, cbd->w, cbd->h)) continue; /* If the layer is higher, the position of the window is higher * (always on top vs always below) */ if (!bd || (cbd->layer > bd->layer)) { bd = cbd; break; } } return bd; } EAPI E_Border * e_border_under_pointer_get(E_Desk *desk, E_Border *exclude) { int x, y; /* We need to ensure that we can get the container window for the * zone of either the given desk or the desk of the excluded * window, so return if neither is given */ if (desk) ecore_x_pointer_xy_get(desk->zone->container->win, &x, &y); else if (exclude) ecore_x_pointer_xy_get(exclude->desk->zone->container->win, &x, &y); else return NULL; return _e_border_under_pointer_helper(desk, exclude, x, y); } static Eina_Bool _e_border_pointer_warp_to_center_timer(void *data __UNUSED__) { if (warp_to) { int x, y; double spd; ecore_x_pointer_xy_get(warp_to_win, &x, &y); /* move hasn't happened yet */ if ((x == warp_x[1]) && (y == warp_y[1])) return EINA_TRUE; if ((abs(x - warp_x[0]) > 5) || (abs(y - warp_y[0]) > 5)) { /* User moved the mouse, so stop warping */ warp_to = 0; goto cleanup; } spd = e_config->pointer_warp_speed; warp_x[1] = x = warp_x[0]; warp_y[1] = y = warp_y[0]; warp_x[0] = (x * (1.0 - spd)) + (warp_to_x * spd); warp_y[0] = (y * (1.0 - spd)) + (warp_to_y * spd); if ((warp_x[0] == x) && (warp_y[0] == y)) { warp_x[0] = warp_to_x; warp_y[0] = warp_to_y; warp_to = 0; goto cleanup; } ecore_x_pointer_warp(warp_to_win, warp_x[0], warp_y[0]); return ECORE_CALLBACK_RENEW; } cleanup: if (warp_timer) ecore_timer_del(warp_timer); warp_timer = NULL; e_border_focus_lock_set(EINA_FALSE); if (warp_timer_border) { warp_x[0] = warp_x[1] = warp_y[0] = warp_y[1] = -1; if (warp_timer_border->modal) { /* got a modal dialog during pointer warp...whoops */ e_border_raise(warp_timer_border->modal); warp_timer_border = NULL; return ECORE_CALLBACK_CANCEL; } e_focus_event_mouse_in(warp_timer_border); if (warp_timer_border->iconic) { if (!warp_timer_border->lock_user_iconify) e_border_uniconify(warp_timer_border); } if (warp_timer_border->shaded) { if (!warp_timer_border->lock_user_shade) e_border_unshade(warp_timer_border, warp_timer_border->shade.dir); } if (!warp_timer_border->lock_user_stacking) e_border_raise(warp_timer_border); if (!warp_timer_border->lock_focus_out) { e_border_focus_set(warp_timer_border, 1, 1); e_border_focus_latest_set(warp_timer_border); } warp_timer_border = NULL; } return ECORE_CALLBACK_CANCEL; } EAPI int e_border_pointer_warp_to_center_now(E_Border *bd) { if (e_config->disable_all_pointer_warps) return 0; if (warp_timer_border == bd) { ecore_x_pointer_warp(warp_to_win, warp_to_x, warp_to_y); warp_to = 0; } else { if (e_border_pointer_warp_to_center(bd)) e_border_pointer_warp_to_center_now(bd); } return 1; } EAPI int e_border_pointer_warp_to_center(E_Border *bd) { int x, y; E_Border *cbd = NULL; if (e_config->disable_all_pointer_warps) return 0; /* Only warp the pointer if it is not already in the area of * the given border */ ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y); if ((x >= bd->x) && (x <= (bd->x + bd->w)) && (y >= bd->y) && (y <= (bd->y + bd->h))) { cbd = _e_border_under_pointer_helper(bd->desk, bd, x, y); if (cbd == bd) return 0; } warp_to_x = bd->x + (bd->w / 2); if (warp_to_x < (bd->zone->x + 1)) warp_to_x = bd->zone->x + ((bd->x + bd->w - bd->zone->x) / 2); else if (warp_to_x > (bd->zone->x + bd->zone->w)) warp_to_x = (bd->zone->x + bd->zone->w + bd->x) / 2; warp_to_y = bd->y + (bd->h / 2); if (warp_to_y < (bd->zone->y + 1)) warp_to_y = bd->zone->y + ((bd->y + bd->h - bd->zone->y) / 2); else if (warp_to_y > (bd->zone->y + bd->zone->h)) warp_to_y = (bd->zone->y + bd->zone->h + bd->y) / 2; /* TODO: handle case where another border is over the exact center, * find a place where the requested border is not overlapped? * if (!cbd) cbd = _e_border_under_pointer_helper(bd->desk, bd, x, y); if (cbd != bd) { } */ warp_to = 1; warp_to_win = bd->zone->container->win; ecore_x_pointer_xy_get(bd->zone->container->win, &warp_x[0], &warp_y[0]); if (warp_timer) ecore_timer_del(warp_timer); warp_timer = ecore_timer_add(0.01, _e_border_pointer_warp_to_center_timer, bd); warp_timer_border = bd; e_border_focus_lock_set(EINA_TRUE); return 1; } EAPI void e_border_comp_hidden_set(E_Border *bd, Eina_Bool hidden) { E_Border *tmp; Eina_List *l; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) { if (hidden) ecore_x_window_hide(tmp->win); else ecore_x_window_show(tmp->win); } if (bd->comp_hidden == hidden) return; bd->comp_hidden = hidden; if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0)) { ecore_x_composite_window_events_disable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_TRUE); } else { ecore_x_composite_window_events_enable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_FALSE); } } EAPI void e_border_tmp_input_hidden_push(E_Border *bd) { E_Border *tmp; Eina_List *l; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) e_border_tmp_input_hidden_push(tmp); bd->tmp_input_hidden++; if (bd->tmp_input_hidden != 1) return; if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0)) { ecore_x_composite_window_events_disable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_TRUE); } else { _e_border_shape_input_rectangle_set(bd); ecore_x_window_ignore_set(bd->win, EINA_FALSE); } } EAPI void e_border_tmp_input_hidden_pop(E_Border *bd) { E_Border *tmp; Eina_List *l; E_OBJECT_CHECK(bd); E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE); EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp) e_border_tmp_input_hidden_pop(tmp); bd->tmp_input_hidden--; if (bd->tmp_input_hidden != 0) return; if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0)) { ecore_x_composite_window_events_disable(bd->win); ecore_x_window_ignore_set(bd->win, EINA_TRUE); } else { _e_border_shape_input_rectangle_set(bd); ecore_x_window_ignore_set(bd->win, EINA_FALSE); } } EAPI void e_border_activate(E_Border *bd, Eina_Bool just_do_it) { if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || ((bd->parent) && ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) || ((bd->parent->focused) && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))) || (just_do_it)) { if (bd->iconic) { if (e_config->clientlist_warp_to_iconified_desktop == 1) e_desk_show(bd->desk); if (!bd->lock_user_iconify) e_border_uniconify(bd); } if ((!bd->iconic) && (!bd->sticky)) e_desk_show(bd->desk); if (!bd->lock_user_stacking) e_border_raise(bd); if (!bd->lock_focus_out) { /* XXX ooffice does send this request for config dialogs when the main window gets focus. causing the pointer to jump back and forth. */ if ((e_config->focus_policy != E_FOCUS_CLICK) && (!bd->new_client) && (!e_config->disable_all_pointer_warps) && !(bd->client.icccm.name && !strcmp(bd->client.icccm.name, "VCLSalFrame"))) ecore_x_pointer_warp(bd->zone->container->win, bd->x + (bd->w / 2), bd->y + (bd->h / 2)); e_border_focus_set(bd, 1, 1); } } } /*vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0*/