void actions_client_move(ObActionsData *data, gboolean start) { static gulong ignore_start = 0; if (start) ignore_start = event_start_ignore_all_enters(); else if (config_focus_follow && data->context != OB_FRAME_CONTEXT_CLIENT) { if (data->uact == OB_USER_ACTION_MOUSE_PRESS) { struct _ObClient *c; syslog(LOG_INFO,"client move"); /* usually this is sorta redundant, but with a press action that moves windows our from under the cursor, the enter event will come as a GrabNotify which is ignored, so this makes a fake enter event don't do this if there is a grab on the pointer. enter events are ignored during a grab, so don't force fake ones when they should be ignored */ if ((c = client_under_pointer()) && c != data->client && !grab_on_pointer()) { ob_debug_type(OB_DEBUG_FOCUS, "Generating fake enter because we did a " "mouse-event action"); event_enter_client(c); } } else if (!data->button && !config_focus_under_mouse) event_end_ignore_all_enters(ignore_start); } }
void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client) { ObMenu *self; ObMenuFrame *frame; if (!(self = menu_from_name(name)) || grab_on_keyboard() || grab_on_pointer()) return; /* if the requested menu is already the top visible menu, then don't bother */ if (menu_frame_visible) { frame = menu_frame_visible->data; if (frame->menu == self) return; } menu_frame_hide_all(); /* clear the pipe menus when showing a new menu */ menu_clear_pipe_caches(); frame = menu_frame_new(self, 0, client); if (!menu_frame_show_topmenu(frame, x, y, mouse)) menu_frame_free(frame); else { if (!mouse) { /* select the first entry if it's not a submenu and we opened * the menu with the keyboard, and skip all headers */ GList *it = frame->entries; while (it) { ObMenuEntryFrame *e = it->data; if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { menu_frame_select(frame, e, FALSE); break; } else if (e->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR) it = g_list_next(it); else break; } } /* reset the hide timer */ if (!mouse) menu_can_hide = TRUE; else { menu_can_hide = FALSE; obt_main_loop_timeout_add(ob_main_loop, config_menu_hide_delay * 1000, menu_hide_delay_func, NULL, g_direct_equal, NULL); } } }
void mouse_event(ObClient *client, XEvent *e) { static Time ltime; static guint button = 0, state = 0, lbutton = 0; static Window lwindow = None; static gint px, py, pwx = -1, pwy = -1; ObFrameContext context; gboolean click = FALSE; gboolean dclick = FALSE; switch (e->type) { case ButtonPress: context = frame_context(client, e->xbutton.window, e->xbutton.x, e->xbutton.y); context = mouse_button_frame_context(context, e->xbutton.button, e->xbutton.state); px = e->xbutton.x_root; py = e->xbutton.y_root; if (!button) pwx = e->xbutton.x; if (!button) pwy = e->xbutton.y; button = e->xbutton.button; state = e->xbutton.state; /* if the binding was in a client context, then we need to call XAllowEvents with ReplayPointer at some point, to send the event through to the client. when this happens though depends. if windows are going to be moved on screen, then the click will end up going somewhere wrong, set that we need it, and if nothing else causes the replay pointer to be run, then we will do it after all the actions are finished. (We do it after all the actions because FocusIn interrupts dragging for kdesktop, so if we send the button event now, and then they get a focus event after, it breaks. Instead, wait to send the button press until after the actions when possible.) */ if (CLIENT_CONTEXT(context, client)) replay_pointer_needed = TRUE; fire_binding(OB_MOUSE_ACTION_PRESS, context, client, e->xbutton.state, e->xbutton.button, e->xbutton.x_root, e->xbutton.y_root); /* if the bindings grab the pointer, there won't be a ButtonRelease event for us */ if (grab_on_pointer()) button = 0; /* replay the pointer event if it hasn't been replayed yet (i.e. no windows were moved) */ mouse_replay_pointer(); /* in the client context, we won't get a button release because of the way it is grabbed, so just fake one */ if (!CLIENT_CONTEXT(context, client)) break; case ButtonRelease: /* use where the press occured in the window */ context = frame_context(client, e->xbutton.window, pwx, pwy); context = mouse_button_frame_context(context, e->xbutton.button, e->xbutton.state); if (e->xbutton.button == button) pwx = pwy = -1; if (e->xbutton.button == button) { /* clicks are only valid if its released over the window */ gint junk1, junk2; Window wjunk; guint ujunk, b, w, h; /* this can cause errors to occur when the window closes */ xerror_set_ignore(TRUE); junk1 = XGetGeometry(ob_display, e->xbutton.window, &wjunk, &junk1, &junk2, &w, &h, &b, &ujunk); xerror_set_ignore(FALSE); if (junk1) { if (e->xbutton.x >= (signed)-b && e->xbutton.y >= (signed)-b && e->xbutton.x < (signed)(w+b) && e->xbutton.y < (signed)(h+b)) { click = TRUE; /* double clicks happen if there were 2 in a row! */ if (lbutton == button && lwindow == e->xbutton.window && e->xbutton.time - config_mouse_dclicktime <= ltime) { dclick = TRUE; lbutton = 0; } else { lbutton = button; lwindow = e->xbutton.window; } } else { lbutton = 0; lwindow = None; } } button = 0; state = 0; ltime = e->xbutton.time; } fire_binding(OB_MOUSE_ACTION_RELEASE, context, client, e->xbutton.state, e->xbutton.button, e->xbutton.x_root, e->xbutton.y_root); if (click) fire_binding(OB_MOUSE_ACTION_CLICK, context, client, e->xbutton.state, e->xbutton.button, e->xbutton.x_root, e->xbutton.y_root); if (dclick) fire_binding(OB_MOUSE_ACTION_DOUBLE_CLICK, context, client, e->xbutton.state, e->xbutton.button, e->xbutton.x_root, e->xbutton.y_root); break; case MotionNotify: if (button) { context = frame_context(client, e->xmotion.window, pwx, pwy); context = mouse_button_frame_context(context, button, state); if (ABS(e->xmotion.x_root - px) >= config_mouse_threshold || ABS(e->xmotion.y_root - py) >= config_mouse_threshold) { /* You can't drag on buttons */ if (context == OB_FRAME_CONTEXT_MAXIMIZE || context == OB_FRAME_CONTEXT_ALLDESKTOPS || context == OB_FRAME_CONTEXT_SHADE || context == OB_FRAME_CONTEXT_ICONIFY || context == OB_FRAME_CONTEXT_ICON || context == OB_FRAME_CONTEXT_CLOSE) break; fire_binding(OB_MOUSE_ACTION_MOTION, context, client, state, button, px, py); button = 0; state = 0; } } break; default: g_assert_not_reached(); } }