diff options
Diffstat (limited to 'src/actions.c')
-rw-r--r-- | src/actions.c | 6005 |
1 files changed, 0 insertions, 6005 deletions
diff --git a/src/actions.c b/src/actions.c deleted file mode 100644 index d847fa7..0000000 --- a/src/actions.c +++ /dev/null @@ -1,6005 +0,0 @@ -/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> - * - * This file is part of ratpoison. - * - * ratpoison 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, or (at your option) - * any later version. - * - * ratpoison 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. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - */ - -#include <unistd.h> -#include <ctype.h> /* for isspace */ -#include <sys/wait.h> -#include <X11/keysym.h> -#include <string.h> -#include <strings.h> -#include <time.h> -#include <errno.h> -#include <signal.h> -#include <X11/Xproto.h> - -#include "ratpoison.h" - -#ifdef HAVE_LIBXTST -# include <X11/extensions/XTest.h> -#endif - - -#define ARG_STRING(elt) args[elt]->string -#define ARG(elt, type) args[elt]->arg.type - -struct set_var -{ - char *var; - cmdret *(*set_fn)(struct cmdarg **); - int nargs; - struct argspec *args; - struct list_head node; -}; - -static cmdret * set_resizeunit (struct cmdarg **args); -static cmdret * set_wingravity (struct cmdarg **args); -static cmdret * set_transgravity (struct cmdarg **args); -static cmdret * set_maxsizegravity (struct cmdarg **args); -static cmdret * set_bargravity (struct cmdarg **args); -static cmdret * set_font (struct cmdarg **args); -static cmdret * set_padding (struct cmdarg **args); -static cmdret * set_border (struct cmdarg **args); -static cmdret * set_barborder (struct cmdarg **args); -static cmdret * set_barinpadding (struct cmdarg **args); -static cmdret * set_inputwidth (struct cmdarg **args); -static cmdret * set_waitcursor (struct cmdarg **args); -static cmdret * set_winfmt (struct cmdarg **args); -static cmdret * set_winname (struct cmdarg **args); -static cmdret * set_framefmt (struct cmdarg **args); -static cmdret * set_fgcolor (struct cmdarg **args); -static cmdret * set_bgcolor (struct cmdarg **args); -static cmdret * set_fwcolor (struct cmdarg **args); -static cmdret * set_bwcolor (struct cmdarg **args); -static cmdret * set_barpadding (struct cmdarg **args); -static cmdret * set_winliststyle (struct cmdarg **args); -static cmdret * set_framesels (struct cmdarg **args); -static cmdret * set_maxundos (struct cmdarg **args); -static cmdret * set_infofmt (struct cmdarg **args); -static cmdret * set_topkmap (struct cmdarg **args); -static cmdret * set_historysize (struct cmdarg **args); -static cmdret * set_historycompaction (struct cmdarg **args); -static cmdret * set_historyexpansion (struct cmdarg **args); - -LIST_HEAD(set_vars); - -/* FIXME This variable should really be kept static for group.c */ -extern struct numset *group_numset; - -static void -add_set_var (char *name, cmdret * (*fn)(struct cmdarg **), int nargs, ...) -{ - int i = 0; - struct set_var *var; - va_list va; - - var = xmalloc (sizeof (struct set_var)); - var->var = name; - var->set_fn = fn; - var->nargs = nargs; - var->args = xmalloc(sizeof(struct argspec) * nargs); - - /* Fill var->args */ - va_start(va, nargs); - for (i=0; i<nargs; i++) - { - var->args[i].prompt = va_arg(va, char*); - var->args[i].type = va_arg(va, int); - } - va_end(va); - - list_add (&var->node, &set_vars); -} - -static void -set_var_free (struct set_var *var) -{ - if (var == NULL) - return; - free(var->args); - free(var); -} - -static void -init_set_vars(void) -{ - add_set_var ("resizeunit", set_resizeunit, 1, "", arg_NUMBER); - add_set_var ("maxundos", set_maxundos, 1, "", arg_NUMBER); - add_set_var ("wingravity", set_wingravity, 1, "", arg_GRAVITY); - add_set_var ("transgravity", set_transgravity, 1, "", arg_GRAVITY); - add_set_var ("maxsizegravity", set_maxsizegravity, 1, "", arg_GRAVITY); - add_set_var ("bargravity", set_bargravity, 1, "", arg_GRAVITY); - add_set_var ("font", set_font, 1, "", arg_STRING); - add_set_var ("padding", set_padding, 4, - "", arg_NUMBER, "", arg_NUMBER, "", arg_NUMBER, "", arg_NUMBER); - add_set_var ("border", set_border, 1, "", arg_NUMBER); - add_set_var ("barborder", set_barborder, 1, "", arg_NUMBER); - add_set_var ("barinpadding", set_barinpadding, 1, "", arg_NUMBER); - add_set_var ("inputwidth", set_inputwidth, 1, "", arg_NUMBER); - add_set_var ("waitcursor", set_waitcursor, 1, "", arg_NUMBER); - add_set_var ("winfmt", set_winfmt, 1, "", arg_REST); - add_set_var ("winname", set_winname, 1, "", arg_STRING); - add_set_var ("framefmt", set_framefmt, 1, "", arg_REST); - add_set_var ("fgcolor", set_fgcolor, 1, "", arg_STRING); - add_set_var ("bgcolor", set_bgcolor, 1, "", arg_STRING); - add_set_var ("fwcolor", set_fwcolor, 1, "", arg_STRING); - add_set_var ("bwcolor", set_bwcolor, 1, "", arg_STRING); - add_set_var ("barpadding", set_barpadding, 2, "", arg_NUMBER, "", arg_NUMBER); - add_set_var ("winliststyle", set_winliststyle, 1, "", arg_STRING); - add_set_var ("framesels", set_framesels, 1, "", arg_STRING); - add_set_var ("infofmt", set_infofmt, 1, "", arg_REST); - add_set_var ("topkmap", set_topkmap, 1, "", arg_STRING); - add_set_var ("historysize", set_historysize, 1, "", arg_NUMBER); - add_set_var ("historycompaction", set_historycompaction, 1, "", arg_NUMBER); - add_set_var ("historyexpansion", set_historyexpansion, 1, "", arg_NUMBER); -} - -/* rp_keymaps is ratpoison's list of keymaps. */ -LIST_HEAD(rp_keymaps); -LIST_HEAD(user_commands); - -/* i_nrequired is the number required when called - interactively. ni_nrequired is when called non-interactively. */ -static void -add_command (char *name, cmdret * (*fn)(int, struct cmdarg **), int nargs, int i_nrequired, int ni_nrequired, ...) -{ - int i = 0; - struct user_command *cmd; - va_list va; - - cmd = xmalloc (sizeof (struct user_command)); - cmd->name = name; - cmd->func = fn; - cmd->num_args = nargs; - cmd->ni_required_args = ni_nrequired; - cmd->i_required_args = i_nrequired; - cmd->args = xmalloc(sizeof(struct argspec) * nargs); - - /* Fill cmd->args */ - va_start(va, ni_nrequired); - for (i=0; i<nargs; i++) - { - cmd->args[i].prompt = va_arg(va, char*); - cmd->args[i].type = va_arg(va, int); - } - va_end(va); - - list_add (&cmd->node, &user_commands); -} - -static void -user_command_free(struct user_command *cmd) -{ - if (cmd == NULL ) - return; - - free(cmd->args); - free(cmd); -} - -void -init_user_commands(void) -{ - /*@begin (tag required for genrpbindings) */ - add_command ("abort", cmd_abort, 0, 0, 0); - add_command ("addhook", cmd_addhook, 2, 2, 2, - "Hook: ", arg_HOOK, - "Command: ", arg_COMMAND); - add_command ("alias", cmd_alias, 2, 2, 2, - "Alias: ", arg_STRING, - "Command: ", arg_COMMAND); - add_command ("banish", cmd_banish, 0, 0, 0); - add_command ("chdir", cmd_chdir, 1, 0, 0, - "Dir: ", arg_REST); - add_command ("clrunmanaged", cmd_clrunmanaged, 0, 0, 0); - add_command ("colon", cmd_colon, 1, 0, 0, - "", arg_REST); - add_command ("curframe", cmd_curframe, 0, 0, 0); - add_command ("definekey", cmd_definekey, 3, 3, 3, - "Keymap: ", arg_KEYMAP, - "Key: ", arg_KEY, - "Command: ", arg_COMMAND); - add_command ("undefinekey", cmd_undefinekey, 2, 2, 2, - "Keymap: ", arg_KEYMAP, - "Key: ", arg_KEY); - add_command ("delete", cmd_delete, 0, 0, 0); - add_command ("delkmap", cmd_delkmap, 1, 1, 1, - "Keymap: ", arg_KEYMAP); - add_command ("echo", cmd_echo, 1, 1, 1, - "Echo: ", arg_RAW); - add_command ("escape", cmd_escape, 1, 1, 1, - "Key: ", arg_KEY); - add_command ("exec", cmd_exec, 1, 1, 1, - "/bin/sh -c ", arg_SHELLCMD); - add_command ("execa", cmd_execa, 1, 1, 1, - "/bin/sh -c ", arg_SHELLCMD); - add_command ("execf", cmd_execf, 2, 2, 2, - "frame to execute in:", arg_FRAME, - "/bin/sh -c ", arg_SHELLCMD); - add_command ("fdump", cmd_fdump, 1, 0, 0, - "", arg_NUMBER); - add_command ("focus", cmd_next_frame, 0, 0, 0); - add_command ("focusprev", cmd_prev_frame, 0, 0, 0); - add_command ("focusdown", cmd_focusdown, 0, 0, 0); - add_command ("exchangeup", cmd_exchangeup, 0, 0, 0); - add_command ("exchangedown", cmd_exchangedown, 0, 0, 0); - add_command ("exchangeleft", cmd_exchangeleft, 0, 0, 0); - add_command ("exchangeright", cmd_exchangeright, 0, 0, 0); - add_command ("swap", cmd_swap, 2, 1, 1, - "destination frame: ", arg_FRAME, - "source frame: ", arg_FRAME); - add_command ("focuslast", cmd_focuslast, 0, 0, 0); - add_command ("focusleft", cmd_focusleft, 0, 0, 0); - add_command ("focusright", cmd_focusright, 0, 0, 0); - add_command ("focusup", cmd_focusup, 0, 0, 0); - add_command ("frestore", cmd_frestore, 1, 1, 1, - "Frames: ", arg_REST); - add_command ("fselect", cmd_fselect, 1, 1, 1, - "", arg_FRAME); - add_command ("gdelete", cmd_gdelete, 1, 0, 0, - "Group:", arg_GROUP); - add_command ("getenv", cmd_getenv, 1, 1, 1, - "Variable: ", arg_STRING); - add_command ("gmerge", cmd_gmerge, 1, 1, 1, - "Group: ", arg_GROUP); - add_command ("gmove", cmd_gmove, 1, 1, 1, - "Group: ", arg_GROUP); - add_command ("gnew", cmd_gnew, 1, 1, 1, - "Name: ", arg_STRING); - add_command ("gnewbg", cmd_gnewbg, 1, 1, 1, - "Name: ", arg_STRING); - add_command ("gnumber", cmd_gnumber, 2, 1, 1, - "Number: ", arg_NUMBER, - "Number: ", arg_NUMBER); - add_command ("grename", cmd_grename, 1, 1, 1, - "Change group name to: ", arg_REST); - add_command ("gnext", cmd_gnext, 0, 0, 0); - add_command ("gprev", cmd_gprev, 0, 0, 0); - add_command ("gother", cmd_gother, 0, 0, 0); - add_command ("gravity", cmd_gravity, 1, 0, 0, - "Gravity: ", arg_GRAVITY); - add_command ("groups", cmd_groups, 0, 0, 0); - add_command ("gselect", cmd_gselect, 1, 1, 1, - "Group: ", arg_GROUP); - add_command ("help", cmd_help, 1, 0, 0, - "Keymap: ", arg_KEYMAP); - add_command ("hsplit", cmd_h_split, 1, 0, 0, - "Split: ", arg_STRING); - add_command ("info", cmd_info, 1, 0, 0, - "Format: ", arg_REST); - add_command ("kill", cmd_kill, 0, 0, 0); - add_command ("lastmsg", cmd_lastmsg, 0, 0, 0); - add_command ("license", cmd_license, 0, 0, 0); - add_command ("link", cmd_link, 2, 1, 1, - "Key: ", arg_STRING, - "Keymap: ", arg_KEYMAP); - add_command ("listhook", cmd_listhook, 1, 1, 1, - "Hook: ", arg_HOOK); - add_command ("meta", cmd_meta, 1, 0, 0, - "key: ", arg_KEY); - add_command ("msgwait", cmd_msgwait, 1, 0, 0, - "", arg_NUMBER); - add_command ("newkmap", cmd_newkmap, 1, 1, 1, - "Keymap: ", arg_STRING); - add_command ("newwm", cmd_newwm, 1, 1, 1, - "Switch to wm: ", arg_REST); - add_command ("next", cmd_next, 0, 0, 0); - add_command ("nextscreen", cmd_nextscreen, 0, 0, 0); - add_command ("number", cmd_number, 2, 1, 1, - "Number: ", arg_NUMBER, - "Number: ", arg_NUMBER); - add_command ("only", cmd_only, 0, 0, 0); - add_command ("other", cmd_other, 0, 0, 0); - add_command ("prev", cmd_prev, 0, 0, 0); - add_command ("prevscreen", cmd_prevscreen, 0, 0, 0); - add_command ("quit", cmd_quit, 0, 0, 0); - add_command ("ratinfo", cmd_ratinfo, 0, 0, 0); - add_command ("ratrelinfo", cmd_ratrelinfo, 0, 0, 0); - add_command ("banishrel", cmd_banishrel, 0, 0, 0); - add_command ("ratwarp", cmd_ratwarp, 2, 2, 2, - "X: ", arg_NUMBER, - "Y: ", arg_NUMBER); - add_command ("ratrelwarp", cmd_ratrelwarp, 2, 2, 2, - "X: ", arg_NUMBER, - "Y: ", arg_NUMBER); - add_command ("ratclick", cmd_ratclick, 1, 0, 0, - "Button: ", arg_NUMBER); - add_command ("rathold", cmd_rathold, 2, 1, 1, - "State: ", arg_STRING, - "Button: ", arg_NUMBER); - add_command ("readkey", cmd_readkey, 1, 1, 1, - "Keymap: ", arg_KEYMAP); - add_command ("redisplay", cmd_redisplay, 0, 0, 0); - add_command ("remhook", cmd_remhook, 2, 2, 2, - "Hook: ", arg_HOOK, - "Command: ", arg_COMMAND); - add_command ("remove", cmd_remove, 0, 0, 0); - add_command ("resize", cmd_resize, 2, 0, 2, - "", arg_NUMBER, - "", arg_NUMBER); - add_command ("restart", cmd_restart, 0, 0, 0); - add_command ("rudeness", cmd_rudeness, 1, 0, 0, - "Rudeness: ", arg_NUMBER); - add_command ("select", cmd_select, 1, 0, 1, - "Select window: ", arg_REST); - add_command ("set", cmd_set, 2, 0, 0, - "", arg_VARIABLE, - "", arg_REST); - add_command ("setenv", cmd_setenv, 2, 2, 2, - "Variable: ", arg_STRING, - "Value: ", arg_REST); - add_command ("shrink", cmd_shrink, 0, 0, 0); - add_command ("sfrestore", cmd_sfrestore, 1, 1, 1, - "Frames: ", arg_REST); - add_command ("source", cmd_source, 1, 1, 1, - "File: ", arg_REST); - add_command ("sselect", cmd_sselect, 1, 1, 1, - "Screen: ", arg_NUMBER); - add_command ("startup_message", cmd_startup_message, 1, 1, 1, - "Startup message: ", arg_STRING); - add_command ("time", cmd_time, 0, 0, 0); - add_command ("title", cmd_rename, 1, 1, 1, - "Set window's title to: ", arg_REST); - add_command ("tmpwm", cmd_tmpwm, 1, 1, 1, - "Tmp wm: ", arg_REST); - add_command ("unalias", cmd_unalias, 1, 1, 1, - "Alias: ", arg_STRING); - add_command ("unmanage", cmd_unmanage, 1, 1, 0, - "Unmanage: ", arg_REST); - add_command ("unsetenv", cmd_unsetenv, 1, 1, 1, - "Variable: ", arg_STRING); - add_command ("verbexec", cmd_verbexec, 1, 1, 1, - "/bin/sh -c ", arg_SHELLCMD); - add_command ("version", cmd_version, 0, 0, 0); - add_command ("vsplit", cmd_v_split, 1, 0, 0, - "Split: ", arg_STRING); - add_command ("warp", cmd_warp, 1, 1, 1, - "Warp State: ", arg_STRING); - add_command ("windows", cmd_windows, 1, 0, 0, - "", arg_REST); - add_command ("cnext", cmd_cnext, 0, 0, 0); - add_command ("cother", cmd_cother, 0, 0, 0); - add_command ("cprev", cmd_cprev, 0, 0, 0); - add_command ("dedicate", cmd_dedicate, 1, 0, 0, - "", arg_NUMBER); - add_command ("describekey", cmd_describekey, 1, 1, 1, - "Keymap: ", arg_KEYMAP); - add_command ("inext", cmd_inext, 0, 0, 0); - add_command ("iother", cmd_iother, 0, 0, 0); - add_command ("iprev", cmd_iprev, 0, 0, 0); - add_command ("prompt", cmd_prompt, 1, 0, 0, - "", arg_REST); - add_command ("sdump", cmd_sdump, 0, 0, 0); - add_command ("sfdump", cmd_sfdump, 0, 0, 0); - add_command ("undo", cmd_undo, 0, 0, 0); - add_command ("redo", cmd_redo, 0, 0, 0); - add_command ("putsel", cmd_putsel, 1, 1, 1, - "Text: ", arg_RAW); - add_command ("getsel", cmd_getsel, 0, 0, 0); - add_command ("compat", cmd_compat, 0, 0, 0); - /*@end (tag required for genrpbindings) */ - - /* Commands to help debug ratpoison. */ -#ifdef DEBUG -#endif - - /* the following screen commands may or may not be able to be - implemented. See the screen documentation for what should be - emulated with these commands */ -#if 0 - add_command ("msgminwait", cmd_unimplemented, 0); - add_command ("nethack", cmd_unimplemented, 0); - add_command ("sleep", cmd_unimplemented, 0); - add_command ("stuff", cmd_unimplemented, 0); -#endif - - init_set_vars(); -} - -typedef struct -{ - char *name; - char *alias; -} alias_t; - -static alias_t *alias_list; -static int alias_list_size; -static int alias_list_last; - -static cmdret* frestore (char *data, rp_screen *s); -static char* fdump (rp_screen *screen); - -/* Delete all entries in the redo list. */ -static void -clear_frame_redos (void) -{ - rp_frame_undo *cur; - struct list_head *tmp, *iter; - - list_for_each_safe_entry (cur, iter, tmp, &rp_frame_redos, node) - { - if (cur->frames) free (cur->frames); - list_del (&(cur->node)); - } -} - -void -del_frame_undo (rp_frame_undo *u) -{ - if (!u) return; - if (u->frames) free (u->frames); - list_del (&(u->node)); - free (u); -} - -static void -push_frame_undo(rp_screen *screen) -{ - rp_frame_undo *cur; - if (list_size (&rp_frame_undos) > defaults.maxundos) - { - /* Delete the oldest node */ - list_last (cur, &rp_frame_undos, node); - del_frame_undo (cur); - } - cur = xmalloc (sizeof(rp_frame_undo)); - cur->frames = fdump (screen); - cur->screen = screen; - list_add (&cur->node, &rp_frame_undos); - /* Since we're creating new frames the redo list is now invalid, so - clear it. */ - clear_frame_redos(); -} - -static rp_frame_undo * -pop_frame_list (struct list_head *undo_list, struct list_head *redo_list) -{ - rp_screen *screen = current_screen(); - rp_frame_undo *first, *new; - - /* Is there something to restore? */ - list_first (first, undo_list, node); - if (!first) - return NULL; - - /* First save the current layout into undo */ - new = xmalloc (sizeof(rp_frame_undo)); - new->frames = fdump (screen); - new->screen = screen; - list_add (&new->node, redo_list); - - list_del (&(first->node)); - return first; -} - -/* Pop the head of the frame undo list off and put it in the redo list. */ -static rp_frame_undo * -pop_frame_undo (void) -{ - return pop_frame_list (&rp_frame_undos, &rp_frame_redos); -} - -/* Pop the head of the frame redo list off and put it in the undo list. */ -static rp_frame_undo * -pop_frame_redo (void) -{ - return pop_frame_list (&rp_frame_redos, &rp_frame_undos); -} - -rp_action* -find_keybinding_by_action (char *action, rp_keymap *map) -{ - int i; - - for (i=0; i<map->actions_last; i++) - { - if (!strcmp (map->actions[i].data, action)) - { - return &map->actions[i]; - } - } - - return NULL; -} - -rp_action* -find_keybinding (KeySym keysym, unsigned int state, rp_keymap *map) -{ - int i; - for (i = 0; i < map->actions_last; i++) - { - if (map->actions[i].key == keysym - && map->actions[i].state == state) - return &map->actions[i]; - } - return NULL; -} - -static char * -find_command_by_keydesc (char *desc, rp_keymap *map) -{ - int i = 0; - char *keysym_name; - - while (i < map->actions_last) - { - keysym_name = keysym_to_string (map->actions[i].key, map->actions[i].state); - if (!strcmp (keysym_name, desc)) - { - free (keysym_name); - return map->actions[i].data; - } - free (keysym_name); - i++; - } - - return NULL; -} - -static char * -resolve_command_from_keydesc (char *desc, int depth, rp_keymap *map) -{ - char *cmd, *c; - - c = find_command_by_keydesc (desc, map); - if (!c) - return NULL; - - /* is it a link? */ - if (strncmp (c, "link", 4) || depth > MAX_LINK_DEPTH) - /* it is not */ - return c; - - cmd = resolve_command_from_keydesc (&c[5], depth + 1, map); - return (cmd != NULL) ? cmd : c; -} - - -static void -add_keybinding (KeySym keysym, int state, char *cmd, rp_keymap *map) -{ - if (map->actions_last >= map->actions_size) - { - /* double the key table size */ - map->actions_size *= 2; - map->actions = (rp_action*) xrealloc (map->actions, sizeof (rp_action) * map->actions_size); - PRINT_DEBUG (("realloc()ed key_table %d\n", map->actions_size)); - } - - map->actions[map->actions_last].key = keysym; - map->actions[map->actions_last].state = state; - /* free this on shutdown, or re/unbinding */ - map->actions[map->actions_last].data = xstrdup (cmd); - - map->actions_last++; -} - -static void -replace_keybinding (rp_action *key_action, char *newcmd) -{ - if (strlen (key_action->data) < strlen (newcmd)) - key_action->data = (char*) realloc (key_action->data, strlen (newcmd) + 1); - - strcpy (key_action->data, newcmd); -} - -static int -remove_keybinding (KeySym keysym, unsigned int state, rp_keymap *map) -{ - int i; - int found = -1; - - for (i=0; i<map->actions_last; i++) - { - if (map->actions[i].key == keysym && map->actions[i].state == state) - { - found = i; - break; - } - } - - if (found >= 0) - { - free (map->actions[found].data); - - memmove (&map->actions[found], &map->actions[found+1], - sizeof (rp_action) * (map->actions_last - found - 1)); - map->actions_last--; - - return 1; - } - - return 0; -} - -static rp_keymap * -keymap_new (char *name) -{ - rp_keymap *map; - - /* All keymaps must have a name. */ - if (name == NULL) - return NULL; - - map = xmalloc (sizeof (rp_keymap)); - map->name = xstrdup (name); - map->actions_size = 1; - map->actions = (rp_action*) xmalloc (sizeof (rp_action) * map->actions_size); - map->actions_last = 0; - - return map; -} - -rp_keymap * -find_keymap (char *name) -{ - rp_keymap *cur; - - list_for_each_entry (cur, &rp_keymaps, node) - { - if (!strcmp (name, cur->name)) - { - return cur; - } - } - - return NULL; -} - -/* Search the alias table for a match. If a match is found, return its - index into the table. Otherwise return -1. */ -static int -find_alias_index (char *name) -{ - int i; - - for (i=0; i<alias_list_last; i++) - if (!strcmp (name, alias_list[i].name)) - return i; - - return -1; -} - -static void -add_alias (char *name, char *alias) -{ - int i; - - /* Are we updating an existing alias, or creating a new one? */ - i = find_alias_index (name); - if (i >= 0) - { - free (alias_list[i].alias); - alias_list[i].alias = xstrdup (alias); - } - else - { - if (alias_list_last >= alias_list_size) - { - alias_list_size *= 2; - alias_list = xrealloc (alias_list, sizeof (alias_t) * alias_list_size); - } - - alias_list[alias_list_last].name = xstrdup (name); - alias_list[alias_list_last].alias = xstrdup (alias); - alias_list_last++; - } -} - -void -initialize_default_keybindings (void) -{ - rp_keymap *map, *top; - - map = keymap_new (ROOT_KEYMAP); - list_add (&map->node, &rp_keymaps); - - top = keymap_new (defaults.top_kmap); - list_add (&top->node, &rp_keymaps); - - /* Initialive the alias list. */ - alias_list_size = 5; - alias_list_last = 0; - alias_list = xmalloc (sizeof (alias_t) * alias_list_size); - - prefix_key.sym = KEY_PREFIX; - prefix_key.state = MODIFIER_PREFIX; - - /* Add the prefix key to the top-level map. */ - add_keybinding (prefix_key.sym, prefix_key.state, "readkey " ROOT_KEYMAP, top); - - add_keybinding (prefix_key.sym, prefix_key.state, "other", map); - add_keybinding (prefix_key.sym, 0, "meta", map); - add_keybinding (XK_g, RP_CONTROL_MASK, "abort", map); - add_keybinding (XK_0, 0, "select 0", map); - add_keybinding (XK_1, 0, "select 1", map); - add_keybinding (XK_2, 0, "select 2", map); - add_keybinding (XK_3, 0, "select 3", map); - add_keybinding (XK_4, 0, "select 4", map); - add_keybinding (XK_5, 0, "select 5", map); - add_keybinding (XK_6, 0, "select 6", map); - add_keybinding (XK_7, 0, "select 7", map); - add_keybinding (XK_8, 0, "select 8", map); - add_keybinding (XK_9, 0, "select 9", map); - add_keybinding (XK_minus, 0, "select -", map); - add_keybinding (XK_A, 0, "title", map); - add_keybinding (XK_A, RP_CONTROL_MASK, "title", map); - add_keybinding (XK_K, 0, "kill", map); - add_keybinding (XK_K, RP_CONTROL_MASK, "kill", map); - add_keybinding (XK_Return, 0, "next", map); - add_keybinding (XK_Return, RP_CONTROL_MASK, "next", map); - add_keybinding (XK_a, 0, "time", map); - add_keybinding (XK_a, RP_CONTROL_MASK, "time", map); - add_keybinding (XK_b, 0, "banish", map); - add_keybinding (XK_b, RP_CONTROL_MASK, "banish", map); - add_keybinding (XK_c, 0, "exec " TERM_PROG, map); - add_keybinding (XK_c, RP_CONTROL_MASK, "exec " TERM_PROG, map); - add_keybinding (XK_colon, 0, "colon", map); - add_keybinding (XK_exclam, 0, "exec", map); - add_keybinding (XK_exclam, RP_CONTROL_MASK, "colon exec " TERM_PROG " -e ", map); - add_keybinding (XK_i, 0, "info", map); - add_keybinding (XK_i, RP_CONTROL_MASK, "info", map); - add_keybinding (XK_k, 0, "delete", map); - add_keybinding (XK_k, RP_CONTROL_MASK, "delete", map); - add_keybinding (XK_l, 0, "redisplay", map); - add_keybinding (XK_l, RP_CONTROL_MASK, "redisplay", map); - add_keybinding (XK_m, 0, "lastmsg", map); - add_keybinding (XK_m, RP_CONTROL_MASK, "lastmsg", map); - add_keybinding (XK_n, 0, "next", map); - add_keybinding (XK_n, RP_CONTROL_MASK, "next", map); - add_keybinding (XK_p, 0, "prev", map); - add_keybinding (XK_p, RP_CONTROL_MASK, "prev", map); - add_keybinding (XK_quoteright, 0, "select", map); - add_keybinding (XK_quoteright, RP_CONTROL_MASK, "select", map); - add_keybinding (XK_space, 0, "next", map); - add_keybinding (XK_space, RP_CONTROL_MASK, "next", map); - add_keybinding (XK_v, 0, "version", map); - add_keybinding (XK_v, RP_CONTROL_MASK, "version", map); - add_keybinding (XK_V, 0, "license", map); - add_keybinding (XK_V, RP_CONTROL_MASK, "license", map); - add_keybinding (XK_w, 0, "windows", map); - add_keybinding (XK_w, RP_CONTROL_MASK, "windows", map); - add_keybinding (XK_s, 0, "split", map); - add_keybinding (XK_s, RP_CONTROL_MASK, "split", map); - add_keybinding (XK_S, 0, "hsplit", map); - add_keybinding (XK_S, RP_CONTROL_MASK, "hsplit", map); - add_keybinding (XK_Tab, 0, "focus", map); - add_keybinding (XK_Tab, RP_META_MASK, "focuslast", map); - add_keybinding (XK_Left, RP_CONTROL_MASK, "exchangeleft", map); - add_keybinding (XK_Right, RP_CONTROL_MASK, "exchangeright", map); - add_keybinding (XK_Up, RP_CONTROL_MASK, "exchangeup", map); - add_keybinding (XK_Down, RP_CONTROL_MASK, "exchangedown", map); - add_keybinding (XK_Left, 0, "focusleft", map); - add_keybinding (XK_Right, 0, "focusright", map); - add_keybinding (XK_Up, 0, "focusup", map); - add_keybinding (XK_Down, 0, "focusdown", map); - add_keybinding (XK_Q, 0, "only", map); - add_keybinding (XK_R, 0, "remove", map); - add_keybinding (XK_f, 0, "fselect", map); - add_keybinding (XK_f, RP_CONTROL_MASK, "fselect", map); - add_keybinding (XK_F, 0, "curframe", map); - add_keybinding (XK_r, 0, "resize", map); - add_keybinding (XK_r, RP_CONTROL_MASK, "resize", map); - add_keybinding (XK_question, 0, "help " ROOT_KEYMAP, map); - add_keybinding (XK_underscore, RP_CONTROL_MASK, "undo", map); - add_keybinding (XK_u, 0, "undo", map); - add_keybinding (XK_u, RP_CONTROL_MASK, "undo", map); - add_keybinding (XK_U, 0, "redo", map); - add_keybinding (XK_x, 0, "swap", map); - add_keybinding (XK_x, RP_CONTROL_MASK, "swap", map); - add_keybinding (XK_N, 0, "nextscreen", map); - add_keybinding (XK_P, 0, "prevscreen", map); - - add_alias ("unbind", "undefinekey " ROOT_KEYMAP); - add_alias ("bind", "definekey " ROOT_KEYMAP); - add_alias ("split", "vsplit"); -} - -cmdret * -cmdret_new (int success, char *fmt, ...) -{ - cmdret *ret = xmalloc (sizeof (cmdret)); - va_list ap; - - ret->success = success; - - if (fmt) - { - va_start (ap, fmt); - ret->output = xvsprintf (fmt, ap); - va_end (ap); - } - else - ret->output = NULL; - - return ret; -} - -void -cmdret_free (cmdret *ret) -{ - if (ret->output) - free (ret->output); - free (ret); -} - -void -keymap_free (rp_keymap *map) -{ - int i; - - /* Free the data in the actions. */ - for (i=0; i<map->actions_last; i++) - { - free (map->actions[i].data); - } - - /* Free the map data. */ - free (map->actions); - free (map->name); - - /* ...and the map itself. */ - free (map); -} - -void -free_keymaps (void) -{ - rp_keymap *cur; - struct list_head *tmp, *iter; - - list_for_each_safe_entry (cur, iter, tmp, &rp_keymaps, node) - { - list_del (&cur->node); - keymap_free (cur); - } -} - -void -free_aliases (void) -{ - int i; - - /* Free the alias data. */ - for (i=0; i<alias_list_last; i++) - { - free (alias_list[i].name); - free (alias_list[i].alias); - } - - /* Free the alias list. */ - free (alias_list); -} - -void -free_user_commands (void) -{ - struct user_command *cur; - struct set_var *var; - struct list_head *tmp, *iter; - - list_for_each_safe_entry (cur, iter, tmp, &user_commands, node) - { - list_del (&cur->node); - user_command_free (cur); - } - list_for_each_safe_entry (var, iter, tmp, &set_vars, node) - { - list_del (&var->node); - set_var_free (var); - } -} - -/* return a KeySym from a string that contains either a hex value or - an X keysym description */ -static int string_to_keysym (char *str) -{ - int retval; - int keysym; - - retval = sscanf (str, "0x%x", &keysym); - - if (!retval || retval == EOF) - keysym = XStringToKeysym (str); - - return keysym; -} - -/* Parse a key description. 's' is, naturally, the key description. */ -static cmdret * -parse_keydesc (char *s, struct rp_key *key) -{ - char *token, *next_token, *keydesc; - - if (s == NULL) - return NULL; - - /* Avoid mangling s. */ - keydesc = xstrdup (s); - - key->state = 0; - key->sym = 0; - - if (!strchr (keydesc, '-')) - { - /* Its got no hyphens in it, so just grab the keysym */ - key->sym = string_to_keysym (keydesc); - - if (key->sym == NoSymbol) - { - cmdret *ret = cmdret_new (RET_FAILURE, "parse_keydesc: Unknown key '%s'", keydesc); - free (keydesc); - return ret; - } - } - else if (keydesc[strlen (keydesc) - 1] == '-') - { - /* A key description can't end in a -. */ - free (keydesc); - return cmdret_new (RET_FAILURE, "parse_keydesc: Can't parse key '%s'", s); - } - else - { - /* Its got hyphens, so parse out the modifiers and keysym */ - token = strtok (keydesc, "-"); - - if (token == NULL) - { - /* It was nothing but hyphens */ - free (keydesc); - return cmdret_new (RET_FAILURE, "parse_keydesc: Can't parse key '%s'", s); - } - - do - { - next_token = strtok (NULL, "-"); - - if (next_token == NULL) - { - /* There is nothing more to parse and token contains the - keysym name. */ - key->sym = string_to_keysym (token); - - if (key->sym == NoSymbol) - { - cmdret *ret = cmdret_new (RET_FAILURE, "parse_keydesc: Unknown key '%s'", token); - free (keydesc); - return ret; - } - } - else - { - /* Which modifier is it? Only accept modifiers that are - present. ie don't accept a hyper modifier if the keymap - has no hyper key. */ - if (!strcmp (token, "C")) - { - key->state |= RP_CONTROL_MASK; - } - else if (!strcmp (token, "M")) - { - key->state |= RP_META_MASK; - } - else if (!strcmp (token, "A")) - { - key->state |= RP_ALT_MASK; - } - else if (!strcmp (token, "S")) - { - key->state |= RP_SHIFT_MASK; - } - else if (!strcmp (token, "s")) - { - key->state |= RP_SUPER_MASK; - } - else if (!strcmp (token, "H")) - { - key->state |= RP_HYPER_MASK; - } - else - { - free (keydesc); - return cmdret_new (RET_FAILURE, "parse_keydesc: Unknown modifier '%s'", token); - } - } - - token = next_token; - } while (next_token != NULL); - } - - /* Successfully parsed the key. */ - free (keydesc); - return NULL; -} - -static void -grab_rat (void) -{ - XGrabPointer (dpy, current_screen()->root, True, 0, - GrabModeAsync, GrabModeAsync, - None, current_screen()->rat, CurrentTime); -} - -static void -ungrab_rat (void) -{ - XUngrabPointer (dpy, CurrentTime); -} - -/* Unmanage window */ -cmdret * -cmd_unmanage (int interactive, struct cmdarg **args) -{ - if (args[0] == NULL && !interactive) - { - cmdret *ret; - char *s = list_unmanaged_windows(); - - if (s) - ret = cmdret_new (RET_SUCCESS, "%s", s); - else - ret = cmdret_new (RET_SUCCESS, NULL); - - free (s); - return ret; - } - - if (args[0]) - add_unmanaged_window(ARG_STRING(0)); - else - return cmdret_new (RET_FAILURE, "unmanage: at least one argument required"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Clear the unmanaged window list */ -cmdret * -cmd_clrunmanaged (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - clear_unmanaged_list(); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_undefinekey (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret = NULL; - rp_keymap *map; - struct rp_key *key; - - map = ARG (0, keymap); - key = ARG (1, key); - - /* If we're updating the top level map, we'll need to update the - keys grabbed. */ - if (map == find_keymap (defaults.top_kmap)) - ungrab_keys_all_wins (); - - /* If no comand is specified, then unbind the key. */ - if (!remove_keybinding (key->sym, key->state, map)) - ret = cmdret_new (RET_FAILURE, "undefinekey: key '%s' is not bound", ARG_STRING(1)); - - /* Update the grabbed keys. */ - if (map == find_keymap (defaults.top_kmap)) - grab_keys_all_wins (); - XSync (dpy, False); - - if (ret) - return ret; - else - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_definekey (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret = NULL; - rp_keymap *map; - struct rp_key *key; - char *cmd; - rp_action *key_action; - - map = ARG(0,keymap); - key = ARG(1,key); - cmd = ARG_STRING(2); - - /* If we're updating the top level map, we'll need to update the - keys grabbed. */ - if (map == find_keymap (defaults.top_kmap)) - ungrab_keys_all_wins (); - - if ((key_action = find_keybinding (key->sym, key->state, map))) - replace_keybinding (key_action, cmd); - else - add_keybinding (key->sym, key->state, cmd, map); - - /* Update the grabbed keys. */ - if (map == find_keymap (defaults.top_kmap)) - grab_keys_all_wins (); - XSync (dpy, False); - - if (ret) - return ret; - else - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_unimplemented (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - return cmdret_new (RET_FAILURE, "FIXME: unimplemented command"); -} - -cmdret * -cmd_source (int interactive UNUSED, struct cmdarg **args) -{ - FILE *fileptr; - - if ((fileptr = fopen (ARG_STRING(0), "r")) == NULL) - return cmdret_new (RET_FAILURE, "source: %s : %s", ARG_STRING(0), strerror(errno)); - else - { - set_close_on_exec (fileptr); - read_rc_file (fileptr); - fclose (fileptr); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_meta (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret = NULL; - struct rp_key key; - XEvent ev; - - if (current_window() == NULL) - return cmdret_new (RET_FAILURE, NULL); - - ev.xkey.type = KeyPress; - ev.xkey.display = dpy; - ev.xkey.window = current_window()->w; - - if (args[0]) - { - if((ret = parse_keydesc (ARG_STRING(0), &key))) - return ret; - - ev.xkey.state = rp_mask_to_x11_mask (key.state); - if(!(ev.xkey.keycode = XKeysymToKeycode (dpy, key.sym))) - return cmdret_new (RET_FAILURE, "meta: Couldn't convert keysym to keycode"); - } - else - { - ev.xkey.state = rp_mask_to_x11_mask (prefix_key.state); - ev.xkey.keycode = XKeysymToKeycode (dpy, prefix_key.sym); - } - XSendEvent (dpy, current_window()->w, False, KeyPressMask, &ev); - - /* XTestFakeKeyEvent (dpy, XKeysymToKeycode (dpy, 't'), True, 0); */ - - XSync (dpy, False); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_prev (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_window *cur, *win; - cur = current_window(); - win = group_prev_window (rp_current_group, cur); - - if (win) - set_active_window (win); - else if (cur) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); - else - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_MANAGED_WINDOWS); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_prev_frame (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - frame = find_frame_prev (current_frame()); - if (!frame) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_FRAME); - else - set_active_frame (frame, 0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_next (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_window *cur, *win; - cur = current_window(); - win = group_next_window (rp_current_group, cur); - - if (win) - set_active_window (win); - else if (cur) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); - else - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_MANAGED_WINDOWS); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_next_frame (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - frame = find_frame_next (current_frame()); - if (!frame) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_FRAME); - else - set_active_frame (frame, 0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_other (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_window *w; - -/* w = find_window_other (); */ - w = group_last_window (rp_current_group, current_screen()); - - if (!w) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); - else - set_active_window_force (w); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static int -string_to_window_number (char *str) -{ - int i; - char *s; - - for (i = 0, s = str; *s; s++) - { - if (*s < '0' || *s > '9') - break; - i = i * 10 + (*s - '0'); - } - - return *s ? -1 : i; -} - -static struct list_head * -trivial_completions (char* str UNUSED) -{ - struct list_head *list; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - return list; -} - -static struct list_head * -keymap_completions (char* str UNUSED) -{ - rp_keymap *cur; - struct list_head *list; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - list_for_each_entry (cur, &rp_keymaps, node) - { - struct sbuf *name; - - name = sbuf_new (0); - sbuf_copy (name, cur->name); - list_add_tail (&name->node, list); - } - - return list; -} - -static struct list_head * -window_completions (char* str UNUSED) -{ - rp_window_elem *cur; - struct list_head *list; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - /* Gather the names of all the windows. */ - list_for_each_entry (cur, &rp_current_group->mapped_windows, node) - { - struct sbuf *name; - - name = sbuf_new (0); - sbuf_copy (name, window_name (cur->win)); - list_add_tail (&name->node, list); - } - - return list; -} - -/* switch to window number or name */ -cmdret * -cmd_select (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret = NULL; - char *str; - int n; - - /* FIXME: This is manually done because of the kinds of things - select accepts. */ - if (args[0] == NULL) - str = get_input (MESSAGE_PROMPT_SWITCH_TO_WINDOW, hist_SELECT, - window_completions); - else - str = xstrdup (ARG_STRING(0)); - - /* User aborted. */ - if (str == NULL) - return cmdret_new (RET_FAILURE, NULL); - - /* Only search if the string contains something to search for. */ - if (strlen (str) > 0) - { - if (strlen (str) == 1 && str[0] == '-') - { - blank_frame (current_frame()); - ret = cmdret_new (RET_SUCCESS, NULL); - } - /* try by number */ - else if ((n = string_to_window_number (str)) >= 0) - { - rp_window_elem *elem = group_find_window_by_number (rp_current_group, n); - - if (elem) - { - goto_window (elem->win); - ret = cmdret_new (RET_SUCCESS, NULL); - } - else - { - /* show the window list as feedback */ - show_bar (current_screen (), defaults.window_fmt); - ret = cmdret_new (RET_FAILURE, - "select: unknown window number '%d'", n); - } - } - else - /* try by name */ - { - rp_window *win = find_window_name (str); - - if (win) - { - goto_window (win); - ret = cmdret_new (RET_SUCCESS, NULL); - } - else - ret = cmdret_new (RET_FAILURE, "select: unknown window '%s'", str); - } - } - else - /* Silently fail, since the user didn't provide a window spec */ - ret = cmdret_new (RET_SUCCESS, NULL); - - free (str); - - return ret; -} - -cmdret * -cmd_rename (int interactive UNUSED, struct cmdarg **args) -{ - if (current_window() == NULL) - return cmdret_new (RET_FAILURE, NULL); - - free (current_window()->user_name); - current_window()->user_name = xstrdup (ARG_STRING(0)); - current_window()->named = 1; - hook_run (&rp_title_changed_hook); - - /* Update the program bar. */ - update_window_names (current_screen(), defaults.window_fmt); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_delete (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - XEvent ev; - int status; - - if (current_window() == NULL) - return cmdret_new (RET_FAILURE, NULL); - - ev.xclient.type = ClientMessage; - ev.xclient.window = current_window()->w; - ev.xclient.message_type = wm_protocols; - ev.xclient.format = 32; - ev.xclient.data.l[0] = wm_delete; - ev.xclient.data.l[1] = CurrentTime; - - status = XSendEvent(dpy, current_window()->w, False, 0, &ev); - if (status == 0) - PRINT_DEBUG (("Delete window failed\n")); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_kill (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - if (current_window() == NULL) - return cmdret_new (RET_FAILURE, NULL); - - if (XKillClient(dpy, current_window()->w) == BadValue) - { - return cmdret_new (RET_FAILURE, - "kill failed (got BadValue, this may be a bug)"); - } - else - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_version (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - return cmdret_new (RET_SUCCESS, "%s", PACKAGE " " VERSION " (built " __DATE__ " " __TIME__ ")"); -} - -static char * -frame_selector (unsigned int n) -{ - if (n < strlen (defaults.frame_selectors)) - { - return xsprintf (" %c ", defaults.frame_selectors[n]); - } - else - { - return xsprintf (" %d ", n); - } -} - -/* Return true if ch is nth frame selector. */ -static int -frame_selector_match (char ch) -{ - size_t i; - - /* Is it in the frame selector string? */ - for (i=0; i<strlen (defaults.frame_selectors); i++) - { - if (ch == defaults.frame_selectors[i]) - return i; - } - - /* Maybe it's a number less than 9 and the frame selector doesn't - define that many selectors. */ - if (ch >= '0' && ch <= '9' - && (size_t)(ch - '0') >= strlen (defaults.frame_selectors)) - { - return ch - '0'; - } - - return -1; -} - -static cmdret * -read_string (struct argspec *spec, struct sbuf *s, int history_id, completion_fn fn, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - input = get_input (spec->prompt, history_id, fn); - - if (input) - { - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = spec->type; - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -read_keymap (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - if (s) - input = xstrdup (sbuf_get (s)); - else - input = get_input (spec->prompt, hist_KEYMAP, keymap_completions); - - if (input) - { - rp_keymap *map; - map = find_keymap (input); - if (map == NULL) - { - cmdret *ret = cmdret_new (RET_FAILURE, "unknown keymap '%s'", input); - free (input); - return ret; - } - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = spec->type; - (*arg)->arg.keymap = map; - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -read_keydesc (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - if (s) - input = xstrdup (sbuf_get (s)); - else - input = get_input (spec->prompt, hist_KEY, trivial_completions); - - if (input) - { - cmdret *ret; - struct rp_key *key = xmalloc (sizeof(struct rp_key)); - ret = parse_keydesc (input, key); - if (ret) { - free (key); - return ret; - } - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = spec->type; - (*arg)->arg.key = key; - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static struct list_head * -group_completions (char *str UNUSED) -{ - struct list_head *list; - rp_group *cur; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - /* Grab all the group names. */ - list_for_each_entry (cur, &rp_groups, node) - { - struct sbuf *s; - - s = sbuf_new (0); - /* A group may not have a name, so if it doesn't, use it's - number. */ - if (cur->name) - { - sbuf_copy (s, cur->name); - } - else - { - sbuf_printf (s, "%d", cur->number); - } - - list_add_tail (&s->node, list); - } - - return list; -} - -static struct list_head * -colon_completions (char* str UNUSED) -{ - int i; - struct user_command *uc; - struct sbuf *s; - struct list_head *list; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - /* Put all the aliases in our list. */ - for(i=0; i<alias_list_last; ++i) - { - s = sbuf_new (0); - sbuf_copy (s, alias_list[i].name); - /* The space is so when the user completes a space is - conveniently inserted after the command. */ - sbuf_concat (s, " "); - list_add_tail (&s->node, list); - } - - /* Put all the commands in our list. */ - list_for_each_entry (uc, &user_commands, node) - { - s = sbuf_new (0); - sbuf_copy (s, uc->name); - /* The space is so when the user completes a space is - conveniently inserted after the command. */ - sbuf_concat (s, " "); - list_add_tail (&s->node, list); - } - - return list; -} - -static cmdret * -read_command (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - return read_string (spec, s, hist_COMMAND, colon_completions, arg); -} - -static struct list_head * -exec_completions (char *str) -{ - size_t n = 256; - char *partial; - struct sbuf *line; - FILE *file; - struct list_head *head; - char *completion_string; - - /* Initialize our list. */ - head = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (head); - - /* FIXME: A Bash dependancy?? */ - completion_string = xsprintf("bash -c \"compgen -ac %s|sort\"", str); - file = popen (completion_string, "r"); - free (completion_string); - if (!file) - { - PRINT_ERROR (("popen failed\n")); - return head; - } - - partial = (char*)xmalloc (n); - - /* Read data from the file, split it into lines and store it in a - list. */ - line = sbuf_new (0); - while (fgets (partial, n, file) != NULL) - { - /* Read a chunk from the file into our line accumulator. */ - sbuf_concat (line, partial); - - if (feof(file) || (*(sbuf_get (line) + strlen(sbuf_get (line)) - 1) == '\n')) - { - char *s; - struct sbuf *elem; - - s = sbuf_get (line); - - /* Frob the newline into */ - if (*(s + strlen(s) - 1) == '\n') - *(s + strlen(s) - 1) = '\0'; - - /* Add our line to the list. */ - elem = sbuf_new (0); - sbuf_copy (elem, s); - list_add_tail (&elem->node, head); - - sbuf_clear (line); - } - } - - sbuf_free (line); - - free (partial); - pclose (file); - - return head; -} - -static cmdret * -read_shellcmd (struct argspec *spec, struct sbuf *s, struct cmdarg **arg, const char *command_name) -{ - cmdret *ret; - - ret = read_string (spec, s, hist_SHELLCMD, exec_completions, arg); - if (command_name && !s && !ret) { - /* store for command history */ - char *str = xmalloc (strlen(command_name) + strlen((*arg)->string) + 2); - sprintf (str, "%s %s", command_name, (*arg)->string); - history_add (hist_COMMAND, str); - free(str); - } - return ret; -} - -/* Return NULL on abort/failure. */ -static cmdret * -read_frame (struct sbuf *s, struct cmdarg **arg) -{ - rp_frame *frame; - int fnum = -1; - KeySym c; - char keysym_buf[513]; - int keysym_bufsize = sizeof (keysym_buf); - unsigned int mod; - Window *wins; - int i, j; - rp_frame *cur; - int frames; - - if (s == NULL) - { - frames = 0; - for (j=0; j<num_screens; j++) - frames += num_frames(&screens[j]); - - wins = xmalloc (sizeof (Window) * frames); - - /* Loop through each frame and display its number in it's top - left corner. */ - i = 0; - for (j=0; j<num_screens; j++) - { - XSetWindowAttributes attr; - rp_screen *screen = &screens[j]; - - /* Set up the window attributes to be used in the loop. */ - attr.border_pixel = screen->fg_color; - attr.background_pixel = screen->bg_color; - attr.override_redirect = True; - - list_for_each_entry (cur, &screen->frames, node) - { - int width, height; - char *num; - - /* Create the string to be displayed in the window and - determine the height and width of the window. */ - /* num = xsprintf (" %d ", cur->number); */ - num = frame_selector (cur->number); - width = defaults.bar_x_padding * 2 + rp_text_width (screen, num, -1); - height = (FONT_HEIGHT (screen) + defaults.bar_y_padding * 2); - - /* Create and map the window. */ - wins[i] = XCreateWindow (dpy, screen->root, screen->left + cur->x, screen->top + cur->y, width, height, 1, - CopyFromParent, CopyFromParent, CopyFromParent, - CWOverrideRedirect | CWBorderPixel | CWBackPixel, - &attr); - XMapWindow (dpy, wins[i]); - XClearWindow (dpy, wins[i]); - - /* Display the frame's number inside the window. */ - rp_draw_string (screen, wins[i], STYLE_NORMAL, - defaults.bar_x_padding, - defaults.bar_y_padding + FONT_ASCENT(screen), - num, -1); - - free (num); - i++; - } - } - XSync (dpy, False); - - /* Read a key. */ - read_single_key (&c, &mod, keysym_buf, keysym_bufsize); - - /* Destroy our number windows and free the array. */ - for (i=0; i<frames; i++) - XDestroyWindow (dpy, wins[i]); - - free (wins); - - /* FIXME: We only handle one character long keysym names. */ - if (strlen (keysym_buf) == 1) - { - fnum = frame_selector_match (keysym_buf[0]); - if (fnum == -1) - goto frame_fail; - } - else - { - goto frame_fail; - } - } - else - { - fnum = strtol (sbuf_get (s), NULL, 10); - } - /* Now that we have a frame number to go to, let's try to jump to - it. */ - frame = find_frame_number (fnum); - if (frame) - { - /* We have to return a string, because commands get lists of - strings. Sucky, yes. The command is simply going to parse it - back into an rp_frame. */ - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_FRAME; - (*arg)->string = NULL; - (*arg)->arg.frame = frame; - return NULL; - } - - - frame_fail: - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -read_window (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - rp_window *win = NULL; - char *name; - int n; - - if (s) - name = xstrdup (sbuf_get (s)); - else - name = get_input (spec->prompt, hist_WINDOW, window_completions); - - if (name) - { - /* try by number */ - if ((n = string_to_window_number (name)) >= 0) - { - rp_window_elem *elem = group_find_window_by_number (rp_current_group, n); - if (elem) - win = elem->win; - } - else - /* try by name */ - { - win = find_window_name (name); - } - - if (win) - { - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_WINDOW; - (*arg)->arg.win = win; - (*arg)->string = name; - return NULL; - } - else - { - free (name); - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); - } - } - - /* user abort. */ - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static int -parse_wingravity (char *data) -{ - int ret = -1; - - if (!strcasecmp (data, "northwest") || !strcasecmp (data, "nw") || !strcmp (data, "7")) - ret = NorthWestGravity; - if (!strcasecmp (data, "north") || !strcasecmp (data, "n") || !strcmp (data, "8")) - ret = NorthGravity; - if (!strcasecmp (data, "northeast") || !strcasecmp (data, "ne") || !strcmp (data, "9")) - ret = NorthEastGravity; - if (!strcasecmp (data, "west") || !strcasecmp (data, "w") || !strcmp (data, "4")) - ret = WestGravity; - if (!strcasecmp (data, "center") || !strcasecmp (data, "c") || !strcmp (data, "5")) - ret = CenterGravity; - if (!strcasecmp (data, "east") || !strcasecmp (data, "e") || !strcmp (data, "6")) - ret = EastGravity; - if (!strcasecmp (data, "southwest") || !strcasecmp (data, "sw") || !strcmp (data, "1")) - ret = SouthWestGravity; - if (!strcasecmp (data, "south") || !strcasecmp (data, "s") || !strcmp (data, "2")) - ret = SouthGravity; - if (!strcasecmp (data, "southeast") || !strcasecmp (data, "se") || !strcmp (data, "3")) - ret = SouthEastGravity; - - return ret; -} - -static cmdret * -read_gravity (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - input = get_input (spec->prompt, hist_GRAVITY, trivial_completions); - - if (input) - { - int g = parse_wingravity (input); - if (g == -1) - { - cmdret *ret = cmdret_new (RET_FAILURE, "bad gravity '%s'", input); - free (input); - return ret; - } - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_GRAVITY; - (*arg)->arg.gravity = g; - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Given a string, find a matching group. First check if the string is - a number, then check if it's the name of a group. */ -static rp_group * -find_group (char *str) -{ - rp_group *group; - int n; - - /* Check if the user typed a group number. */ - n = string_to_window_number (str); - if (n >= 0) - { - group = groups_find_group_by_number (n); - if (group) - return group; - } - - group = groups_find_group_by_name (str, 0); - return group; -} - -static cmdret * -read_group (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - input = get_input (spec->prompt, hist_GROUP, group_completions); - - if (input) - { - rp_group *g = find_group (input); - - if (g) - { - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_GROUP; - (*arg)->arg.group = g; - (*arg)->string = input; - return NULL; - } - else - { - cmdret *ret = cmdret_new (RET_FAILURE, "unknown group '%s'", input); - free (input); - return ret; - } - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static struct list_head * -hook_completions (char* str UNUSED) -{ - struct list_head *list; - struct rp_hook_db_entry *entry; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - for (entry = rp_hook_db; entry->name; entry++) - { - struct sbuf *hookname; - - hookname = sbuf_new(0); - sbuf_copy (hookname, entry->name); - list_add_tail (&hookname->node, list); - } - - return list; -} - -static cmdret * -read_hook (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - input = get_input (spec->prompt, hist_HOOK, hook_completions); - - if (input) - { - struct list_head *hook = hook_lookup (input); - - if (hook) - { - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_HOOK; - (*arg)->arg.hook = hook; - (*arg)->string = input; - return NULL; - } - else - { - cmdret *ret = cmdret_new (RET_FAILURE, "unknown hook '%s'", input); - free (input); - return ret; - } - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static struct set_var * -find_variable (char *str) -{ - struct set_var *cur; - list_for_each_entry (cur, &set_vars, node) - { - if (!strcmp (str, cur->var)) - return cur; - } - return NULL; -} - -static struct list_head * -var_completions (char *str UNUSED) -{ - struct list_head *list; - struct set_var *cur; - - /* Initialize our list. */ - list = xmalloc (sizeof (struct list_head)); - INIT_LIST_HEAD (list); - - /* Grab all the group names. */ - list_for_each_entry (cur, &set_vars, node) - { - struct sbuf *s; - s = sbuf_new (0); - sbuf_copy (s, cur->var); - list_add_tail (&s->node, list); - } - - return list; -} - -static cmdret * -read_variable (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - input = get_input (spec->prompt, hist_VARIABLE, var_completions); - - if (input) - { - struct set_var *var = find_variable (input); - if (var == NULL) - { - cmdret *ret = cmdret_new (RET_FAILURE, "unknown variable '%s'", input); - free (input); - return ret; - } - - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_VARIABLE; - (*arg)->arg.variable = var; - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -read_number (struct argspec *spec, struct sbuf *s, struct cmdarg **arg) -{ - char *input; - - if (s) - input = xstrdup (sbuf_get(s)); - else - /* numbers should perhaps be more fine grained, or hist_NONE */ - input = get_input (spec->prompt, hist_OTHER, trivial_completions); - - if (input) - { - *arg = xmalloc (sizeof(struct cmdarg)); - (*arg)->type = arg_NUMBER; - (*arg)->arg.number = strtol (input, NULL, 10); - (*arg)->string = input; - return NULL; - } - - *arg = NULL; - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -read_arg (struct argspec *spec, struct sbuf *s, struct cmdarg **arg, const char *command_name) -{ - cmdret *ret = NULL; - - switch (spec->type) - { - case arg_STRING: - case arg_REST: - case arg_RAW: - ret = read_string (spec, s, hist_OTHER, trivial_completions, arg); - break; - case arg_KEYMAP: - ret = read_keymap (spec, s, arg); - break; - case arg_KEY: - ret = read_keydesc (spec, s, arg); - break; - case arg_NUMBER: - ret = read_number (spec, s, arg); - break; - case arg_GRAVITY: - ret = read_gravity (spec, s, arg); - break; - case arg_COMMAND: - ret = read_command (spec, s, arg); - break; - case arg_SHELLCMD: - ret = read_shellcmd (spec, s, arg, command_name); - break; - case arg_WINDOW: - ret = read_window (spec, s, arg); - break; - case arg_FRAME: - ret = read_frame (s, arg); - break; - case arg_GROUP: - ret = read_group (spec, s, arg); - break; - case arg_HOOK: - ret = read_hook (spec, s, arg); - break; - case arg_VARIABLE: - ret = read_variable (spec, s, arg); - break; - } - - return ret; -} - -/* Return -1 on failure. Return the number of args on success. */ -static cmdret * -parsed_input_to_args (int num_args, struct argspec *argspec, struct list_head *list, - struct list_head *args, int *parsed_args, const char *command_name) -{ - struct sbuf *s; - struct cmdarg *arg; - cmdret *ret; - - PRINT_DEBUG (("list len: %d\n", list_size (list))); - - *parsed_args = 0; - - /* Convert the existing entries to cmdarg's. */ - list_for_each_entry (s, list, node) - { - if (*parsed_args >= num_args) break; - ret = read_arg (&argspec[*parsed_args], s, &arg, command_name); - /* If there was an error, then abort. */ - if (ret) - return ret; - - list_add_tail (&arg->node, args); - (*parsed_args)++; - } - - return NULL; -} - -/* Prompt the user for missing arguments. Returns non-zero on - failure. 0 on success. */ -static cmdret * -fill_in_missing_args (struct user_command *cmd, struct list_head *list, struct list_head *args, const char *command_name) -{ - cmdret *ret; - struct cmdarg *arg; - int i = 0; - - ret = parsed_input_to_args (cmd->num_args, cmd->args, list, args, &i, command_name); - if (ret) - return ret; - - /* Fill in the rest of the required arguments. */ - for(; i < cmd->i_required_args; i++) - { - ret = read_arg (&cmd->args[i], NULL, &arg, command_name); - if (ret) - return ret; - list_add_tail (&arg->node, args); - } - - return NULL; -} - -/* Stick a list of sbuf's in list. if nargs >= 0 then only parse nargs - arguments and and the rest of the string to the list. Return 0 on - success. non-zero on failure. When raw is true, then when we hit - nargs, we should keep any whitespace at the beginning. When false, - gobble the whitespace. */ -static cmdret * -parse_args (char *str, struct list_head *list, int nargs, int raw) -{ - cmdret *ret = NULL; - char *i; - char *tmp; - int len = 0; - int str_escape = 0; - int in_str = 0; - int gobble = 1; - int parsed_args = 0; - - if (str == NULL) - return NULL; - - tmp = malloc (strlen(str) + 1); - - for (i=str; *i; i++) - { - /* Have we hit the arg limit? */ - if (raw && parsed_args >= nargs) - { - struct sbuf *s = sbuf_new(0); - if (!raw) - while (*i && isspace (*i)) i++; - if (*i) - { - sbuf_concat(s, i); - list_add_tail (&s->node, list); - } - len = 0; - break; - } - - /* Should we eat the whitespace? */ - if (gobble) - { - while (*i && isspace (*i)) i++; - gobble = 0; - } - - /* Escaped characters always get added. */ - if (str_escape) - { - tmp[len] = *i; - len++; - str_escape = 0; - } - else if (*i == '\\') - { - str_escape = 1; - } - else if (*i == '"') - { - if (in_str) - { - /* End the arg. */ - struct sbuf *s = sbuf_new(0); - sbuf_nconcat(s, tmp, len); - list_add_tail (&s->node, list); - len = 0; - gobble = 1; - in_str = 0; - parsed_args++; - } - else if (len == 0) - { - /* A string open can only start at the beginning of an - argument. */ - in_str = 1; - } - else - { - ret = cmdret_new (RET_FAILURE, "parse error in '%s'", str); - break; - } - } - else if (isspace (*i) && !in_str) - { - /* End the current arg, and start a new one. */ - struct sbuf *s = sbuf_new(0); - sbuf_nconcat(s, tmp, len); - list_add_tail (&s->node, list); - len = 0; - gobble = 1; - parsed_args++; - } - else - { - /* Add the character to the argument. */ - tmp[len] = *i; - len++; - } - } - /* Add the remaining text in tmp. */ - if (ret == NULL && len) - { - struct sbuf *s = sbuf_new(0); - sbuf_nconcat(s, tmp, len); - list_add_tail (&s->node, list); - } - - /* Free our memory and return. */ - free (tmp); - return ret; -} - -/* Convert the list to an array, for easier access in commands. */ -static struct cmdarg ** -arg_array (struct list_head *head) -{ - int i = 0; - struct cmdarg **args, *cur; - - args = (struct cmdarg **)xmalloc (sizeof (struct cmdarg *) * (list_size (head) + 1)); - list_for_each_entry (cur, head, node) - { - args[i] = cur; - i++; - } - - /* NULL terminate the array. */ - args[list_size (head)] = NULL; - return args; -} - -static void -arg_free (struct cmdarg *arg) -{ - if (arg) - { - /* read_frame doesn't fill in string. */ - if (arg->string) - free (arg->string); - switch (arg->type) - { - case arg_KEY: - free (arg->arg.key); - break; - case arg_REST: - case arg_STRING: - case arg_NUMBER: - case arg_WINDOW: - case arg_FRAME: - case arg_COMMAND: - case arg_SHELLCMD: - case arg_KEYMAP: - case arg_GRAVITY: - case arg_GROUP: - case arg_HOOK: - case arg_VARIABLE: - case arg_RAW: - /* Do nothing */ - break; - default: - PRINT_ERROR (("Missed an arg type.\n")); - break; - } - free (arg); - } -} - -cmdret * -command (int interactive, char *data) -{ - /* This static counter is used to exit from recursive alias calls. */ - static int alias_recursive_depth = 0; - cmdret *result = NULL; - char *cmd, *rest; - char *input; - user_command *uc; - int i; - - if (data == NULL) - return cmdret_new (RET_FAILURE, NULL); - - /* get a writable copy for strtok() */ - input = xstrdup (data); - - cmd = input; - /* skip beginning whitespace. */ - while (*cmd && isspace (*cmd)) cmd++; - rest = cmd; - /* skip til we get to whitespace */ - while (*rest && !isspace (*rest)) rest++; - /* mark that spot as the end of the command and make rest point to - the rest of the string. */ - if (*rest) - { - *rest = 0; - rest++; - } - - PRINT_DEBUG (("cmd==%s rest==%s\n", cmd, rest?rest:"NULL")); - - /* Look for it in the aliases, first. */ - for (i=0; i<alias_list_last; i++) - { - if (!strcmp (cmd, alias_list[i].name)) - { - struct sbuf *s; - - /* Append any arguments onto the end of the alias' command. */ - s = sbuf_new (0); - sbuf_concat (s, alias_list[i].alias); - if (rest != NULL && *rest) - sbuf_printf_concat (s, " %s", rest); - - alias_recursive_depth++; - if (alias_recursive_depth >= MAX_ALIAS_RECURSIVE_DEPTH) - result = cmdret_new (RET_FAILURE, "command: alias recursion has exceeded maximum depth"); - else - result = command (interactive, sbuf_get (s)); - alias_recursive_depth--; - - sbuf_free (s); - goto done; - } - } - - /* If it wasn't an alias, maybe its a command. */ - list_for_each_entry (uc, &user_commands, node) - { - if (!strcmp (cmd, uc->name)) - { - struct sbuf *scur; - struct cmdarg *acur; - struct list_head *iter, *tmp; - struct list_head head, args; - int nargs = 0, raw = 0; - - INIT_LIST_HEAD (&args); - INIT_LIST_HEAD (&head); - - /* We need to tell parse_args about arg_REST and arg_SHELLCMD. */ - for (i=0; i<uc->num_args; i++) - if (uc->args[i].type == arg_REST - || uc->args[i].type == arg_COMMAND - || uc->args[i].type == arg_SHELLCMD - || uc->args[i].type == arg_RAW) - { - raw = 1; - nargs = i; - break; - } - - /* Parse the arguments and call the function. */ - result = parse_args (rest, &head, nargs, raw); - if (result) - goto free_lists; - - /* Interactive commands prompt the user for missing args. */ - if (interactive) - result = fill_in_missing_args (uc, &head, &args, uc->name); - else - { - int parsed_args; - result = parsed_input_to_args (uc->num_args, uc->args, &head, &args, &parsed_args, uc->name); - } - - if (result == NULL) - { - if ((interactive && list_size (&args) < uc->i_required_args) - || (!interactive && list_size (&args) < uc->ni_required_args)) - { - result = cmdret_new (RET_FAILURE, "not enough arguments."); - goto free_lists; - } - else if (list_size (&head) > uc->num_args) - { - result = cmdret_new (RET_FAILURE, "too many arguments."); - goto free_lists; - } - else - { - struct cmdarg **cmdargs = arg_array (&args); - result = uc->func (interactive, cmdargs); - free (cmdargs); - } - } - - free_lists: - /* Free the parsed strings */ - list_for_each_safe_entry (scur, iter, tmp, &head, node) - sbuf_free(scur); - /* Free the args */ - list_for_each_safe_entry (acur, iter, tmp, &args, node) - arg_free (acur); - - goto done; - } - } - - result = cmdret_new (RET_FAILURE, MESSAGE_UNKNOWN_COMMAND, cmd); - - done: - free (input); - return result; -} - -cmdret * -cmd_colon (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *result; - char *input; - - if (args[0] == NULL) - input = get_input (MESSAGE_PROMPT_COMMAND, hist_COMMAND, colon_completions); - else - input = get_more_input (MESSAGE_PROMPT_COMMAND, ARG_STRING(0), hist_COMMAND, - colon_completions); - - /* User aborted. */ - if (input == NULL) - return cmdret_new (RET_FAILURE, NULL); - - result = command (1, input); - free (input); - return result; -} - -cmdret * -cmd_exec (int interactive UNUSED, struct cmdarg **args) -{ - spawn (ARG_STRING(0), 0, current_frame()); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_execa (int interactive UNUSED, struct cmdarg **args) -{ - spawn (ARG_STRING(0), 0, NULL); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_execf (int interactive UNUSED, struct cmdarg **args) -{ - spawn (ARG_STRING(1), 0, ARG(0,frame)); - return cmdret_new (RET_SUCCESS, NULL); -} - -int -spawn(char *cmd, int raw, rp_frame *frame) -{ - rp_child_info *child; - int pid; - - pid = fork(); - if (pid == 0) - { - /* Some process setup to make sure the spawned process runs - in its own session. */ - putenv(current_screen()->display_string); -#ifdef HAVE_SETSID - setsid(); -#endif -#if defined (HAVE_SETPGID) - setpgid (0, 0); -#elif defined (HAVE_SETPGRP) - setpgrp (0, 0); -#endif - /* raw means don't run it through sh. */ - if (raw) - execl (cmd, cmd, NULL); - execl("/bin/sh", "sh", "-c", cmd, NULL); - _exit(EXIT_FAILURE); - } - -/* wait((int *) 0); */ - PRINT_DEBUG (("spawned %s\n", cmd)); - - /* Add this child process to our list. */ - child = malloc (sizeof (rp_child_info)); - child->cmd = strdup (cmd); - child->pid = pid; - child->terminated = 0; - child->frame = frame; - child->group = rp_current_group; - child->screen = current_screen(); - child->window_mapped = 0; - - list_add (&child->node, &rp_children); - - return pid; -} - -/* Switch to a different Window Manager. Thanks to -"Chr. v. Stuckrad" <stucki@math.fu-berlin.de> for the patch. */ -cmdret * -cmd_newwm(int interactive UNUSED, struct cmdarg **args) -{ - /* in the event loop, this will switch WMs. */ - rp_exec_newwm = xstrdup (ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_quit(int interactive UNUSED, struct cmdarg **args UNUSED) -{ - kill_signalled = 1; - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Show the current time on the bar. Thanks to Martin Samuelsson - <cosis@lysator.liu.se> for the patch. Thanks to Jonathan Walther - <krooger@debian.org> for making it pretty. */ -cmdret * -cmd_time (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - char *msg, *tmp; - time_t timep; - cmdret *ret; - - timep = time (NULL); - tmp = ctime (&timep); - msg = xstrdup (tmp); - msg[strcspn (msg, "\n")] = '\0' ; /* Remove the newline */ - - ret = cmdret_new (RET_SUCCESS, "%s", msg); - free (msg); - - return ret; -} - -/* Assign a new number to a window ala screen's number command. */ -cmdret * -cmd_number (int interactive UNUSED, struct cmdarg **args) -{ - int old_number, new_number; - rp_window_elem *other_win, *win; - - if (args[0] == NULL) - { - /* XXX: Fix this. */ - print_window_information (rp_current_group, current_window()); - return cmdret_new (RET_SUCCESS, NULL); - } - - /* Gather the args. */ - new_number = ARG(0,number); - if (args[1]) - win = group_find_window_by_number (rp_current_group, ARG(1,number)); - else - win = group_find_window (&rp_current_group->mapped_windows, current_window()); - - /* Make the switch. */ - if ( new_number >= 0 && win) - { - /* Find other window with same number and give it old number. */ - other_win = group_find_window_by_number (rp_current_group, new_number); - if (other_win != NULL) - { - old_number = win->number; - other_win->number = old_number; - - /* Resort the window in the list */ - group_resort_window (rp_current_group, other_win); - } - else - { - numset_release (rp_current_group->numset, win->number); - } - - win->number = new_number; - numset_add_num (rp_current_group->numset, new_number); - - /* resort the the window in the list */ - group_resort_window (rp_current_group, win); - - /* Update the window list. */ - update_window_names (win->win->scr, defaults.window_fmt); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Toggle the display of the program bar */ -cmdret * -cmd_windows (int interactive, struct cmdarg **args) -{ - struct sbuf *window_list = NULL; - int dummy; - rp_screen *s; - char *fmt; - - if (args[0] == NULL) - fmt = defaults.window_fmt; - else - fmt = ARG_STRING(0); - - if (interactive) - { - s = current_screen (); - /* This is a yukky hack. If the bar already hidden then show the - bar. This handles the case when msgwait is 0 (the bar sticks) - and the user uses this command to toggle the bar on and - off. OR the timeout is >0 then show the bar. Which means, - always show the bar if msgwait is >0 which fixes the case - when a command in the prefix hook displays the bar. */ - if (!hide_bar (s) || defaults.bar_timeout > 0) show_bar (s, fmt); - - return cmdret_new (RET_SUCCESS, NULL); - } - else - { - cmdret *ret; - - window_list = sbuf_new (0); - get_window_list (fmt, "\n", window_list, &dummy, &dummy); - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (window_list)); - sbuf_free (window_list); - return ret; - } -} - -cmdret * -cmd_abort (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Redisplay the current window by sending 2 resize events. */ -cmdret * -cmd_redisplay (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - force_maximize (current_window()); - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Reassign the prefix key. */ -cmdret * -cmd_escape (int interactive UNUSED, struct cmdarg **args) -{ - struct rp_key *key; - rp_action *action; - rp_keymap *map, *top; - - top = find_keymap (defaults.top_kmap); - map = find_keymap (ROOT_KEYMAP); - key = ARG(0,key); - - /* Update the "other" keybinding */ - action = find_keybinding(prefix_key.sym, prefix_key.state, map); - if (action != NULL && !strcmp (action->data, "other")) - { - action->key = key->sym; - action->state = key->state; - } - - /* Update the "meta" keybinding */ - action = find_keybinding(prefix_key.sym, 0, map); - if (action != NULL && !strcmp (action->data, "meta")) - { - action->key = key->sym; - if (key->state != 0) - action->state = 0; - else - action->state = RP_CONTROL_MASK; - } - - /* Remove the grab on the current prefix key */ - ungrab_keys_all_wins(); - - action = find_keybinding(prefix_key.sym, prefix_key.state, top); - if (action != NULL && !strcmp (action->data, "readkey " ROOT_KEYMAP)) - { - action->key = key->sym; - action->state = key->state; - } - - /* Add the grab for the new prefix key */ - grab_keys_all_wins(); - - /* Finally, keep track of the current prefix. */ - prefix_key.sym = key->sym; - prefix_key.state = key->state; - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* User accessible call to display the passed in string. */ -cmdret * -cmd_echo (int interactive UNUSED, struct cmdarg **args) -{ - marked_message_printf (0, 0, "%s", ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - - -static cmdret * -read_split (char *str, int max, int *p) -{ - int a, b; - - if (sscanf(str, "%d/%d", &a, &b) == 2) - { - *p = (int)(max * (float)(a) / (float)(b)); - } - else if (sscanf(str, "%d", p) == 1) - { - if (*p < 0) - *p = max + *p; - } - else - { - /* Failed to read input. */ - return cmdret_new (RET_FAILURE, "bad split '%s'", str); - } - - return NULL; -} - -cmdret * -cmd_v_split (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret; - rp_frame *frame; - int pixels; - - push_frame_undo (current_screen()); /* fdump to stack */ - frame = current_frame(); - - /* Default to dividing the frame in half. */ - if (args[0] == NULL) - pixels = frame->height / 2; - else - { - ret = read_split (ARG_STRING(0), frame->height, &pixels); - if (ret) - return ret; - } - - if (pixels > 0) - h_split_frame (frame, pixels); - else - return cmdret_new (RET_FAILURE, "vsplit: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_h_split (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret; - rp_frame *frame; - int pixels; - - push_frame_undo (current_screen()); /* fdump to stack */ - frame = current_frame(); - - /* Default to dividing the frame in half. */ - if (args[0] == NULL) - pixels = frame->width / 2; - else - { - ret = read_split (ARG_STRING(0), frame->width, &pixels); - if (ret) - return ret; - } - - if (pixels > 0) - v_split_frame (frame, pixels); - else - return cmdret_new (RET_FAILURE, "hsplit: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_only (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - push_frame_undo (current_screen()); /* fdump to stack */ - remove_all_splits(); - maximize (current_window()); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_remove (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s = current_screen(); - rp_frame *frame; - - push_frame_undo (current_screen()); /* fdump to stack */ - - if (num_frames(s) <= 1) - { - return cmdret_new (RET_FAILURE, "remove: cannot remove only frame"); - } - - frame = find_frame_next (current_frame()); - - if (frame) - { - remove_frame (current_frame()); - set_active_frame (frame, 0); - show_frame_indicator(0); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_shrink (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - push_frame_undo (current_screen()); /* fdump to stack */ - resize_shrink_to_window (current_frame()); - return cmdret_new (RET_SUCCESS, NULL); -} - -typedef struct resize_binding resize_binding; - -struct resize_binding -{ - struct rp_key key; - enum resize_action {RESIZE_UNKNOWN=0, RESIZE_VGROW, RESIZE_VSHRINK, - RESIZE_HGROW, RESIZE_HSHRINK, RESIZE_TO_WINDOW, - RESIZE_ABORT, RESIZE_END } action; -}; - -static resize_binding resize_bindings[] = - { {{INPUT_ABORT_KEY, INPUT_ABORT_MODIFIER}, RESIZE_ABORT}, - {{RESIZE_VGROW_KEY, RESIZE_VGROW_MODIFIER}, RESIZE_VGROW}, - {{RESIZE_VSHRINK_KEY, RESIZE_VSHRINK_MODIFIER}, RESIZE_VSHRINK}, - {{RESIZE_HGROW_KEY, RESIZE_HGROW_MODIFIER}, RESIZE_HGROW}, - {{RESIZE_HSHRINK_KEY, RESIZE_HSHRINK_MODIFIER}, RESIZE_HSHRINK}, - {{RESIZE_SHRINK_TO_WINDOW_KEY,RESIZE_SHRINK_TO_WINDOW_MODIFIER},RESIZE_TO_WINDOW}, - {{RESIZE_END_KEY, RESIZE_END_MODIFIER}, RESIZE_END}, -/* Some more default keys - * (after the values from conf.h, so that they have lower priority): - * first the arrow keys: */ - {{XK_Escape, 0}, RESIZE_ABORT}, - {{XK_Down, 0}, RESIZE_VGROW}, - {{XK_Up, 0}, RESIZE_VSHRINK}, - {{XK_Right, 0}, RESIZE_HGROW}, - {{XK_Left, 0}, RESIZE_HSHRINK}, -/* some vi-like bindings: */ - {{XK_j, 0}, RESIZE_VGROW}, - {{XK_k, 0}, RESIZE_VSHRINK}, - {{XK_l, 0}, RESIZE_HGROW}, - {{XK_h, 0}, RESIZE_HSHRINK}, - {{0, 0}, RESIZE_UNKNOWN} }; - - -cmdret * -cmd_resize (int interactive, struct cmdarg **args) -{ - rp_screen *s = current_screen (); - - /* If the user calls resize with arguments, treat it like the - non-interactive version. */ - if (interactive && args[0] == NULL) - { - char buffer[513]; - unsigned int mod; - KeySym c; - struct list_head *bk; - - /* If we haven't got at least 2 frames, there isn't anything to - scale. */ - if (num_frames (s) < 2) - return cmdret_new (RET_FAILURE, NULL); - - /* Save the frameset in case the user aborts. */ - bk = screen_copy_frameset (s); - - /* Get ready to read keys. */ - grab_rat(); - XGrabKeyboard (dpy, s->key_window, False, GrabModeAsync, GrabModeAsync, CurrentTime); - - while (1) - { - struct resize_binding *binding; - - show_frame_message ("Resize frame"); - read_key (&c, &mod, buffer, sizeof (buffer)); - - /* Convert the mask to be compatible with ratpoison. */ - mod = x11_mask_to_rp_mask (mod); - - for (binding = resize_bindings; binding->action; binding++) - { - if (c == binding->key.sym && mod == binding->key.state) - break; - } - - if (binding->action == RESIZE_VGROW) - resize_frame_vertically (current_frame(), defaults.frame_resize_unit); - else if (binding->action == RESIZE_VSHRINK) - resize_frame_vertically (current_frame(), -defaults.frame_resize_unit); - else if (binding->action == RESIZE_HGROW) - resize_frame_horizontally (current_frame(), defaults.frame_resize_unit); - else if (binding->action == RESIZE_HSHRINK) - resize_frame_horizontally (current_frame(), -defaults.frame_resize_unit); - else if (binding->action == RESIZE_TO_WINDOW) - resize_shrink_to_window (current_frame()); - else if (binding->action == RESIZE_ABORT) - { - rp_frame *cur; - - screen_restore_frameset (s, bk); - list_for_each_entry (cur, &s->frames, node) - { - maximize_all_windows_in_frame (cur); - } - break; - } - else if (binding->action == RESIZE_END) - { - frameset_free (bk); - break; - } - } - - /* It is our responsibility to free this. */ - free (bk); - - hide_frame_indicator (); - ungrab_rat(); - XUngrabKeyboard (dpy, CurrentTime); - } - else - { - if (args[0] && args[1]) - { - resize_frame_horizontally (current_frame(), ARG(0,number)); - resize_frame_vertically (current_frame(), ARG(1,number)); - } - else - return cmdret_new (RET_FAILURE, "resize: two numeric arguments required"); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_resizeunit (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.frame_resize_unit); - - if (ARG(0,number) >= 0) - defaults.frame_resize_unit = ARG(0,number); - else - return cmdret_new (RET_FAILURE, "defresizeunit: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* banish the rat pointer */ -cmdret * -cmd_banish (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s; - - s = current_screen (); - - XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, s->left + s->width - 2, s->top + s->height - 2); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_banishrel (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s = current_screen(); - rp_window *w = current_window(); - rp_frame *f = current_frame(); - - if (w) - XWarpPointer (dpy, None, w->w, 0, 0, 0, 0, w->x + w->width - 2, w->y + w->height - 2); - else - XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, f->x + f->width, f->y + f->height); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_ratinfo (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s; - Window root_win, child_win; - int mouse_x, mouse_y, root_x, root_y; - unsigned int mask; - - s = current_screen(); - XQueryPointer (dpy, s->root, &root_win, &child_win, &mouse_x, &mouse_y, &root_x, &root_y, &mask); - - return cmdret_new (RET_SUCCESS, "%d %d", mouse_x, mouse_y); -} - -cmdret * -cmd_ratrelinfo (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s; - rp_window *rpw; - rp_frame *f; - Window root_win, child_win; - int mouse_x, mouse_y, root_x, root_y; - unsigned int mask; - - s = current_screen(); - rpw = current_window(); - f = current_frame(); - - if (rpw) - XQueryPointer (dpy, rpw->w, &root_win, &child_win, &mouse_x, &mouse_y, &root_x, &root_y, &mask); - else - { - XQueryPointer (dpy, s->root, &root_win, &child_win, &mouse_x, &mouse_y, &root_x, &root_y, &mask); - root_x -= f->x; - root_y -= f->y; - } - - return cmdret_new (RET_SUCCESS, "%d %d", root_x, root_y); -} - -cmdret * -cmd_ratwarp (int interactive UNUSED, struct cmdarg **args) -{ - rp_screen *s; - - s = current_screen (); - XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, ARG(0,number), ARG(1,number)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_ratrelwarp (int interactive UNUSED, struct cmdarg **args) -{ - XWarpPointer (dpy, None, None, 0, 0, 0, 0, ARG(0,number), ARG(1,number)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_ratclick (int interactive UNUSED, struct cmdarg **args) -{ - int button = 1; - - if (args[0]) - { - button = ARG(0,number); - if (button < 1 || button > 3) - return cmdret_new (RET_SUCCESS, "ratclick: invalid argument"); - } - -#ifdef HAVE_LIBXTST - XTestFakeButtonEvent(dpy, button, True, CurrentTime); - XTestFakeButtonEvent(dpy, button, False, CurrentTime); - return cmdret_new (RET_SUCCESS, NULL); -#else - return cmdret_new (RET_FAILURE, "ratclick: Please compile with the Xtst extension"); -#endif -} - -cmdret * -cmd_rathold (int interactive UNUSED, struct cmdarg **args) -{ - int button = 1; - - if (args[1]) - { - button = ARG(1,number); - if (button < 1 || button > 3) - return cmdret_new (RET_SUCCESS, "ratclick: invalid argument"); - } - -#ifdef HAVE_LIBXTST - if (!strcmp(ARG_STRING(0), "down")) - XTestFakeButtonEvent(dpy, button, True, CurrentTime); - else if(!strcmp(ARG_STRING(0),"up")) - XTestFakeButtonEvent(dpy, button, False, CurrentTime); - else - return cmdret_new (RET_FAILURE, "rathold: '%s' invalid argument", ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -#else - return cmdret_new (RET_FAILURE, "rathold: Please compile with the Xtst extension"); -#endif -} - -cmdret * -cmd_curframe (int interactive, struct cmdarg **args UNUSED) -{ - if (interactive) - { - show_frame_indicator(1); - return cmdret_new (RET_SUCCESS, NULL); - } - else - return cmdret_new(RET_SUCCESS, "%d", current_frame()->number); -} - -/* Thanks to Martin Samuelsson <cosis@lysator.liu.se> for the - original patch. */ -cmdret * -cmd_license (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_screen *s = current_screen(); - int x = 10; - int y = 10; - int i; - int max_width = 0; - char *license_text[] = { PACKAGE " " VERSION, "(built " __DATE__ " " __TIME__ ")", - "", - "Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts", - "", - "ratpoison 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, or (at your option) ", - "any later version.", - "", - "ratpoison 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.", - "", - "You should have received a copy of the GNU General Public License ", - "along with this software; see the file COPYING. If not, write to ", - "the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ", - "Boston, MA 02111-1307 USA", - "", - "Send bugreports, fixes, enhancements, t-shirts, money, beer & pizza ", - "to ratpoison-devel@nongnu.org or visit ", - "http://www.nongnu.org/ratpoison/", - "", - "[Press any key to end.] ", - NULL}; - - /* Switch to the default colormap. */ - if (current_window()) - XUninstallColormap (dpy, current_window()->colormap); - XInstallColormap (dpy, s->def_cmap); - - XMapRaised (dpy, s->help_window); - - /* Find the longest line. */ - for(i=0; license_text[i]; i++) - { - int tmp; - - tmp = rp_text_width (s, license_text[i], -1); - if (tmp > max_width) - max_width = tmp; - } - - /* Offset the text so its in the center. */ - x = s->left + (s->width - max_width) / 2; - y = s->top + (s->height - i * FONT_HEIGHT (s)) / 2; - if (x < 0) x = 0; - if (y < 0) y = 0; - - /* Print the text. */ - for(i=0; license_text[i]; i++) - { - rp_draw_string (s, s->help_window, STYLE_NORMAL, - x, y + FONT_ASCENT(s), - license_text[i], -1); - - y += FONT_HEIGHT (s); - } - - /* Wait for a key press. */ - read_any_key (); - XUnmapWindow (dpy, s->help_window); - - /* Possibly restore colormap. */ - if (current_window()) - { - XUninstallColormap (dpy, s->def_cmap); - XInstallColormap (dpy, current_window()->colormap); - } - - /* The help window overlaps the bar, so redraw it. */ - if (current_screen()->bar_is_raised) - redraw_last_message(); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_help (int interactive, struct cmdarg **args) -{ - rp_keymap *map; - - if (args[0]) - map = ARG(0,keymap); - else - map = find_keymap (ROOT_KEYMAP); - - if (interactive) - { - rp_screen *s = current_screen(); - int i, old_i; - int x = 10; - int y = 0; - int header_offset; - int width, max_width = 0; - /* 1 if we are drawing keys, 0 if we are drawing commands */ - int drawing_keys = 1; - char *keysym_name; - - /* Switch to the default colormap. */ - if (current_window()) - XUninstallColormap (dpy, current_window()->colormap); - XInstallColormap (dpy, s->def_cmap); - - XMapRaised (dpy, s->help_window); - - rp_draw_string (s, s->help_window, STYLE_NORMAL, - 10, y + FONT_ASCENT(s), - "ratpoison key bindings", -1); - - y += FONT_HEIGHT (s) * 2; - - /* Only print the "Command key" for the root keymap */ - if (map == find_keymap (ROOT_KEYMAP)) - { - rp_draw_string (s, s->help_window, STYLE_NORMAL, - 10, y + FONT_ASCENT(s), - "Command key: ", -1); - - keysym_name = keysym_to_string (prefix_key.sym, prefix_key.state); - rp_draw_string (s, s->help_window, STYLE_NORMAL, - 10 + rp_text_width (s, "Command key: ", -1), - y + FONT_ASCENT(s), - keysym_name, -1); - free (keysym_name); - - y += FONT_HEIGHT (s) * 2; - } - - header_offset = y; - - i = old_i = 0; - while (i < map->actions_last && old_i < map->actions_last) - { - if (drawing_keys) - { - keysym_name = - keysym_to_string (map->actions[i].key, map->actions[i].state); - - rp_draw_string (s, s->help_window, STYLE_NORMAL, - x, y + FONT_ASCENT(s), - keysym_name, -1); - - width = rp_text_width (s, keysym_name, -1); - if (width > max_width) - max_width = width; - - free (keysym_name); - } - else - { - rp_draw_string (s, s->help_window, STYLE_NORMAL, - x, y + FONT_ASCENT(s), - map->actions[i].data, -1); - - width = rp_text_width (s, map->actions[i].data, -1); - if (width > max_width) - max_width = width; - } - - y += FONT_HEIGHT (s); - /* Make sure the next line fits entirely within the window. */ - if (y + FONT_HEIGHT (s) >= (s->top + s->height)) - { - if (drawing_keys) - { - x += max_width + 10; - drawing_keys = 0; - i = old_i; - } - else - { - x += max_width + 20; - drawing_keys = 1; - i++; - old_i = i; - } - - max_width = 0; - y = header_offset; - } - else - { - i++; - if (i == map->actions_last && drawing_keys) - { - x += max_width + 10; - drawing_keys = 0; - y = header_offset; - i = old_i; - max_width = 0; - } - } - } - - read_any_key(); - XUnmapWindow (dpy, s->help_window); - - /* Possibly restore colormap. */ - if (current_window()) - { - XUninstallColormap (dpy, s->def_cmap); - XInstallColormap (dpy, current_window()->colormap); - } - - /* The help window overlaps the bar, so redraw it. */ - if (current_screen()->bar_is_raised) - redraw_last_message(); - - return cmdret_new (RET_SUCCESS, NULL); - } - else - { - struct sbuf *help_list; - char *keysym_name; - int i; - cmdret *ret; - - help_list = sbuf_new (0); - - for (i = 0; i < map->actions_last; i++) - { - keysym_name = keysym_to_string (map->actions[i].key, map->actions[i].state); - sbuf_concat (help_list, keysym_name); - free (keysym_name); - sbuf_concat (help_list, " "); - sbuf_concat (help_list, map->actions[i].data); - if (i < map->actions_last - 1) - sbuf_concat (help_list, "\n"); - } - - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (help_list)); - sbuf_free (help_list); - return ret; - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_rudeness (int interactive UNUSED, struct cmdarg **args) -{ - int num; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", - rp_honour_transient_raise - | (rp_honour_normal_raise << 1) - | (rp_honour_transient_map << 2) - | (rp_honour_normal_map << 3)); - - num = ARG(0,number); - if (num < 0 || num > 15) - return cmdret_new (RET_FAILURE, "rudeness: invalid level '%s'", ARG_STRING(0)); - - rp_honour_transient_raise = num & 1 ? 1 : 0; - rp_honour_normal_raise = num & 2 ? 1 : 0; - rp_honour_transient_map = num & 4 ? 1 : 0; - rp_honour_normal_map = num & 8 ? 1 : 0; - - return cmdret_new (RET_SUCCESS, NULL); -} - -char * -wingravity_to_string (int g) -{ - switch (g) - { - case NorthWestGravity: - return "nw"; - case WestGravity: - return "w"; - case SouthWestGravity: - return "sw"; - case NorthGravity: - return "n"; - case CenterGravity: - return "c"; - case SouthGravity: - return "s"; - case NorthEastGravity: - return "ne"; - case EastGravity: - return "e"; - case SouthEastGravity: - return "se"; - } - - PRINT_DEBUG (("Unknown gravity!\n")); - return "Unknown"; -} - -cmdret * -cmd_gravity (int interactive UNUSED, struct cmdarg **args) -{ - int gravity; - rp_window *win; - - win = current_window(); - if (!win) - return cmdret_new (RET_FAILURE, NULL); - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", wingravity_to_string (win->gravity)); - - if ((gravity = parse_wingravity (ARG_STRING(0))) < 0) - return cmdret_new (RET_FAILURE, "gravity: unknown gravity"); - else - { - win->gravity = gravity; - maximize (win); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_wingravity (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", wingravity_to_string (defaults.win_gravity)); - - defaults.win_gravity = ARG(0,gravity); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_transgravity (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", wingravity_to_string (defaults.trans_gravity)); - - defaults.trans_gravity = ARG(0,gravity); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_maxsizegravity (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", wingravity_to_string (defaults.maxsize_gravity)); - - defaults.maxsize_gravity = ARG(0,gravity); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_msgwait (int interactive UNUSED, struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.bar_timeout); - - if (ARG(0,number) < 0) - return cmdret_new (RET_FAILURE, "msgwait: invalid argument"); - else - defaults.bar_timeout = ARG(0,number); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_bargravity (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", wingravity_to_string (defaults.bar_location)); - - defaults.bar_location = ARG(0,gravity); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static void -update_gc (rp_screen *s) -{ - XGCValues gcv; - - gcv.foreground = s->fg_color; - gcv.background = s->bg_color; - gcv.function = GXcopy; - gcv.line_width = 1; - gcv.subwindow_mode = IncludeInferiors; - XFreeGC (dpy, s->normal_gc); - s->normal_gc = XCreateGC(dpy, s->root, - GCForeground | GCBackground - | GCFunction | GCLineWidth - | GCSubwindowMode, &gcv); - gcv.foreground = s->bg_color; - gcv.background = s->fg_color; - XFreeGC (dpy, s->inverse_gc); - s->inverse_gc = XCreateGC(dpy, s->root, - GCForeground | GCBackground - | GCFunction | GCLineWidth - | GCSubwindowMode, &gcv); -} - -#ifndef USE_XFT_FONT -static void -update_all_gcs (void) -{ - int i; - - for (i=0; i<num_screens; i++) - { - update_gc (&screens[i]); - } -} -#endif - -static cmdret * -set_historysize (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.history_size); - - defaults.history_size = ARG(0, number); - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_historycompaction (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.history_compaction); - - defaults.history_compaction = ARG(0, number); - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_historyexpansion (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.history_expansion); -#ifndef HAVE_HISTORY - if (ARG(0, number)) { - return cmdret_new (RET_FAILURE, "Not compiled with libhistory"); - } -#endif - defaults.history_expansion = ARG(0, number); - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_font (struct cmdarg **args) -{ -#ifdef USE_XFT_FONT - XftFont *font; - rp_screen *s = current_screen (); - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.font_string); - - font = XftFontOpenName (dpy, s->screen_num, ARG_STRING (0)); - - if (font == NULL) - return cmdret_new (RET_FAILURE, "deffont: unknown font"); - - XftFontClose (dpy, s->xft_font); - s->xft_font = font; -#else - XFontSet font; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.font_string); - - font = load_query_font_set (dpy, ARG_STRING(0)); - if (font == NULL) - return cmdret_new (RET_FAILURE, "deffont: unknown font"); - - /* Save the font as the default. */ - XFreeFontSet (dpy, defaults.font); - defaults.font = font; - set_extents_of_fontset(font); - update_all_gcs(); -#endif - - free (defaults.font_string); - defaults.font_string = xstrdup (ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_padding (struct cmdarg **args) -{ - rp_frame *frame; - int l, t, r, b; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d %d %d %d", - defaults.padding_left, - defaults.padding_top, - defaults.padding_right, - defaults.padding_bottom); - - l = ARG(0,number); - t = ARG(1,number); - r = ARG(2,number); - b = ARG(3,number); - - /* Resize the frames to make sure they are not too big and not too - small. */ - list_for_each_entry (frame,&(current_screen()->frames),node) - { - int bk_pos, bk_len; - - /* Resize horizontally. */ - bk_pos = frame->x; - bk_len = frame->width; - - if (frame->x == defaults.padding_left) - { - frame->x = l; - frame->width += bk_pos - l; - } - - if ((bk_pos + bk_len) == (current_screen()->left + current_screen()->width - defaults.padding_right)) - frame->width = current_screen()->left + current_screen()->width - r - frame->x; - - /* Resize vertically. */ - bk_pos = frame->y; - bk_len = frame->height; - - if (frame->y == defaults.padding_top) - { - frame->y = t; - frame->height += bk_pos - t; - } - - if ((bk_pos + bk_len) == (current_screen()->top + current_screen()->height - defaults.padding_bottom)) - frame->height = current_screen()->top + current_screen()->height - b - frame->y; - - maximize_all_windows_in_frame (frame); - } - - defaults.padding_left = l; - defaults.padding_right = r; - defaults.padding_top = t; - defaults.padding_bottom = b; - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_border (struct cmdarg **args) -{ - rp_window *win; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.window_border_width); - - if (ARG(0,number) < 0) - return cmdret_new (RET_FAILURE, "defborder: invalid argument"); - - defaults.window_border_width = ARG(0,number); - - /* Update all the visible windows. */ - list_for_each_entry (win,&rp_mapped_window,node) - { - if (win_get_frame (win)) - maximize (win); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_barborder (struct cmdarg **args) -{ - int i; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.bar_border_width); - - if (ARG(0,number) < 0) - return cmdret_new (RET_FAILURE, "defbarborder: invalid argument"); - - defaults.bar_border_width = ARG(0,number); - - /* Update the frame and bar windows. */ - for (i=0; i<num_screens; i++) - { - XSetWindowBorderWidth (dpy, screens[i].bar_window, defaults.bar_border_width); - XSetWindowBorderWidth (dpy, screens[i].frame_window, defaults.bar_border_width); - XSetWindowBorderWidth (dpy, screens[i].input_window, defaults.bar_border_width); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_barinpadding (struct cmdarg **args) -{ - int new_value; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.bar_in_padding); - - new_value = ARG(0,number); - if (new_value < 0) - return cmdret_new (RET_FAILURE, "defbarborder: invalid argument"); - - defaults.bar_in_padding = new_value; - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_inputwidth (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.input_window_size); - - if (ARG(0,number) < 0) - return cmdret_new (RET_FAILURE, "definputwidth: invalid argument"); - else - defaults.input_window_size = ARG(0,number); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_waitcursor (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.wait_for_key_cursor); - - defaults.wait_for_key_cursor = ARG(0,number); - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_infofmt (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.info_fmt); - - free (defaults.info_fmt); - defaults.info_fmt = xstrdup (ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_topkmap (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.top_kmap); - - if (!find_keymap (ARG_STRING(0))) - return cmdret_new(RET_FAILURE, "Unknown keymap %s", ARG_STRING(0)); - - ungrab_keys_all_wins(); - - free (defaults.top_kmap); - defaults.top_kmap = xstrdup (ARG_STRING(0)); - - grab_keys_all_wins(); - XSync(dpy, False); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_winfmt (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.window_fmt); - - free (defaults.window_fmt); - defaults.window_fmt = xstrdup (ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_winname (struct cmdarg **args) -{ - char *name; - - if (args[0] == NULL) - switch (defaults.win_name) - { - case WIN_NAME_TITLE: - return cmdret_new (RET_SUCCESS, "title"); - case WIN_NAME_RES_NAME: - return cmdret_new (RET_SUCCESS, "name"); - case WIN_NAME_RES_CLASS: - return cmdret_new (RET_SUCCESS, "class"); - default: - PRINT_DEBUG (("Unknown win_name\n")); - return cmdret_new (RET_FAILURE, "unknown"); - } - - name = ARG_STRING(0); - - /* FIXME: Using strncmp is sorta dirty since `title' and - `titlefoobar' would both match. But its quick and dirty. */ - if (!strncmp (name, "title", 5)) - defaults.win_name = WIN_NAME_TITLE; - else if (!strncmp (name, "name", 4)) - defaults.win_name = WIN_NAME_RES_NAME; - else if (!strncmp (name, "class", 5)) - defaults.win_name = WIN_NAME_RES_CLASS; - else - return cmdret_new (RET_FAILURE, "defwinname: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_framefmt (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.frame_fmt); - - free (defaults.frame_fmt); - defaults.frame_fmt = xstrdup (ARG_STRING(0)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_fgcolor (struct cmdarg **args) -{ - int i; - XColor color, junk; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.fgcolor_string); - - for (i=0; i<num_screens; i++) - { - if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, &junk)) - return cmdret_new (RET_FAILURE, "deffgcolor: unknown color"); - - screens[i].fg_color = color.pixel; - update_gc (&screens[i]); - XSetWindowBorder (dpy, screens[i].bar_window, color.pixel); - XSetWindowBorder (dpy, screens[i].input_window, color.pixel); - XSetWindowBorder (dpy, screens[i].frame_window, color.pixel); - XSetWindowBorder (dpy, screens[i].help_window, color.pixel); - -#ifdef USE_XFT_FONT - if (!XftColorAllocName (dpy, DefaultVisual (dpy, screens[i].screen_num), - DefaultColormap (dpy, screens[i].screen_num), - ARG_STRING(0), &screens[i].xft_fg_color)) - return cmdret_new (RET_FAILURE, "deffgcolor: unknown color"); -#endif - - free (defaults.fgcolor_string); - defaults.fgcolor_string = xstrdup (ARG_STRING(0)); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_bgcolor (struct cmdarg **args) -{ - int i; - XColor color, junk; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.bgcolor_string); - - for (i=0; i<num_screens; i++) - { - if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, &junk)) - return cmdret_new (RET_FAILURE, "defbgcolor: unknown color"); - - screens[i].bg_color = color.pixel; - update_gc (&screens[i]); - XSetWindowBackground (dpy, screens[i].bar_window, color.pixel); - XSetWindowBackground (dpy, screens[i].input_window, color.pixel); - XSetWindowBackground (dpy, screens[i].frame_window, color.pixel); - XSetWindowBackground (dpy, screens[i].help_window, color.pixel); - -#ifdef USE_XFT_FONT - if (!XftColorAllocName (dpy, DefaultVisual (dpy, screens[i].screen_num), - DefaultColormap (dpy, screens[i].screen_num), - ARG_STRING(0), &screens[i].xft_bg_color)) - return cmdret_new (RET_FAILURE, "deffgcolor: unknown color"); -#endif - - free (defaults.bgcolor_string); - defaults.bgcolor_string = xstrdup (ARG_STRING(0)); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_fwcolor (struct cmdarg **args) -{ - int i; - XColor color, junk; - rp_window *win = current_window(); - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.fwcolor_string); - - for (i=0; i<num_screens; i++) - { - if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, &junk)) - return cmdret_new (RET_FAILURE, "deffwcolor: unknown color"); - - screens[i].fw_color = color.pixel; - update_gc (&screens[i]); - - free (defaults.fwcolor_string); - defaults.fwcolor_string = xstrdup (ARG_STRING(0)); - } - - /* Update current window. */ - if (win != NULL) - XSetWindowBorder (dpy, win->w, win->scr->fw_color); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_bwcolor (struct cmdarg **args) -{ - int i; - XColor color, junk; - rp_window *win, *cur = current_window(); - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.bwcolor_string); - - for (i=0; i<num_screens; i++) - { - if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, &junk)) - return cmdret_new (RET_FAILURE, "defbwcolor: unknown color"); - - screens[i].bw_color = color.pixel; - update_gc (&screens[i]); - - free (defaults.bwcolor_string); - defaults.bwcolor_string = xstrdup (ARG_STRING(0)); - } - - /* Update all the visible windows. */ - list_for_each_entry (win,&rp_mapped_window,node) - { - if (win != cur) - XSetWindowBorder (dpy, win->w, win->scr->bw_color); - } - - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_setenv (int interactive UNUSED, struct cmdarg **args) -{ - - const char *var = ARG_STRING(0), *val = ARG_STRING(1); - int ret; - -#ifdef HAVE_SETENV - - PRINT_DEBUG(("setenv (\"%s\", \"%s\", 1)\n", var, val)); - ret = setenv (var, val, 1); - -#else /* not HAVE_SETENV */ - - struct sbuf *env; - - /* Setup the environment string. */ - env = sbuf_new (strlen (var) + 1 + strlen (val) + 1); - - sbuf_copy (env, var); - sbuf_concat (env, "="); - sbuf_concat (env, val); - - /* Stick it in the environment. We must *not* free it. */ - PRINT_DEBUG(("putenv(\"%s\")\n", sbuf_get(env))); - ret = putenv (sbuf_free_struct (env)); - -#endif /* not HAVE_SETENV */ - - if (ret == -1) - return cmdret_new (RET_FAILURE, "cmd_setenv failed: %s", strerror(errno)); - else - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_getenv (int interactive UNUSED, struct cmdarg **args) -{ - char *value; - - value = getenv (ARG_STRING(0)); - if (value) - return cmdret_new (RET_SUCCESS, "%s", value); - else - return cmdret_new (RET_FAILURE, NULL); -} - -/* Thanks to Gergely Nagy <algernon@debian.org> for the original - patch. */ -cmdret * -cmd_chdir (int interactive UNUSED, struct cmdarg **args) -{ - char *dir; - - if (args[0] == NULL) - { - dir = getenv ("HOME"); - if (dir == NULL || *dir == '\0') - { - return cmdret_new (RET_FAILURE, "chdir: HOME not set"); - } - } - else - dir = ARG_STRING(0); - - if (chdir (dir) == -1) - return cmdret_new (RET_FAILURE, "chdir: %s: %s", dir, strerror(errno)); - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Thanks to Gergely Nagy <algernon@debian.org> for the original - patch. */ -cmdret * -cmd_unsetenv (int interactive UNUSED, struct cmdarg **args) -{ - const char *var = ARG_STRING(0); - int ret; - - /* Use unsetenv() where possible since putenv("FOO") is not legit everywhere */ -#ifdef HAVE_UNSETENV - ret = unsetenv(var); -#else - /* MinGW doesn't have unsetenv() and uses putenv("FOO=") */ - struct sbuf *s = sbuf_new (strlen (var) + 1 + 1); - sbuf_copy (s, var); - sbuf_concat (s, "="); - /* let putenv() decide whether to call free() */ - ret = putenv (sbuf_free_struct (s)); -#endif - - if (ret == -1) - return cmdret_new (RET_FAILURE, "cmd_unsetenv failed: %s", strerror (errno)); - else - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Thanks to Gergely Nagy <algernon@debian.org> for the original - patch. */ -cmdret * -cmd_info (int interactive UNUSED, struct cmdarg **args) -{ - struct sbuf *buf; - if (current_window() != NULL) - { - rp_window *win = current_window(); - rp_window_elem *win_elem; - win_elem = group_find_window (&rp_current_group->mapped_windows, win); - if (!win_elem) - win_elem = group_find_window (&rp_current_group->unmapped_windows, win); - if (!win_elem) - { - rp_group *g = groups_find_group_by_window(win); - if (g != NULL) - win_elem = group_find_window (&g->mapped_windows, win); - if (!win_elem && g != NULL) - win_elem = group_find_window (&g->unmapped_windows, win); - } - if (win_elem) - { - char *s; - cmdret *ret; - - if (args[0] == NULL) - s = defaults.info_fmt; - else - s = ARG_STRING(0); - buf = sbuf_new (0); - format_string (s, win_elem, buf); - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (buf)); - sbuf_free (buf); - return ret; - } - } - - return cmdret_new (RET_SUCCESS, "No window."); -} - -/* Thanks to Gergely Nagy <algernon@debian.org> for the original - patch. */ -cmdret * -cmd_lastmsg (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - show_last_message(); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_focusup (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_up (current_frame()))) - set_active_frame (frame, 0); - else - show_frame_indicator(0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_focusdown (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_down (current_frame()))) - set_active_frame (frame, 0); - else - show_frame_indicator(0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_focusleft (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_left (current_frame()))) - set_active_frame (frame, 0); - else - show_frame_indicator(0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_focusright (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_right (current_frame()))) - set_active_frame (frame, 0); - else - show_frame_indicator(0); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_exchangeup (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_up (current_frame()))) - exchange_with_frame (current_frame(), frame); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_exchangedown (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_down (current_frame()))) - exchange_with_frame (current_frame(), frame); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_exchangeleft (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_left (current_frame()))) - exchange_with_frame (current_frame(), frame); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_exchangeright (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame; - - if ((frame = find_frame_right (current_frame()))) - exchange_with_frame (current_frame(), frame); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_swap (int interactive UNUSED, struct cmdarg **args) -{ - rp_screen *s; - rp_frame *dest_frame; - rp_frame *src_frame; - - dest_frame = ARG(0, frame); - src_frame = args[1] ? ARG (1, frame) : current_frame(); - - if (!rp_have_xinerama) - { - s = frames_screen(src_frame); - if (screen_find_frame_by_frame(s, dest_frame) == NULL) - return cmdret_new (RET_FAILURE, "swap: frames on different screens"); - } - - exchange_with_frame (src_frame, dest_frame); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_restart (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - hup_signalled = 1; - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_startup_message (int interactive, struct cmdarg **args) -{ - if (args[0] == NULL && !interactive) - return cmdret_new (RET_SUCCESS, "%s", defaults.startup_message ? "on":"off"); - - if (!strcasecmp (ARG_STRING(0), "on")) - defaults.startup_message = 1; - else if (!strcasecmp (ARG_STRING(0), "off")) - defaults.startup_message = 0; - else - return cmdret_new (RET_FAILURE, "startup_message: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_focuslast (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame *frame = find_last_frame(); - - if (frame) - set_active_frame (frame, 0); - else - return cmdret_new (RET_FAILURE, "focuslast: no other frame"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_link (int interactive, struct cmdarg **args) -{ - char *cmd = NULL; - rp_keymap *map; - - if (args[1]) - map = ARG(1,keymap); - else - map = find_keymap (ROOT_KEYMAP); - - cmd = resolve_command_from_keydesc (args[0]->string, 0, map); - if (cmd) - return command (interactive, cmd); - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Thanks to Doug Kearns <djkea2@mugc.its.monash.edu.au> for the - original patch. */ -static cmdret * -set_barpadding (struct cmdarg **args) -{ - int x, y; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d %d", defaults.bar_x_padding, defaults.bar_y_padding); - - x = ARG(0,number); - y = ARG(1,number); - - if (x >= 0 && y >= 0) - { - defaults.bar_x_padding = x; - defaults.bar_y_padding = y; - } - else - return cmdret_new (RET_FAILURE, "defbarpadding: invalid arguments"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_alias (int interactive UNUSED, struct cmdarg **args) -{ - /* Add or update the alias. */ - add_alias (ARG_STRING(0), ARG_STRING(1)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_unalias (int interactive UNUSED, struct cmdarg **args) -{ - int i; - - /* Are we updating an existing alias, or creating a new one? */ - i = find_alias_index (ARG_STRING(0)); - if (i >= 0) - { - char *tmp; - - alias_list_last--; - - /* Free the alias and put the last alias in the the space to - keep alias_list from becoming sparse. This code must jump - through some hoops to correctly handle the case when - alias_list_last == i. */ - tmp = alias_list[i].alias; - alias_list[i].alias = xstrdup (alias_list[alias_list_last].alias); - free (tmp); - free (alias_list[alias_list_last].alias); - - /* Do the same for the name element. */ - tmp = alias_list[i].name; - alias_list[i].name = xstrdup (alias_list[alias_list_last].name); - free (tmp); - free (alias_list[alias_list_last].name); - } - else - return cmdret_new (RET_SUCCESS, "unalias: alias not found"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_nextscreen (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - int new_screen; - - /* No need to go through the motions when we don't have to. */ - if (num_screens <= 1) - return cmdret_new (RET_FAILURE, "nextscreen: no other screen"); - - new_screen = rp_current_screen + 1; - if (new_screen >= num_screens) - new_screen = 0; - - set_active_frame (screen_get_frame (&screens[new_screen], screens[new_screen].current_frame), 1); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_prevscreen (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - int new_screen; - - /* No need to go through the motions when we don't have to. */ - if (num_screens <= 1) - return cmdret_new (RET_SUCCESS, "prevscreen: no other screen"); - - new_screen = rp_current_screen - 1; - if (new_screen < 0) - new_screen = num_screens - 1; - - set_active_frame (screen_get_frame (&screens[new_screen], screens[new_screen].current_frame), 1); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_sselect(int interactive UNUSED, struct cmdarg **args) -{ - int new_screen; - - new_screen = ARG(0,number); - if (new_screen < 0) - return cmdret_new (RET_FAILURE, "sselect: out of range"); - - if (new_screen < num_screens) - set_active_frame (screen_get_frame (&screens[new_screen], screens[new_screen].current_frame), 1); - else - return cmdret_new (RET_FAILURE, "sselect: out of range"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_warp (int interactive, struct cmdarg **args) -{ - if (args[0] == NULL && !interactive) - return cmdret_new (RET_SUCCESS, "%s", defaults.warp ? "on":"off"); - - if (!strcasecmp (ARG_STRING(0), "on")) - defaults.warp = 1; - else if (!strcasecmp (ARG_STRING(0), "off")) - defaults.warp = 0; - else - return cmdret_new (RET_FAILURE, "warp: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static void -sync_wins (rp_screen *s) -{ - rp_window *win, *wintmp; - XWindowAttributes attr; - unsigned int i, nwins; - Window dw1, dw2, *wins; - XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins); - - /* Remove any windows in our cached lists that aren't in the query - tree. These windows have been destroyed. */ - list_for_each_entry_safe (win, wintmp, &rp_mapped_window, node) - { - int found; - - found = 0; - for (i=0; i<nwins; i++) - { - if (win->w == wins[i]) - { - found = 1; - break; - } - } - if (!found) - { - ignore_badwindow++; - - /* If, somehow, the window is not withdrawn before it is destroyed, - perform the necessary steps to withdraw the window before it is - unmanaged. */ - if (win->state == IconicState) - { - PRINT_DEBUG (("Destroying Iconic Window (%s)\n", window_name (win))); - withdraw_window (win); - } - else if (win->state == NormalState) - { - rp_frame *frame; - - PRINT_DEBUG (("Destroying Normal Window (%s)\n", window_name (win))); - frame = find_windows_frame (win); - if (frame) - { - cleanup_frame (frame); - if (frame->number == win->scr->current_frame) - set_active_frame (frame, 0); - } - withdraw_window (win); - } - - /* Now that the window is guaranteed to be in the unmapped window - list, we can safely stop managing it. */ - unmanage (win); - ignore_badwindow--; - } - } - - for (i=0; i<nwins; i++) - { - XGetWindowAttributes(dpy, wins[i], &attr); - if (wins[i] == s->bar_window - || wins[i] == s->key_window - || wins[i] == s->input_window - || wins[i] == s->frame_window - || wins[i] == s->help_window - || attr.override_redirect == True) continue; - - /* Find the window in our mapped window list. */ - win = find_window_in_list (wins[i], &rp_mapped_window); - if (win) - { - rp_frame *frame; - /* If the window is viewable and it is in a frame, then - maximize it and go to the next window. */ - if (attr.map_state == IsViewable) - { - frame = find_windows_frame (win); - if (frame) - { - maximize (win); - } - else - { - hide_window (win); - } - } - else if (attr.map_state == IsUnmapped - && get_state (win) == IconicState) - { - frame = find_windows_frame (win); - if (frame) - { - unhide_window (win); - maximize (win); - } - } - else - { - PRINT_DEBUG (("I don't know what to do...\n")); - } - - /* We've handled the window. */ - continue; - } - - /* Try the unmapped window list. */ - win = find_window_in_list (wins[i], &rp_unmapped_window); - if (win) - { - /* If the window is viewable and it is in a frame, then - maximize it and go to the next window. */ - if (attr.map_state == IsViewable) - { - /* We need to map it since it's visible now. */ - map_window (win); - } - else if (attr.map_state == IsUnmapped - && get_state (win) == IconicState) - { - /* We need to map the window and then hide it. */ - map_window (win); - hide_window (win); - } - else - { - PRINT_DEBUG (("I think it's all sync'd up...\n")); - } - - /* We've handled the window. */ - continue; - } - - /* The window isn't in the mapped or unmapped window list so add - it. */ - win = add_to_window_list (s, wins[i]); - - /* If it's visible or iconized. "Map" it. */ - if (attr.map_state == IsViewable - || (attr.map_state == IsUnmapped - && get_state (win) == IconicState)) - map_window (win); - } - -} - -static int tmpwm_error_raised = 0; - -static int -tmpwm_error_handler (Display *d UNUSED, XErrorEvent *e) -{ - if (e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess) - { - PRINT_DEBUG (("failed to grab root properties\n")); - tmpwm_error_raised++; - } - return 0; -} - -/* Temporarily give control over to another window manager, reclaiming */ -/* control when that WM terminates. */ -cmdret * -cmd_tmpwm (int interactive UNUSED, struct cmdarg **args) -{ - struct list_head *tmp, *iter; - rp_window *win = NULL; - int child; - int status; - int pid; - int i; - int (*old_handler)(Display *, XErrorEvent *); - - push_frame_undo (current_screen()); /* fdump to stack */ - - /* Release event selection on the root windows, so the new WM can - have it. */ - for (i=0; i<num_screens; i++) - { - XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num), 0); - deactivate_screen(&screens[i]); - } - - /* Ungrab all our keys. */ - ungrab_keys_all_wins(); - - /* Don't listen for any events from any window. */ - list_for_each_safe_entry (win, iter, tmp, &rp_mapped_window, node) - { - unhide_window (win); - maximize (win); - XSelectInput (dpy, win->w, 0); - } - - list_for_each_safe_entry (win, iter, tmp, &rp_unmapped_window, node) - XSelectInput (dpy, win->w, 0); - - XSync (dpy, False); - - /* Disable our SIGCHLD handler */ - set_sig_handler (SIGCHLD, SIG_DFL); - /* Launch the new WM and wait for it to terminate. */ - pid = spawn (ARG_STRING(0), 0, NULL); - PRINT_DEBUG (("spawn pid: %d\n", pid)); - do - { - child = waitpid (pid, &status, 0); - } while (child != -1 && child != pid); - /* Enable our SIGCHLD handler */ - set_sig_handler (SIGCHLD, chld_handler); - /* Some processes may have quit while our sigchld handler was - disabled, so check for them. */ - check_child_procs(); - - /* Enable the event selection on the root window. We need to loop - until we don't get an X error. This is due to a race between the - X server cleaning up after the temporary wm and ratpoison - grabbing events. */ - old_handler = XSetErrorHandler (tmpwm_error_handler); - do { - tmpwm_error_raised = 0; - for (i=0; i<num_screens; i++) - { - XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num), - PropertyChangeMask | ColormapChangeMask - | SubstructureRedirectMask | SubstructureNotifyMask - | StructureNotifyMask); - XSync (dpy, False); - } - if (tmpwm_error_raised) - sleep(1); - } while (tmpwm_error_raised); - XSetErrorHandler (old_handler); - - for (i=0; i<num_screens; i++) - activate_screen (&screens[i]); - - /* Sort through all the windows in each group and pick out the ones - that are unmapped or destroyed. */ - for (i=0; i<num_screens; i++) - sync_wins (&screens[i]); - - /* At this point, new windows have the top level keys grabbed but - existing windows don't. So grab them on all windows just to be - sure. */ - grab_keys_all_wins(); - - /* If no window has focus, give the key_window focus. */ - if (current_window()) - set_active_window (current_window()); - else - set_window_focus (current_screen()->key_window); - - /* And we're back in ratpoison. */ - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Return a new string with the frame selector or it as a string if no - selector exists for the number. */ - -/* Select a frame by number. */ -cmdret * -cmd_fselect (int interactive, struct cmdarg **args) -{ - set_active_frame (ARG(0,frame), 1); - if (interactive) - return cmdret_new (RET_SUCCESS, NULL); - else - return cmdret_new (RET_SUCCESS, "%d", ARG(0,frame)->number); -} - -static char * -fdump (rp_screen *screen) -{ - struct sbuf *s; - char *tmp; - rp_frame *cur; - - s = sbuf_new (0); - - /* FIXME: Oooh, gross! there's a trailing comma, yuk! */ - list_for_each_entry (cur, &(screen->frames), node) - { - char *t; - - t = frame_dump (cur, screen); - sbuf_concat (s, t); - sbuf_concat (s, ","); - free (t); - } - - tmp = sbuf_free_struct (s); - return tmp; -} - -cmdret * -cmd_fdump (int interactively UNUSED, struct cmdarg **args) -{ - if (args[0] == NULL) - { - char *s = fdump (current_screen()); - cmdret *ret = cmdret_new (RET_SUCCESS, "%s", s); - free (s); - return ret; - } - else - { - int snum; - snum = ARG(0,number); - - if (snum < 0 || num_screens <= snum) - return cmdret_new (RET_FAILURE, "fdump: invalid argument"); - else - { - char *s = fdump (&screens[snum]); - cmdret *ret = cmdret_new (RET_SUCCESS, "%s", s); - free (s); - return ret; - } - } -} - -static cmdret * -frestore (char *data, rp_screen *s) -{ - char *token; - char *d; - rp_frame *new, *cur; - rp_window *win; - struct list_head fset; - int max = -1; - char *nexttok = NULL; - - INIT_LIST_HEAD (&fset); - - d = xstrdup (data); - token = strtok_r (d, ",", &nexttok); - if (token == NULL) - { - free (d); - return cmdret_new (RET_FAILURE, "frestore: invalid frame format"); - } - - /* Build the new frame set. */ - while (token != NULL) - { - new = frame_read (token, s); - if (new == NULL) - { - free (d); - return cmdret_new (RET_SUCCESS, "frestore: invalid frame format");; - } - list_add_tail (&new->node, &fset); - token = strtok_r (NULL, ",", &nexttok); - } - - free (d); - - /* Clear all the frames. */ - list_for_each_entry (cur, &s->frames, node) - { - PRINT_DEBUG (("blank %d\n", cur->number)); - blank_frame (cur); - } - - /* Get rid of the frames' numbers */ - screen_free_nums (s); - - /* Splice in our new frameset. */ - screen_restore_frameset (s, &fset); -/* numset_clear (s->frames_numset); */ - - /* Process the frames a bit to make sure everything lines up. */ - list_for_each_entry (cur, &s->frames, node) - { - PRINT_DEBUG (("restore %d %d\n", cur->number, cur->win_number)); - - /* Grab the frame's number, but if it already exists request a - new one. */ - if (!numset_add_num (s->frames_numset, cur->number)) { - cur->number = numset_request (s->frames_numset); - } - - /* Find the current frame based on last_access. */ - if (cur->last_access > max) - { - s->current_frame = cur->number; - max = cur->last_access; - } - - /* Update the window the frame points to. */ - if (cur->win_number != EMPTY) - { - set_frames_window (cur, find_window_number (cur->win_number)); - } - } - - /* Show the windows in the frames. */ - list_for_each_entry (win, &rp_mapped_window, node) - { - if (win->frame_number != EMPTY) - { - maximize (win); - unhide_window (win); - } - } - - set_active_frame (current_frame(), 0); - update_bar (s); - show_frame_indicator(0); - - PRINT_DEBUG (("Done.\n")); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_frestore (int interactively UNUSED, struct cmdarg **args) -{ - push_frame_undo (current_screen()); /* fdump to stack */ - return frestore (ARG_STRING(0), current_screen()); -} - -cmdret * -cmd_verbexec (int interactive UNUSED, struct cmdarg **args) -{ - marked_message_printf(0, 0, "Running %s", ARG_STRING(0)); - spawn (ARG_STRING(0), 0, current_frame()); - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_winliststyle (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.window_list_style ? "column":"row"); - - if (!strcmp ("column", ARG_STRING(0))) - defaults.window_list_style = STYLE_COLUMN; - else if (!strcmp ("row", ARG_STRING(0))) - defaults.window_list_style = STYLE_ROW; - else - return cmdret_new (RET_FAILURE, "defwinliststyle: invalid argument"); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gnext (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - set_current_group (group_next_group ()); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gprev (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - set_current_group (group_prev_group ()); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gother (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - set_current_group (group_last_group ()); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gnew (int interactive UNUSED, struct cmdarg **args) -{ - if (groups_find_group_by_name (ARG_STRING (0), 1)) - return cmdret_new (RET_FAILURE, "gnew: group already exists"); - set_current_group (group_add_new_group (ARG_STRING(0))); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gnewbg (int interactive UNUSED, struct cmdarg **args) -{ - if (groups_find_group_by_name (ARG_STRING (0), 1)) - return cmdret_new (RET_FAILURE, "gnewbg: group already exists"); - group_add_new_group (ARG_STRING(0)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gnumber (int interactive UNUSED, struct cmdarg **args) -{ - int old_number, new_number; - rp_group *other_g, *g; - -/* FIXME Implement this. */ -// if (args[0] == NULL) -// { -// /* XXX: Fix this. */ -// print_window_information (rp_current_group, current_window()); -// return cmdret_new (RET_SUCCESS, NULL); -// } - - /* Gather the args. */ - new_number = ARG(0,number); - if (args[1]) - g = groups_find_group_by_number (ARG(1,number)); - else - g = rp_current_group; - - /* Make the switch. */ - if ( new_number >= 0 && g) - { - /* Find other window with same number and give it old number. */ - other_g = groups_find_group_by_number (new_number); - if (other_g != NULL) - { - old_number = g->number; - other_g->number = old_number; - - /* Resort the window in the list */ - group_resort_group (other_g); - } - else - { - numset_release (group_numset, g->number); - } - - g->number = new_number; - numset_add_num (group_numset, new_number); - - /* resort the the window in the list */ - group_resort_group (g); - -/* FIXME Implement updating of groups bar. */ -// /* Update the window list. */ -// update_window_names (win->win->scr, defaults.window_fmt); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_grename (int interactive UNUSED, struct cmdarg **args) -{ - if (groups_find_group_by_name (ARG_STRING (0), 1)) - return cmdret_new (RET_FAILURE, "grename: duplicate group name"); - group_rename (rp_current_group, ARG_STRING(0)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gselect (int interactive, struct cmdarg **args) -{ - rp_group *g; - - g = find_group (ARG_STRING(0)); - - if (g) - set_current_group (g); - else - return cmd_groups (interactive, NULL); - - return cmdret_new (RET_SUCCESS, NULL); -} - -/* Show all the groups, with the current one highlighted. */ -cmdret * -cmd_groups (int interactive, struct cmdarg **args UNUSED) -{ - rp_group *cur; - int mark_start = 0, mark_end = 0; - struct sbuf *buffer; - rp_group *last; - - last = group_last_group (); - buffer = sbuf_new (0); - - /* Generate the string. */ - list_for_each_entry (cur, &rp_groups, node) - { - char *fmt; - char separator; - - if (cur == rp_current_group) - mark_start = strlen (sbuf_get (buffer)); - - /* Pad start of group name with a space for row - style. non-Interactive always gets a column.*/ - if (defaults.window_list_style == STYLE_ROW && interactive) - sbuf_concat (buffer, " "); - - if(cur == rp_current_group) - separator = '*'; - else if(cur == last) - separator = '+'; - else - separator = '-'; - - fmt = xsprintf ("%d%c%s", cur->number, separator, cur->name); - sbuf_concat (buffer, fmt); - free (fmt); - - /* Pad end of group name with a space for row style. */ - if (defaults.window_list_style == STYLE_ROW && interactive) - { - sbuf_concat (buffer, " "); - } - else - { - if (cur->node.next != &rp_groups) - sbuf_concat (buffer, "\n"); - } - - if (cur == rp_current_group) - mark_end = strlen (sbuf_get (buffer)); - } - - /* Display it or return it. */ - if (interactive) - { - marked_message (sbuf_get (buffer), mark_start, mark_end); - sbuf_free (buffer); - return cmdret_new (RET_SUCCESS, NULL); - } - else - { - cmdret *ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get(buffer)); - sbuf_free(buffer); - return ret; - } -} - -/* Move a window to a different group. */ -cmdret * -cmd_gmove (int interactive UNUSED, struct cmdarg **args) -{ - if (current_window() == NULL) - return cmdret_new (RET_FAILURE, "gmove: no focused window"); - - group_move_window (ARG(0,group), current_window()); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_gmerge (int interactive UNUSED, struct cmdarg **args) -{ - groups_merge (ARG(0,group), rp_current_group); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_addhook (int interactive UNUSED, struct cmdarg **args) -{ - struct list_head *hook; - struct sbuf *cmd; - - hook = hook_lookup (ARG_STRING(0)); - if (hook == NULL) - return cmdret_new (RET_FAILURE, "addhook: unknown hook '%s'", ARG_STRING(0)); - - /* Add the command to the hook */ - cmd = sbuf_new (0); - sbuf_copy (cmd, ARG_STRING(1)); - hook_add (hook, cmd); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_remhook (int interactive UNUSED, struct cmdarg **args) -{ - struct sbuf *cmd; - - /* Remove the command from the hook */ - cmd = sbuf_new (0); - sbuf_copy (cmd, ARG_STRING(1)); - hook_remove (ARG(0,hook), cmd); - sbuf_free (cmd); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_listhook (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret; - struct sbuf *buffer; - struct list_head *hook; - struct sbuf *cur; - - hook = hook_lookup (ARG_STRING(0)); - if (hook == NULL) - return cmdret_new (RET_FAILURE, "listhook: unknown hook '%s'", ARG_STRING(0)); - - if (list_empty(hook)) - return cmdret_new (RET_FAILURE, " Nothing defined for %s ", ARG_STRING(0)); - - buffer = sbuf_new(0); - - list_for_each_entry (cur, hook, node) - { - sbuf_printf_concat(buffer, "%s", sbuf_get (cur)); - if (cur->node.next != hook) - sbuf_printf_concat(buffer, "\n"); - } - - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (buffer)); - sbuf_free (buffer); - return ret; -} - -cmdret * -cmd_gdelete (int interactive UNUSED, struct cmdarg **args) -{ - rp_group *g; - - if (args[0] == NULL) - g = rp_current_group; - else - g = ARG(0,group); - - switch (group_delete_group (g)) - { - case GROUP_DELETE_GROUP_OK: - break; - case GROUP_DELETE_GROUP_NONEMPTY: - return cmdret_new (RET_FAILURE, "gdelete: non-empty group"); - break; - case GROUP_DELETE_LAST_GROUP: - return cmdret_new (RET_FAILURE, "gdelete: cannot delete the sole group"); - break; - default: - return cmdret_new (RET_FAILURE, "gdelete: unknown return code (this shouldn't happen)"); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_readkey (int interactive UNUSED, struct cmdarg **args) -{ - char *keysym_name; - rp_action *key_action; - KeySym keysym; /* Key pressed */ - unsigned int mod; /* Modifiers */ - int rat_grabbed = 0; - rp_keymap *map; - - map = ARG(0,keymap); - - /* Change the mouse icon to indicate to the user we are waiting for - more keystrokes */ - if (defaults.wait_for_key_cursor) - { - grab_rat(); - rat_grabbed = 1; - } - - read_single_key (&keysym, &mod, NULL, 0); - - if (rat_grabbed) - ungrab_rat(); - - if ((key_action = find_keybinding (keysym, x11_mask_to_rp_mask (mod), map))) - { - return command (1, key_action->data); - } - else - { - cmdret *ret; - /* No key match, notify user. */ - keysym_name = keysym_to_string (keysym, x11_mask_to_rp_mask (mod)); - ret = cmdret_new (RET_FAILURE, "readkey: unbound key '%s'", keysym_name); - free (keysym_name); - return ret; - } -} - -cmdret * -cmd_newkmap (int interactive UNUSED, struct cmdarg **args) -{ - rp_keymap *map; - - map = find_keymap (ARG_STRING(0)); - if (map) - return cmdret_new (RET_FAILURE, "newkmap: keymap '%s' already exists", ARG_STRING(0)); - - map = keymap_new (ARG_STRING(0)); - list_add_tail (&map->node, &rp_keymaps); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_delkmap (int interactive UNUSED, struct cmdarg **args) -{ - rp_keymap *map, *top, *root; - - top = find_keymap (defaults.top_kmap); - root = find_keymap (ROOT_KEYMAP); - - map = ARG(0,keymap); - if (map == root || map == top) - return cmdret_new (RET_FAILURE, "delkmap: cannot delete keymap '%s'", ARG_STRING(0)); - - list_del (&map->node); - - return cmdret_new (RET_SUCCESS, NULL); -} - -static cmdret * -set_framesels (struct cmdarg **args) -{ - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%s", defaults.frame_selectors); - - free (defaults.frame_selectors); - defaults.frame_selectors = xstrdup (ARG_STRING(0)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_set (int interactive UNUSED, struct cmdarg **args) -{ - if (args[0] == NULL) - { - /* List all the settings. */ - cmdret *ret; - struct sbuf *s = sbuf_new(0); - struct set_var *cur, *last; - - list_last (last, &set_vars, node); - list_for_each_entry (cur, &set_vars, node) - { - cmdret *r; - r = cur->set_fn (args); - sbuf_printf_concat (s, "%s: %s", cur->var, r->output); - /* Skip a newline on the last line. */ - if (cur != last) - sbuf_concat (s, "\n"); - cmdret_free (r); - } - - /* Return the accumulated string. */ - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (s)); - sbuf_free (s); - return ret; - } - else - { - struct sbuf *scur; - struct cmdarg *acur; - struct list_head *iter, *tmp; - struct list_head head, arglist; - int i, nargs = 0, raw = 0; - int parsed_args; - cmdret *result = NULL; - struct cmdarg **cmdargs; - char *input; - - INIT_LIST_HEAD (&arglist); - INIT_LIST_HEAD (&head); - - /* We need to tell parse_args about arg_REST and arg_SHELLCMD. */ - for (i=0; i<ARG(0,variable)->nargs; i++) - if (ARG(0,variable)->args[i].type == arg_REST - || ARG(0,variable)->args[i].type == arg_COMMAND - || ARG(0,variable)->args[i].type == arg_SHELLCMD - || ARG(0,variable)->args[i].type == arg_RAW) - { - raw = 1; - nargs = i; - break; - } - - /* Parse the arguments and call the function. */ - if (args[1]) - input = xstrdup (args[1]->string); - else - input = xstrdup (""); - result = parse_args (input, &head, nargs, raw); - free (input); - - if (result) - goto failed; - result = parsed_input_to_args (ARG(0,variable)->nargs, ARG(0,variable)->args, - &head, &arglist, &parsed_args, NULL); - if (result) - goto failed; - /* 0 or nargs is acceptable */ - if (list_size (&arglist) > 0 && list_size (&arglist) < ARG(0,variable)->nargs) - { - result = cmdret_new (RET_FAILURE, "not enough arguments."); - goto failed; - } - else if (list_size (&head) > ARG(0,variable)->nargs) - { - result = cmdret_new (RET_FAILURE, "too many arguments."); - goto failed; - } - - cmdargs = arg_array (&arglist); - result = ARG(0,variable)->set_fn (cmdargs); - free (cmdargs); - - /* Free the lists. */ - failed: - /* Free the parsed strings */ - list_for_each_safe_entry (scur, iter, tmp, &head, node) - sbuf_free(scur); - /* Free the args */ - list_for_each_safe_entry (acur, iter, tmp, &arglist, node) - arg_free (acur); - - return result; - } -} - -cmdret * -cmd_sfdump (int interactively UNUSED, struct cmdarg **args UNUSED) -{ - cmdret *ret; - struct sbuf *s; - char *tmp2; - rp_frame *cur; - int i; - - s = sbuf_new (0); - - for (i=0; i<num_screens; i++) - { - tmp2 = xsprintf (" %d,", (rp_have_xinerama)?(screens[i].xine_screen_num):(screens[i].screen_num)); - - /* FIXME: Oooh, gross! there's a trailing comma, yuk! */ - list_for_each_entry (cur, &(screens[i].frames), node) - { - char *tmp; - - tmp = frame_dump (cur, &screens[i]); - sbuf_concat (s, tmp); - sbuf_concat (s, tmp2); - free (tmp); - } - - free (tmp2); - } - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (s)); - sbuf_free (s); - return ret; -} - -cmdret * -cmd_sfrestore (int interactively UNUSED, struct cmdarg **args) -{ - int out_of_screen = 0; - int number_of_frames = 0; - int j; - long x; - char *d; - char *token; - char *ptr; - struct sbuf *buffer[num_screens]; - - /* initialize frameset-buffer for each screen */ - for (j=0; j<num_screens; j++) { - buffer[j] = sbuf_new(0); - } - - /* now split the whole input to the corresponding screens */ - d = xstrdup (ARG_STRING(0)); - - token = strtok (d, ","); - if (token == NULL) { - free (d); - return cmdret_new (RET_FAILURE, "sfrestore: invalid frame format"); - } - - while (token != NULL) { - /* search for end of frameset */ - ptr = token; - while (*ptr != ')') { - ptr++; - } - /* skip space */ - ptr++; - - /* convert to integer */ - x = strtol (ptr, NULL, 10); - - /* check that specified screen number is not bigger than current number of connected screens */ - if (x < num_screens) { - /* append frameset to buffer[x] */ - sbuf_concat(buffer[x], token); - sbuf_concat(buffer[x], ","); - number_of_frames++; - } - else { - out_of_screen++; - } - - /* continue with next frameset */ - token = strtok (NULL, ","); - } - - free (d); - - /* now restore the frames for each screen */ - for (j=0; j<num_screens; j++) { - push_frame_undo (&screens[j]); /* fdump to stack */ - /* FIXME: store RET_SUCCESS || RET_FAILURE for each screen and output it later */ - frestore (sbuf_get(buffer[j]), &screens[j]); - /* clear buffer */ - sbuf_free(buffer[j]); - } - - if (!out_of_screen) { - return cmdret_new (RET_SUCCESS, "Restored %i Frame(s)", number_of_frames); - } - else { - return cmdret_new (RET_SUCCESS, "Restored %i Frame(s), %i Frame(s) out of Screen(s)", number_of_frames, out_of_screen); - } -} - -cmdret * -cmd_sdump (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - cmdret *ret; - struct sbuf *s; - char *tmp; - int i; - - s = sbuf_new (0); - for (i=0; i<num_screens; ++i) - { - tmp = screen_dump (&screens[i]); - sbuf_concat (s, tmp); - if (i + 1 != num_screens) /* No trailing comma. */ - sbuf_concat (s, ","); - free (tmp); - } - - ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (s)); - sbuf_free (s); - return ret; -} - -static cmdret * -set_maxundos (struct cmdarg **args) -{ - rp_frame_undo *cur; - - if (args[0] == NULL) - return cmdret_new (RET_SUCCESS, "%d", defaults.maxundos); - - if (ARG(0,number) < 0) - return cmdret_new (RET_FAILURE, "defmaxundos: invalid argument"); - - defaults.maxundos = ARG(0,number); - - /* Delete any superfluous undos */ - while (list_size (&rp_frame_undos) > defaults.maxundos) - { - /* Delete the oldest node */ - list_last (cur, &rp_frame_undos, node); - del_frame_undo (cur); - } - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_cnext (int interactive, struct cmdarg **args) -{ - rp_window *cur, *last, *win; - - cur = current_window(); - if (!cur || !cur->res_class) /* Can't be done. */ - return cmd_next (interactive, args); - - /* CUR !in cycle list, so LAST marks last node. */ - last = group_prev_window (rp_current_group, cur); - - if (last) - for (win = group_next_window (rp_current_group, cur); - win; - win = group_next_window (rp_current_group, win)) - { - if (win->res_class - && strcmp (cur->res_class, win->res_class)) - { - set_active_window_force (win); - return cmdret_new (RET_SUCCESS, NULL); - } - - if (win == last) break; - } - - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); -} - -cmdret * -cmd_cprev (int interactive, struct cmdarg **args) -{ - rp_window *cur, *last, *win; - - cur = current_window(); - if (!cur || !cur->res_class) /* Can't be done. */ - return cmd_next (interactive, args); - - /* CUR !in cycle list, so LAST marks last node. */ - last = group_next_window (rp_current_group, cur); - - if (last) - for (win = group_prev_window (rp_current_group, cur); - win; - win = group_prev_window (rp_current_group, win)) - { - if (win->res_class - && strcmp (cur->res_class, win->res_class)) - { - set_active_window_force (win); - return cmdret_new (RET_SUCCESS, NULL); - } - - if (win == last) break; - } - - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); -} - -cmdret * -cmd_inext (int interactive, struct cmdarg **args) -{ - rp_window *cur, *last, *win; - - cur = current_window(); - if (!cur || !cur->res_class) /* Can't be done. */ - return cmd_next (interactive, args); - - /* CUR !in cycle list, so LAST marks last node. */ - last = group_prev_window (rp_current_group, cur); - - if (last) - for (win = group_next_window (rp_current_group, cur); - win; - win = group_next_window (rp_current_group, win)) - { - if (win->res_class - && !strcmp (cur->res_class, win->res_class)) - { - set_active_window_force (win); - return cmdret_new (RET_SUCCESS, NULL); - } - - if (win == last) break; - } - - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); -} - -cmdret * -cmd_iprev (int interactive, struct cmdarg **args) -{ - rp_window *cur, *last, *win; - - cur = current_window(); - if (!cur || !cur->res_class) /* Can't be done. */ - return cmd_next (interactive, args); - - /* CUR !in cycle list, so LAST marks last node. */ - last = group_next_window (rp_current_group, cur); - - if (last) - for (win = group_prev_window (rp_current_group, cur); - win; - win = group_prev_window (rp_current_group, win)) - { - if (win->res_class - && !strcmp (cur->res_class, win->res_class)) - { - set_active_window_force (win); - return cmdret_new (RET_SUCCESS, NULL); - } - - if (win == last) break; - } - - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); -} - -cmdret * -cmd_cother (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_window *cur, *w = NULL; - - cur = current_window(); - if (cur) - w = group_last_window_by_class (rp_current_group, cur->res_class); - - if (!w) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); - else - set_active_window_force (w); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_iother (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_window *cur, *w = NULL; - - cur = current_window(); - if (cur) - w = group_last_window_by_class_complement (rp_current_group, cur->res_class); - - if (!w) - return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); - else - set_active_window_force (w); - - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_undo (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame_undo *cur; - - cur = pop_frame_undo (); - if (!cur) - return cmdret_new (RET_FAILURE, "No more undo information available"); - else - { - cmdret *ret; - - ret = frestore (cur->frames, cur->screen); - return ret; - } -} - -cmdret * -cmd_redo (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - rp_frame_undo *cur; - - /* The current layout goes on the undo. */ - - cur = pop_frame_redo (); - if (!cur) - return cmdret_new (RET_FAILURE, "No more redo information available"); - else - { - cmdret *ret; - - ret = frestore (cur->frames, cur->screen); - return ret; - } -} - -cmdret * -cmd_prompt (int interactive UNUSED, struct cmdarg **args) -{ - cmdret *ret; - char *output; - - if (args[0] == NULL) - output = get_input (MESSAGE_PROMPT_COMMAND, hist_PROMPT, - trivial_completions); - else - { - char *arg_str, *prefix; - - arg_str = ARG_STRING(0); - prefix = strchr (arg_str, ':'); - - if (prefix) - { - struct sbuf *query; - - prefix++; /* Don't return the colon. */ - query = sbuf_new (prefix - arg_str); - sbuf_nconcat (query, arg_str, prefix - arg_str); - output = get_more_input (sbuf_get (query), prefix, hist_PROMPT, - trivial_completions); - sbuf_free (query); - } - else - { - output = get_input (arg_str, hist_PROMPT, trivial_completions); - } - } - - if (output == NULL) - return cmdret_new (RET_FAILURE, NULL); /* User aborted */ - - ret = cmdret_new (RET_SUCCESS, "%s", output); - free (output); - - return ret; -} - -cmdret * -cmd_describekey (int interactive UNUSED, struct cmdarg **args) -{ - char *keysym_name; - rp_action *key_action; - KeySym keysym; /* Key pressed */ - unsigned int mod; /* Modifiers */ - int rat_grabbed = 0; - rp_keymap *map; - - map = ARG(0,keymap); - - /* Change the mouse icon to indicate to the user we are waiting for - more keystrokes */ - if (defaults.wait_for_key_cursor) - { - grab_rat(); - rat_grabbed = 1; - } - - read_single_key (&keysym, &mod, NULL, 0); - - if (rat_grabbed) - ungrab_rat(); - - if ((key_action = find_keybinding (keysym, x11_mask_to_rp_mask (mod), map))) - { - cmdret *ret; - keysym_name = keysym_to_string (keysym, x11_mask_to_rp_mask (mod)); - ret = cmdret_new (RET_SUCCESS, "%s bound to '%s'", keysym_name, key_action->data); - free (keysym_name); - return ret; - } - else - { - cmdret *ret; - /* No key match, notify user. */ - keysym_name = keysym_to_string (keysym, x11_mask_to_rp_mask (mod)); - ret = cmdret_new (RET_SUCCESS, "describekey: unbound key '%s'", keysym_name); - free (keysym_name); - return ret; - } -} - -cmdret * -cmd_dedicate (int interactive UNUSED, struct cmdarg **args) -{ - rp_frame *f; - - f = current_frame(); - if (!f) return cmdret_new (RET_SUCCESS, NULL); - - if (args[0]) - /* Whatever you set it to. */ - f->dedicated = ARG(0,number); - else - /* Just toggle it, rather than on or off. */ - f->dedicated = !(f->dedicated); - - return cmdret_new (RET_SUCCESS, "Consider this frame %s.", - f->dedicated ? "chaste":"promiscuous"); -} - -cmdret * -cmd_putsel (int interactive UNUSED, struct cmdarg **args) -{ - set_selection(ARG_STRING(0)); - return cmdret_new (RET_SUCCESS, NULL); -} - -cmdret * -cmd_getsel (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - char *sel = get_selection(); - cmdret *ret; - ret = cmdret_new (RET_SUCCESS, "%s", sel); - free (sel); - return ret; -} - -/* This is a command that restores old commands that have been - recently depricated. */ -cmdret * -cmd_compat (int interactive UNUSED, struct cmdarg **args UNUSED) -{ - add_alias ("defresizeunit", "set resizeunit"); - add_alias ("defwingravity", "set wingravity"); - add_alias ("deftransgravity", "set transgravity"); - add_alias ("defmaxsizegravity", "set maxsizegravity"); - add_alias ("defbargravity", "set bargravity"); - add_alias ("deffont", "set font"); - add_alias ("defpadding", "set padding"); - add_alias ("defborder", "set border"); - add_alias ("defbarborder", "set barborder"); - add_alias ("definputwidth", "set inputwidth"); - add_alias ("defwaitcursor", "set waitcursor"); - add_alias ("defwinfmt", "set winfmt"); - add_alias ("defwinname", "set winname"); - add_alias ("deffgcolor", "set fgcolor"); - add_alias ("defbgcolor", "set bgcolor"); - add_alias ("defbarpadding", "set barpadding"); - add_alias ("defwinliststyle", "set winliststyle"); - add_alias ("defframesels", "set framesels"); - add_alias ("defmaxundos", "set maxundos"); - - return cmdret_new (RET_SUCCESS, NULL); -} |