/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- action.c for the Openbox window manager Copyright (c) 2006 Mikael Magnusson Copyright (c) 2003-2007 Dana Jansens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the COPYING file for a copy of the GNU General Public License. */ #include "debug.h" #include "client.h" #include "focus.h" #include "moveresize.h" #include "menu.h" #include "prop.h" #include "stacking.h" #include "screen.h" #include "action.h" #include "openbox.h" #include "grab.h" #include "keyboard.h" #include "event.h" #include "dock.h" #include "config.h" #include "mainloop.h" #include "startupnotify.h" #include "gettext.h" #include inline void client_action_start(union ActionData *data) { if (config_focus_follow) if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button) grab_pointer(FALSE, FALSE, OB_CURSOR_NONE); } inline void client_action_end(union ActionData *data) { if (config_focus_follow) if (data->any.context != OB_FRAME_CONTEXT_CLIENT) { if (!data->any.button) { ungrab_pointer(); } else { ObClient *c; /* 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 */ if ((c = client_under_pointer())) event_enter_client(c); } } } typedef struct { const gchar *name; void (*func)(union ActionData *); void (*setup)(ObAction **, ObUserAction uact); } ActionString; static ObAction *action_new(void (*func)(union ActionData *data)) { ObAction *a = g_new0(ObAction, 1); a->ref = 1; a->func = func; return a; } void action_ref(ObAction *a) { ++a->ref; } void action_unref(ObAction *a) { if (a == NULL) return; if (--a->ref > 0) return; /* deal with pointers */ if (a->func == action_execute || a->func == action_restart) g_free(a->data.execute.path); else if (a->func == action_debug) g_free(a->data.debug.string); else if (a->func == action_showmenu) g_free(a->data.showmenu.name); g_free(a); } ObAction* action_copy(const ObAction *src) { ObAction *a = action_new(src->func); a->data = src->data; /* deal with pointers */ if (a->func == action_execute || a->func == action_restart) a->data.execute.path = g_strdup(a->data.execute.path); else if (a->func == action_debug) a->data.debug.string = g_strdup(a->data.debug.string); else if (a->func == action_showmenu) a->data.showmenu.name = g_strdup(a->data.showmenu.name); return a; } void setup_action_directional_focus_north(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_east(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_EAST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_south(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_west(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_WEST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact) { (*a)->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST; (*a)->data.interdiraction.dialog = TRUE; (*a)->data.interdiraction.dock_windows = FALSE; (*a)->data.interdiraction.desktop_windows = FALSE; } void setup_action_send_to_desktop(ObAction **a, ObUserAction uact) { (*a)->data.sendto.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendto.follow = TRUE; } void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_WEST; (*a)->data.sendtodir.linear = TRUE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_EAST; (*a)->data.sendtodir.linear = TRUE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_WEST; (*a)->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_EAST; (*a)->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH; (*a)->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact) { (*a)->data.sendtodir.inter.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH; (*a)->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.follow = TRUE; } void setup_action_desktop(ObAction **a, ObUserAction uact) { /* (*a)->data.desktop.inter.any.interactive = FALSE; */ } void setup_action_desktop_prev(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_WEST; (*a)->data.desktopdir.linear = TRUE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_desktop_next(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_EAST; (*a)->data.desktopdir.linear = TRUE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_desktop_left(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_WEST; (*a)->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_desktop_right(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_EAST; (*a)->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_desktop_up(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH; (*a)->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_desktop_down(ObAction **a, ObUserAction uact) { (*a)->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH; (*a)->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.wrap = TRUE; } void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact) { (*a)->data.cycle.inter.any.interactive = TRUE; (*a)->data.cycle.linear = FALSE; (*a)->data.cycle.forward = TRUE; (*a)->data.cycle.dialog = TRUE; (*a)->data.cycle.dock_windows = FALSE; (*a)->data.cycle.desktop_windows = FALSE; (*a)->data.cycle.all_desktops = FALSE; } void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact) { (*a)->data.cycle.inter.any.interactive = TRUE; (*a)->data.cycle.linear = FALSE; (*a)->data.cycle.forward = FALSE; (*a)->data.cycle.dialog = TRUE; (*a)->data.cycle.dock_windows = FALSE; (*a)->data.cycle.desktop_windows = FALSE; (*a)->data.cycle.all_desktops = FALSE; } void setup_action_movefromedge_north(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_NORTH; (*a)->data.diraction.hang = TRUE; } void setup_action_movefromedge_south(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_SOUTH; (*a)->data.diraction.hang = TRUE; } void setup_action_movefromedge_east(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_EAST; (*a)->data.diraction.hang = TRUE; } void setup_action_movefromedge_west(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_WEST; (*a)->data.diraction.hang = TRUE; } void setup_action_movetoedge_north(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_NORTH; (*a)->data.diraction.hang = FALSE; } void setup_action_movetoedge_south(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_SOUTH; (*a)->data.diraction.hang = FALSE; } void setup_action_movetoedge_east(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_EAST; (*a)->data.diraction.hang = FALSE; } void setup_action_movetoedge_west(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_WEST; (*a)->data.diraction.hang = FALSE; } void setup_action_growtoedge_north(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_NORTH; } void setup_action_growtoedge_south(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_SOUTH; } void setup_action_growtoedge_east(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_EAST; } void setup_action_growtoedge_west(ObAction **a, ObUserAction uact) { (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.diraction.direction = OB_DIRECTION_WEST; } void setup_action_top_layer(ObAction **a, ObUserAction uact) { (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.layer.layer = 1; } void setup_action_normal_layer(ObAction **a, ObUserAction uact) { (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.layer.layer = 0; } void setup_action_bottom_layer(ObAction **a, ObUserAction uact) { (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.layer.layer = -1; } void setup_action_move(ObAction **a, ObUserAction uact) { (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.moveresize.keyboard = (uact == OB_USER_ACTION_NONE || uact == OB_USER_ACTION_KEYBOARD_KEY || uact == OB_USER_ACTION_MENU_SELECTION); (*a)->data.moveresize.corner = 0; } void setup_action_resize(ObAction **a, ObUserAction uact) { (*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS; (*a)->data.moveresize.keyboard = (uact == OB_USER_ACTION_NONE || uact == OB_USER_ACTION_KEYBOARD_KEY || uact == OB_USER_ACTION_MENU_SELECTION); (*a)->data.moveresize.corner = 0; } void setup_action_showmenu(ObAction **a, ObUserAction uact) { (*a)->data.showmenu.any.client_action = OB_CLIENT_ACTION_OPTIONAL; /* you cannot call ShowMenu from inside a menu, cuz the menu code makes assumptions that there is only one menu (and submenus) open at a time! */ if (uact == OB_USER_ACTION_MENU_SELECTION) { action_unref(*a); *a = NULL; } } void setup_action_focus(ObAction **a, ObUserAction uact) { (*a)->data.any.client_action = OB_CLIENT_ACTION_OPTIONAL; } void setup_client_action(ObAction **a, ObUserAction uact) { (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS; } ActionString actionstrings[] = { { "debug", action_debug, NULL }, { "execute", action_execute, NULL }, { "directionalfocusnorth", action_directional_focus, setup_action_directional_focus_north }, { "directionalfocuseast", action_directional_focus, setup_action_directional_focus_east }, { "directionalfocussouth", action_directional_focus, setup_action_directional_focus_south }, { "directionalfocuswest", action_directional_focus, setup_action_directional_focus_west }, { "directionalfocusnortheast", action_directional_focus, setup_action_directional_focus_northeast }, { "directionalfocussoutheast", action_directional_focus, setup_action_directional_focus_southeast }, { "directionalfocussouthwest", action_directional_focus, setup_action_directional_focus_southwest }, { "directionalfocusnorthwest", action_directional_focus, setup_action_directional_focus_northwest }, { "activate", action_activate, setup_action_focus }, { "focus", action_focus, setup_action_focus }, { "unfocus", action_unfocus, setup_client_action }, { "iconify", action_iconify, setup_client_action }, { "focustobottom", action_focus_order_to_bottom, setup_client_action }, { "raiselower", action_raiselower, setup_client_action }, { "raise", action_raise, setup_client_action }, { "lower", action_lower, setup_client_action }, { "close", action_close, setup_client_action }, { "kill", action_kill, setup_client_action }, { "shadelower", action_shadelower, setup_client_action }, { "unshaderaise", action_unshaderaise, setup_client_action }, { "shade", action_shade, setup_client_action }, { "unshade", action_unshade, setup_client_action }, { "toggleshade", action_toggle_shade, setup_client_action }, { "toggleomnipresent", action_toggle_omnipresent, setup_client_action }, { "moverelativehorz", action_move_relative_horz, setup_client_action }, { "moverelativevert", action_move_relative_vert, setup_client_action }, { "movetocenter", action_move_to_center, setup_client_action }, { "resizerelativehorz", action_resize_relative_horz, setup_client_action }, { "resizerelativevert", action_resize_relative_vert, setup_client_action }, { "moverelative", action_move_relative, setup_client_action }, { "resizerelative", action_resize_relative, setup_client_action }, { "maximizefull", action_maximize_full, setup_client_action }, { "unmaximizefull", action_unmaximize_full, setup_client_action }, { "togglemaximizefull", action_toggle_maximize_full, setup_client_action }, { "maximizehorz", action_maximize_horz, setup_client_action }, { "unmaximizehorz", action_unmaximize_horz, setup_client_action }, { "togglemaximizehorz", action_toggle_maximize_horz, setup_client_action }, { "maximizevert", action_maximize_vert, setup_client_action }, { "unmaximizevert", action_unmaximize_vert, setup_client_action }, { "togglemaximizevert", action_toggle_maximize_vert, setup_client_action }, { "togglefullscreen", action_toggle_fullscreen, setup_client_action }, { "sendtodesktop", action_send_to_desktop, setup_action_send_to_desktop }, { "sendtodesktopnext", action_send_to_desktop_dir, setup_action_send_to_desktop_next }, { "sendtodesktopprevious", action_send_to_desktop_dir, setup_action_send_to_desktop_prev }, { "sendtodesktopright", action_send_to_desktop_dir, setup_action_send_to_desktop_right }, { "sendtodesktopleft", action_send_to_desktop_dir, setup_action_send_to_desktop_left }, { "sendtodesktopup", action_send_to_desktop_dir, setup_action_send_to_desktop_up }, { "sendtodesktopdown", action_send_to_desktop_dir, setup_action_send_to_desktop_down }, { "desktop", action_desktop, setup_action_desktop }, { "desktopnext", action_desktop_dir, setup_action_desktop_next }, { "desktopprevious", action_desktop_dir, setup_action_desktop_prev }, { "desktopright", action_desktop_dir, setup_action_desktop_right }, { "desktopleft", action_desktop_dir, setup_action_desktop_left }, { "desktopup", action_desktop_dir, setup_action_desktop_up }, { "desktopdown", action_desktop_dir, setup_action_desktop_down }, { "toggledecorations", action_toggle_decorations, setup_client_action }, { "move", action_move, setup_action_move }, { "resize", action_resize, setup_action_resize }, { "toggledockautohide", action_toggle_dockautohide, NULL }, { "toggleshowdesktop", action_toggle_show_desktop, NULL }, { "showdesktop", action_show_desktop, NULL }, { "unshowdesktop", action_unshow_desktop, NULL }, { "desktoplast", action_desktop_last, NULL }, { "reconfigure", action_reconfigure, NULL }, { "restart", action_restart, NULL }, { "exit", action_exit, NULL }, { "showmenu", action_showmenu, setup_action_showmenu }, { "sendtotoplayer", action_send_to_layer, setup_action_top_layer }, { "togglealwaysontop", action_toggle_layer, setup_action_top_layer }, { "sendtonormallayer", action_send_to_layer, setup_action_normal_layer }, { "sendtobottomlayer", action_send_to_layer, setup_action_bottom_layer }, { "togglealwaysonbottom", action_toggle_layer, setup_action_bottom_layer }, { "nextwindow", action_cycle_windows, setup_action_cycle_windows_next }, { "previouswindow", action_cycle_windows, setup_action_cycle_windows_previous }, { "movefromedgenorth", action_movetoedge, setup_action_movefromedge_north }, { "movefromedgesouth", action_movetoedge, setup_action_movefromedge_south }, { "movefromedgewest", action_movetoedge, setup_action_movefromedge_west }, { "movefromedgeeast", action_movetoedge, setup_action_movefromedge_east }, { "movetoedgenorth", action_movetoedge, setup_action_movetoedge_north }, { "movetoedgesouth", action_movetoedge, setup_action_movetoedge_south }, { "movetoedgewest", action_movetoedge, setup_action_movetoedge_west }, { "movetoedgeeast", action_movetoedge, setup_action_movetoedge_east }, { "growtoedgenorth", action_growtoedge, setup_action_growtoedge_north }, { "growtoedgesouth", action_growtoedge, setup_action_growtoedge_south }, { "growtoedgewest", action_growtoedge, setup_action_growtoedge_west }, { "growtoedgeeast", action_growtoedge, setup_action_growtoedge_east }, { "breakchroot", action_break_chroot, NULL }, { NULL, NULL, NULL } }; /* only key bindings can be interactive. thus saith the xor. because of how the mouse is grabbed, mouse events dont even get read during interactive events, so no dice! >:) */ #define INTERACTIVE_LIMIT(a, uact) \ if (uact != OB_USER_ACTION_KEYBOARD_KEY) \ a->data.any.interactive = FALSE; ObAction *action_from_string(const gchar *name, ObUserAction uact) { ObAction *a = NULL; gboolean exist = FALSE; gint i; for (i = 0; actionstrings[i].name; i++) if (!g_ascii_strcasecmp(name, actionstrings[i].name)) { exist = TRUE; a = action_new(actionstrings[i].func); if (actionstrings[i].setup) actionstrings[i].setup(&a, uact); if (a) INTERACTIVE_LIMIT(a, uact); break; } if (!exist) g_message(_("Invalid action '%s' requested. No such action exists."), name); if (!a) g_message(_("Invalid use of action '%s'. Action will be ignored."), name); return a; } ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, ObUserAction uact) { gchar *actname; ObAction *act = NULL; xmlNodePtr n; if (parse_attr_string("name", node, &actname)) { if ((act = action_from_string(actname, uact))) { if (act->func == action_execute || act->func == action_restart) { if ((n = parse_find_node("execute", node->xmlChildrenNode))) { gchar *s = parse_string(doc, n); act->data.execute.path = parse_expand_tilde(s); g_free(s); } if ((n = parse_find_node("startupnotify", node->xmlChildrenNode))) { xmlNodePtr m; if ((m = parse_find_node("enabled", n->xmlChildrenNode))) act->data.execute.startupnotify = parse_bool(doc, m); if ((m = parse_find_node("name", n->xmlChildrenNode))) act->data.execute.name = parse_string(doc, m); if ((m = parse_find_node("icon", n->xmlChildrenNode))) act->data.execute.icon_name = parse_string(doc, m); } } else if (act->func == action_debug) { if ((n = parse_find_node("string", node->xmlChildrenNode))) act->data.debug.string = parse_string(doc, n); } else if (act->func == action_showmenu) { if ((n = parse_find_node("menu", node->xmlChildrenNode))) act->data.showmenu.name = parse_string(doc, n); } else if (act->func == action_move_relative_horz || act->func == action_move_relative_vert || act->func == action_resize_relative_horz || act->func == action_resize_relative_vert) { if ((n = parse_find_node("delta", node->xmlChildrenNode))) act->data.relative.deltax = parse_int(doc, n); } else if (act->func == action_move_relative) { if ((n = parse_find_node("x", node->xmlChildrenNode))) act->data.relative.deltax = parse_int(doc, n); if ((n = parse_find_node("y", node->xmlChildrenNode))) act->data.relative.deltay = parse_int(doc, n); } else if (act->func == action_resize_relative) { if ((n = parse_find_node("left", node->xmlChildrenNode))) act->data.relative.deltaxl = parse_int(doc, n); if ((n = parse_find_node("up", node->xmlChildrenNode))) act->data.relative.deltayu = parse_int(doc, n); if ((n = parse_find_node("right", node->xmlChildrenNode))) act->data.relative.deltax = parse_int(doc, n); if ((n = parse_find_node("down", node->xmlChildrenNode))) act->data.relative.deltay = parse_int(doc, n); } else if (act->func == action_desktop) { if ((n = parse_find_node("desktop", node->xmlChildrenNode))) act->data.desktop.desk = parse_int(doc, n); if (act->data.desktop.desk > 0) act->data.desktop.desk--; /* if ((n = parse_find_node("dialog", node->xmlChildrenNode))) act->data.desktop.inter.any.interactive = parse_bool(doc, n); */ } else if (act->func == action_send_to_desktop) { if ((n = parse_find_node("desktop", node->xmlChildrenNode))) act->data.sendto.desk = parse_int(doc, n); if (act->data.sendto.desk > 0) act->data.sendto.desk--; if ((n = parse_find_node("follow", node->xmlChildrenNode))) act->data.sendto.follow = parse_bool(doc, n); } else if (act->func == action_desktop_dir) { if ((n = parse_find_node("wrap", node->xmlChildrenNode))) act->data.desktopdir.wrap = parse_bool(doc, n); if ((n = parse_find_node("dialog", node->xmlChildrenNode))) act->data.desktopdir.inter.any.interactive = parse_bool(doc, n); } else if (act->func == action_send_to_desktop_dir) { if ((n = parse_find_node("wrap", node->xmlChildrenNode))) act->data.sendtodir.wrap = parse_bool(doc, n); if ((n = parse_find_node("follow", node->xmlChildrenNode))) act->data.sendtodir.follow = parse_bool(doc, n); if ((n = parse_find_node("dialog", node->xmlChildrenNode))) act->data.sendtodir.inter.any.interactive = parse_bool(doc, n); } else if (act->func == action_activate) { if ((n = parse_find_node("here", node->xmlChildrenNode))) act->data.activate.here = parse_bool(doc, n); } else if (act->func == action_cycle_windows) { if ((n = parse_find_node("linear", node->xmlChildrenNode))) act->data.cycle.linear = parse_bool(doc, n); if ((n = parse_find_node("dialog", node->xmlChildrenNode))) act->data.cycle.dialog = parse_bool(doc, n); if ((n = parse_find_node("panels", node->xmlChildrenNode))) act->data.cycle.dock_windows = parse_bool(doc, n); if ((n = parse_find_node("desktop", node->xmlChildrenNode))) act->data.cycle.desktop_windows = parse_bool(doc, n); if ((n = parse_find_node("allDesktops", node->xmlChildrenNode))) act->data.cycle.all_desktops = parse_bool(doc, n); } else if (act->func == action_directional_focus) { if ((n = parse_find_node("dialog", node->xmlChildrenNode))) act->data.interdiraction.dialog = parse_bool(doc, n); if ((n = parse_find_node("panels", node->xmlChildrenNode))) act->data.interdiraction.dock_windows = parse_bool(doc, n); if ((n = parse_find_node("desktop", node->xmlChildrenNode))) act->data.interdiraction.desktop_windows = parse_bool(doc, n); } else if (act->func == action_resize) { if ((n = parse_find_node("edge", node->xmlChildrenNode))) { gchar *s = parse_string(doc, n); if (!g_ascii_strcasecmp(s, "top")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_top; else if (!g_ascii_strcasecmp(s, "bottom")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_bottom; else if (!g_ascii_strcasecmp(s, "left")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_left; else if (!g_ascii_strcasecmp(s, "right")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_right; else if (!g_ascii_strcasecmp(s, "topleft")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft; else if (!g_ascii_strcasecmp(s, "topright")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topright; else if (!g_ascii_strcasecmp(s, "bottomleft")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_bottomleft; else if (!g_ascii_strcasecmp(s, "bottomright")) act->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_bottomright; g_free(s); } } else if (act->func == action_raise || act->func == action_lower || act->func == action_raiselower || act->func == action_shadelower || act->func == action_unshaderaise) { } INTERACTIVE_LIMIT(act, uact); } g_free(actname); } return act; } void action_run_list(GSList *acts, ObClient *c, ObFrameContext context, guint state, guint button, gint x, gint y, Time time, gboolean cancel, gboolean done) { GSList *it; ObAction *a; gboolean ungrabbed = FALSE; if (!acts) return; if (x < 0 && y < 0) screen_pointer_pos(&x, &y); for (it = acts; it; it = g_slist_next(it)) { a = it->data; if (!(a->data.any.client_action == OB_CLIENT_ACTION_ALWAYS && !c)) { a->data.any.c = a->data.any.client_action ? c : NULL; a->data.any.context = context; a->data.any.x = x; a->data.any.y = y; a->data.any.button = button; a->data.any.time = time; if (a->data.any.interactive) { a->data.inter.cancel = cancel; a->data.inter.final = done; if (!(cancel || done)) if (!keyboard_interactive_grab(state, a->data.any.c, a)) continue; } else if (!ungrabbed) { /* Ungrab the keyboard before running the action if it's not interactive. If there is an interactive action going on, then cancel it to release the keyboard. If not, then call XUngrabKeyboard(). We call XUngrabKeyboard() because a key press causes a passive grab on the keyboard, and so if program we are executing wants to grab the keyboard, it will fail if the button is still held down (which is likely). Use the X function not out own, because we're not considering a grab to be in place at all so our function won't try ungrab anything. */ if (keyboard_interactively_grabbed()) keyboard_interactive_cancel(); else XUngrabKeyboard(ob_display, time); /* We don't the same with XUngrabPointer, even though it can cause the same problem. But then Press bindings cause Drag bindings to break. XUngrabPointer(ob_display, time);*/ } /* XXX UGLY HACK race with motion event starting a move and the button release gettnig processed first. answer: don't queue moveresize starts. UGLY HACK XXX */ if (a->data.any.interactive || a->func == action_move || a->func == action_resize) { /* interactive actions are not queued */ a->func(&a->data); } else if (c && (context == OB_FRAME_CONTEXT_CLIENT || (c->type == OB_CLIENT_TYPE_DESKTOP && context == OB_FRAME_CONTEXT_DESKTOP)) && (a->func == action_focus || a->func == action_activate || a->func == action_showmenu)) { /* XXX MORE UGLY HACK actions from clicks on client windows are NOT queued. this solves the mysterious click-and-drag-doesnt-work problem. it was because the window gets focused and stuff after the button event has already been passed through. i dont really know why it should care but it does and it makes a difference. however this very bogus ! ! we want to send the button press to the window BEFORE we do the action because the action might move the windows (eg change desktops) and then the button press ends up on the completely wrong window ! so, this is just for that bug, and it will only NOT queue it if it is a focusing action that can be used with the mouse pointer. ugh. also with the menus, there is a race going on. if the desktop wants to pop up a menu, and we do to, we send them the button before we pop up the menu, so they pop up their menu first. but not always. if we pop up our menu before sending them the button press, then the result is deterministic. yay. */ a->func(&a->data); } else ob_main_loop_queue_action(ob_main_loop, a); } } } void action_run_string(const gchar *name, struct _ObClient *c, Time time) { ObAction *a; GSList *l; a = action_from_string(name, OB_USER_ACTION_NONE); g_assert(a); l = g_slist_append(NULL, a); action_run(l, c, 0, time); } void action_debug(union ActionData *data) { if (data->debug.string) g_print("%s\n", data->debug.string); } void action_execute(union ActionData *data) { GError *e = NULL; gchar *cmd, **argv = 0; if (data->execute.path) { cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL); if (cmd) { if (!g_shell_parse_argv (cmd, NULL, &argv, &e)) { g_message(_("Failed to execute '%s': %s"), cmd, e->message); g_error_free(e); } else if (data->execute.startupnotify) { gchar *program; program = g_path_get_basename(argv[0]); /* sets up the environment */ sn_setup_spawn_environment(program, data->execute.name, data->execute.icon_name, /* launch it on the current desktop */ screen_desktop, data->execute.any.time); if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, NULL, &e)) { g_message(_("Failed to execute '%s': %s"), cmd, e->message); g_error_free(e); sn_spawn_cancel(); } unsetenv("DESKTOP_STARTUP_ID"); g_free(program); g_strfreev(argv); } else { if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, NULL, &e)) { g_message(_("Failed to execute '%s': %s"), cmd, e->message); g_error_free(e); } g_strfreev(argv); } g_free(cmd); } else { g_message(_("Failed to convert the path '%s' from utf8"), data->execute.path); } } } void action_activate(union ActionData *data) { if (data->client.any.c) { if (!data->any.button || client_mouse_focusable(data->client.any.c) || (data->any.context != OB_FRAME_CONTEXT_CLIENT && data->any.context != OB_FRAME_CONTEXT_FRAME)) { /* if using focus_delay, stop the timer now so that focus doesn't go moving on us */ event_halt_focus_delay(); client_activate(data->activate.any.c, data->activate.here, TRUE); } } else { /* focus action on something other than a client, make keybindings work for this openbox instance, but don't focus any specific client */ focus_nothing(); } } void action_focus(union ActionData *data) { if (data->client.any.c) { if (!data->any.button || client_mouse_focusable(data->client.any.c) || (data->any.context != OB_FRAME_CONTEXT_CLIENT && data->any.context != OB_FRAME_CONTEXT_FRAME)) { /* if using focus_delay, stop the timer now so that focus doesn't go moving on us */ event_halt_focus_delay(); client_focus(data->client.any.c); } } else { /* focus action on something other than a client, make keybindings work for this openbox instance, but don't focus any specific client */ focus_nothing(); } } void action_unfocus (union ActionData *data) { if (data->client.any.c == focus_client) focus_fallback(TRUE); } void action_iconify(union ActionData *data) { client_action_start(data); client_iconify(data->client.any.c, TRUE, TRUE, FALSE); client_action_end(data); } void action_focus_order_to_bottom(union ActionData *data) { focus_order_to_bottom(data->client.any.c); } void action_raiselower(union ActionData *data) { ObClient *c = data->client.any.c; GList *it; gboolean raise = FALSE; for (it = stacking_list; it; it = g_list_next(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *cit = it->data; if (cit == c) break; if (client_normal(cit) == client_normal(c) && cit->layer == c->layer && cit->frame->visible && !client_search_transient(c, cit)) { if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) { raise = TRUE; break; } } } } if (raise) action_raise(data); else action_lower(data); } void action_raise(union ActionData *data) { client_action_start(data); stacking_raise(CLIENT_AS_WINDOW(data->client.any.c)); client_action_end(data); } void action_unshaderaise(union ActionData *data) { if (data->client.any.c->shaded) action_unshade(data); else action_raise(data); } void action_shadelower(union ActionData *data) { if (data->client.any.c->shaded) action_lower(data); else action_shade(data); } void action_lower(union ActionData *data) { client_action_start(data); stacking_lower(CLIENT_AS_WINDOW(data->client.any.c)); client_action_end(data); } void action_close(union ActionData *data) { client_close(data->client.any.c); } void action_kill(union ActionData *data) { client_kill(data->client.any.c); } void action_shade(union ActionData *data) { client_action_start(data); client_shade(data->client.any.c, TRUE); client_action_end(data); } void action_unshade(union ActionData *data) { client_action_start(data); client_shade(data->client.any.c, FALSE); client_action_end(data); } void action_toggle_shade(union ActionData *data) { client_action_start(data); client_shade(data->client.any.c, !data->client.any.c->shaded); client_action_end(data); } void action_toggle_omnipresent(union ActionData *data) { client_set_desktop(data->client.any.c, data->client.any.c->desktop == DESKTOP_ALL ? screen_desktop : DESKTOP_ALL, FALSE); } void action_move_relative_horz(union ActionData *data) { ObClient *c = data->relative.any.c; client_action_start(data); client_move(c, c->area.x + data->relative.deltax, c->area.y); client_action_end(data); } void action_move_relative_vert(union ActionData *data) { ObClient *c = data->relative.any.c; client_action_start(data); client_move(c, c->area.x, c->area.y + data->relative.deltax); client_action_end(data); } void action_move_to_center(union ActionData *data) { ObClient *c = data->client.any.c; Rect *area; area = screen_area_monitor(c->desktop, 0); client_action_start(data); client_move(c, area->width / 2 - c->area.width / 2, area->height / 2 - c->area.height / 2); client_action_end(data); } void action_resize_relative_horz(union ActionData *data) { ObClient *c = data->relative.any.c; client_action_start(data); client_resize(c, c->area.width + data->relative.deltax * c->size_inc.width, c->area.height); client_action_end(data); } void action_resize_relative_vert(union ActionData *data) { ObClient *c = data->relative.any.c; if (!c->shaded) { client_action_start(data); client_resize(c, c->area.width, c->area.height + data->relative.deltax * c->size_inc.height); client_action_end(data); } } void action_move_relative(union ActionData *data) { ObClient *c = data->relative.any.c; client_action_start(data); client_move(c, c->area.x + data->relative.deltax, c->area.y + data->relative.deltay); client_action_end(data); } void action_resize_relative(union ActionData *data) { ObClient *c = data->relative.any.c; gint x, y, ow, w, oh, h, lw, lh; client_action_start(data); x = c->area.x; y = c->area.y; ow = c->area.width; w = ow + data->relative.deltax * c->size_inc.width + data->relative.deltaxl * c->size_inc.width; oh = c->area.height; h = oh + data->relative.deltay * c->size_inc.height + data->relative.deltayu * c->size_inc.height; client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE); client_move_resize(c, x + (ow - w), y + (oh - h), w, h); client_action_end(data); } void action_maximize_full(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, TRUE, 0); client_action_end(data); } void action_unmaximize_full(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, FALSE, 0); client_action_end(data); } void action_toggle_maximize_full(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, !(data->client.any.c->max_horz || data->client.any.c->max_vert), 0); client_action_end(data); } void action_maximize_horz(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, TRUE, 1); client_action_end(data); } void action_unmaximize_horz(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, FALSE, 1); client_action_end(data); } void action_toggle_maximize_horz(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, !data->client.any.c->max_horz, 1); client_action_end(data); } void action_maximize_vert(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, TRUE, 2); client_action_end(data); } void action_unmaximize_vert(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, FALSE, 2); client_action_end(data); } void action_toggle_maximize_vert(union ActionData *data) { client_action_start(data); client_maximize(data->client.any.c, !data->client.any.c->max_vert, 2); client_action_end(data); } void action_toggle_fullscreen(union ActionData *data) { client_action_start(data); client_fullscreen(data->client.any.c, !(data->client.any.c->fullscreen)); client_action_end(data); } void action_send_to_desktop(union ActionData *data) { ObClient *c = data->sendto.any.c; if (!client_normal(c)) return; if (data->sendto.desk < screen_num_desktops || data->sendto.desk == DESKTOP_ALL) { client_set_desktop(c, data->sendto.desk, data->sendto.follow); if (data->sendto.follow) screen_set_desktop(data->sendto.desk, TRUE); } } void action_desktop(union ActionData *data) { /* XXX add the interactive/dialog option back again once the dialog has been made to not use grabs */ if (data->desktop.desk < screen_num_desktops || data->desktop.desk == DESKTOP_ALL) { screen_set_desktop(data->desktop.desk, TRUE); if (data->inter.any.interactive) screen_desktop_popup(data->desktop.desk, TRUE); } } void action_desktop_dir(union ActionData *data) { guint d; d = screen_cycle_desktop(data->desktopdir.dir, data->desktopdir.wrap, data->desktopdir.linear, data->desktopdir.inter.any.interactive, data->desktopdir.inter.final, data->desktopdir.inter.cancel); /* only move the desktop when the action is complete. if we switch desktops during the interactive action, focus will move but with NotifyWhileGrabbed and applications don't like that. */ if (!data->sendtodir.inter.any.interactive || (data->sendtodir.inter.final && !data->sendtodir.inter.cancel)) { if (d != screen_desktop) screen_set_desktop(d, TRUE); } } void action_send_to_desktop_dir(union ActionData *data) { ObClient *c = data->sendtodir.inter.any.c; guint d; if (!client_normal(c)) return; d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap, data->sendtodir.linear, data->sendtodir.inter.any.interactive, data->sendtodir.inter.final, data->sendtodir.inter.cancel); /* only move the desktop when the action is complete. if we switch desktops during the interactive action, focus will move but with NotifyWhileGrabbed and applications don't like that. */ if (!data->sendtodir.inter.any.interactive || (data->sendtodir.inter.final && !data->sendtodir.inter.cancel)) { client_set_desktop(c, d, data->sendtodir.follow); if (data->sendtodir.follow && d != screen_desktop) screen_set_desktop(d, TRUE); } } void action_desktop_last(union ActionData *data) { screen_set_desktop(screen_last_desktop, TRUE); } void action_toggle_decorations(union ActionData *data) { ObClient *c = data->client.any.c; client_action_start(data); client_set_undecorated(c, !c->undecorated); client_action_end(data); } static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch, gboolean shaded) { /* let's make x and y client relative instead of screen relative */ x = x - cx; y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */ #define X x*ch/cw #define A -4*X + 7*ch/3 #define B 4*X -15*ch/9 #define C -X/4 + 2*ch/3 #define D X/4 + 5*ch/12 #define E X/4 + ch/3 #define F -X/4 + 7*ch/12 #define G 4*X - 4*ch/3 #define H -4*X + 8*ch/3 #define a (y > 5*ch/9) #define b (x < 4*cw/9) #define c (x > 5*cw/9) #define d (y < 4*ch/9) /* Each of these defines (except X which is just there for fun), represents the equation of a line. The lines they represent are shown in the diagram below. Checking y against these lines, we are able to choose a region of the window as shown. +---------------------A-------|-------|-------B---------------------+ | |A B| | | |A | | B| | | | A B | | | | A | | B | | | | A B | | | | A | | B | | | northwest | A north B | northeast | | | A | | B | | | | A B | | C---------------------+----A--+-------+--B----+---------------------D |CCCCCCC | A B | DDDDDDD| | CCCCCCCC | A | | B | DDDDDDDD | | CCCCCCC A B DDDDDDD | - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - - | | b c | | sh | west | b move c | east | ad | | b c | | ed - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - - | EEEEEEE G H FFFFFFF | | EEEEEEEE | G | | H | FFFFFFFF | |EEEEEEE | G H | FFFFFFF| E---------------------+----G--+-------+--H----+---------------------F | | G H | | | | G | | H | | | southwest | G south H | southeast | | | G | | H | | | | G H | | | | G | | H | | | | G H | | | |G | | H| | | |G H| | +---------------------G-------|-------|-------H---------------------+ */ if (shaded) { /* for shaded windows, you can only resize west/east and move */ if (b) return prop_atoms.net_wm_moveresize_size_left; if (c) return prop_atoms.net_wm_moveresize_size_right; return prop_atoms.net_wm_moveresize_move; } if (y < A && y >= C) return prop_atoms.net_wm_moveresize_size_topleft; else if (y >= A && y >= B && a) return prop_atoms.net_wm_moveresize_size_top; else if (y < B && y >= D) return prop_atoms.net_wm_moveresize_size_topright; else if (y < C && y >= E && b) return prop_atoms.net_wm_moveresize_size_left; else if (y < D && y >= F && c) return prop_atoms.net_wm_moveresize_size_right; else if (y < E && y >= G) return prop_atoms.net_wm_moveresize_size_bottomleft; else if (y < G && y < H && d) return prop_atoms.net_wm_moveresize_size_bottom; else if (y >= H && y < F) return prop_atoms.net_wm_moveresize_size_bottomright; else return prop_atoms.net_wm_moveresize_move; #undef X #undef A #undef B #undef C #undef D #undef E #undef F #undef G #undef H #undef a #undef b #undef c #undef d } void action_move(union ActionData *data) { ObClient *c = data->moveresize.any.c; guint32 corner; if (data->moveresize.keyboard) corner = prop_atoms.net_wm_moveresize_move_keyboard; else corner = prop_atoms.net_wm_moveresize_move; moveresize_start(c, data->any.x, data->any.y, data->any.button, corner); } void action_resize(union ActionData *data) { ObClient *c = data->moveresize.any.c; guint32 corner; if (data->moveresize.keyboard) corner = prop_atoms.net_wm_moveresize_size_keyboard; else if (data->moveresize.corner) corner = data->moveresize.corner; /* it was specified in the binding */ else corner = pick_corner(data->any.x, data->any.y, c->frame->area.x, c->frame->area.y, /* use the client size because the frame can be differently sized (shaded windows) and we want this based on the clients size */ c->area.width + c->frame->size.left + c->frame->size.right, c->area.height + c->frame->size.top + c->frame->size.bottom, c->shaded); moveresize_start(c, data->any.x, data->any.y, data->any.button, corner); } void action_reconfigure(union ActionData *data) { ob_reconfigure(); } void action_restart(union ActionData *data) { ob_restart_other(data->execute.path); } void action_exit(union ActionData *data) { ob_exit(0); } void action_showmenu(union ActionData *data) { if (data->showmenu.name) { menu_show(data->showmenu.name, data->any.x, data->any.y, data->any.button, data->showmenu.any.c); } } void action_cycle_windows(union ActionData *data) { /* if using focus_delay, stop the timer now so that focus doesn't go moving on us */ event_halt_focus_delay(); focus_cycle(data->cycle.forward, data->cycle.all_desktops, data->cycle.dock_windows, data->cycle.desktop_windows, data->cycle.linear, data->any.interactive, data->cycle.dialog, data->cycle.inter.final, data->cycle.inter.cancel); } void action_directional_focus(union ActionData *data) { /* if using focus_delay, stop the timer now so that focus doesn't go moving on us */ event_halt_focus_delay(); focus_directional_cycle(data->interdiraction.direction, data->interdiraction.dock_windows, data->interdiraction.desktop_windows, data->any.interactive, data->interdiraction.dialog, data->interdiraction.inter.final, data->interdiraction.inter.cancel); } void action_movetoedge(union ActionData *data) { gint x, y; ObClient *c = data->diraction.any.c; x = c->frame->area.x; y = c->frame->area.y; switch(data->diraction.direction) { case OB_DIRECTION_NORTH: y = client_directional_edge_search(c, OB_DIRECTION_NORTH, data->diraction.hang) - (data->diraction.hang ? c->frame->area.height : 0); break; case OB_DIRECTION_WEST: x = client_directional_edge_search(c, OB_DIRECTION_WEST, data->diraction.hang) - (data->diraction.hang ? c->frame->area.width : 0); break; case OB_DIRECTION_SOUTH: y = client_directional_edge_search(c, OB_DIRECTION_SOUTH, data->diraction.hang) - (data->diraction.hang ? 0 : c->frame->area.height); break; case OB_DIRECTION_EAST: x = client_directional_edge_search(c, OB_DIRECTION_EAST, data->diraction.hang) - (data->diraction.hang ? 0 : c->frame->area.width); break; default: g_assert_not_reached(); } frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height); client_action_start(data); client_move(c, x, y); client_action_end(data); } void action_growtoedge(union ActionData *data) { gint x, y, width, height, dest; ObClient *c = data->diraction.any.c; Rect *a; a = screen_area(c->desktop); x = c->frame->area.x; y = c->frame->area.y; /* get the unshaded frame's dimensions..if it is shaded */ width = c->area.width + c->frame->size.left + c->frame->size.right; height = c->area.height + c->frame->size.top + c->frame->size.bottom; switch(data->diraction.direction) { case OB_DIRECTION_NORTH: if (c->shaded) break; /* don't allow vertical resize if shaded */ dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE); if (a->y == y) height = height / 2; else { height = c->frame->area.y + height - dest; y = dest; } break; case OB_DIRECTION_WEST: dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE); if (a->x == x) width = width / 2; else { width = c->frame->area.x + width - dest; x = dest; } break; case OB_DIRECTION_SOUTH: if (c->shaded) break; /* don't allow vertical resize if shaded */ dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE); if (a->y + a->height == y + c->frame->area.height) { height = c->frame->area.height / 2; y = a->y + a->height - height; } else height = dest - c->frame->area.y; y += (height - c->frame->area.height) % c->size_inc.height; height -= (height - c->frame->area.height) % c->size_inc.height; break; case OB_DIRECTION_EAST: dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE); if (a->x + a->width == x + c->frame->area.width) { width = c->frame->area.width / 2; x = a->x + a->width - width; } else width = dest - c->frame->area.x; x += (width - c->frame->area.width) % c->size_inc.width; width -= (width - c->frame->area.width) % c->size_inc.width; break; default: g_assert_not_reached(); } width -= c->frame->size.left + c->frame->size.right; height -= c->frame->size.top + c->frame->size.bottom; frame_frame_gravity(c->frame, &x, &y, width, height); client_action_start(data); client_move_resize(c, x, y, width, height); client_action_end(data); } void action_send_to_layer(union ActionData *data) { client_set_layer(data->layer.any.c, data->layer.layer); } void action_toggle_layer(union ActionData *data) { ObClient *c = data->layer.any.c; client_action_start(data); if (data->layer.layer < 0) client_set_layer(c, c->below ? 0 : -1); else if (data->layer.layer > 0) client_set_layer(c, c->above ? 0 : 1); client_action_end(data); } void action_toggle_dockautohide(union ActionData *data) { config_dock_hide = !config_dock_hide; dock_configure(); } void action_toggle_show_desktop(union ActionData *data) { screen_show_desktop(!screen_showing_desktop, NULL); } void action_show_desktop(union ActionData *data) { screen_show_desktop(TRUE, NULL); } void action_unshow_desktop(union ActionData *data) { screen_show_desktop(FALSE, NULL); } void action_break_chroot(union ActionData *data) { /* break out of one chroot */ keyboard_reset_chains(1); }