A tiling window manager
at master 5896 lines 145 kB view raw
1/* 2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the Free 6 * Software Foundation; either version 2 of the License, or (at your option) 7 * any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 * Place, Suite 330, Boston, MA 02111-1307 USA. 17 */ 18 19#include <unistd.h> 20#include <ctype.h> 21#include <sys/wait.h> 22#include <X11/keysym.h> 23#include <string.h> 24#include <strings.h> 25#include <err.h> 26#include <errno.h> 27#include <signal.h> 28#include <limits.h> 29#include <X11/Xproto.h> 30#include <X11/extensions/XTest.h> 31#include <sys/ioctl.h> 32 33#include "sdorfehs.h" 34 35/* arg_REST and arg_SHELLCMD eat the rest of the input. */ 36enum argtype { 37 arg_REST, 38 arg_NUMBER, 39 arg_STRING, 40 arg_FRAME, 41 arg_WINDOW, 42 arg_COMMAND, 43 arg_SHELLCMD, 44 arg_KEYMAP, 45 arg_KEY, 46 arg_GRAVITY, 47 arg_VSCREEN, 48 arg_HOOK, 49 arg_VARIABLE, 50 arg_RAW, 51}; 52 53union arg_union { 54 rp_frame *frame; 55 int number; 56 float fnumber; 57 rp_window *win; 58 rp_keymap *keymap; 59 rp_vscreen *vscreen; 60 struct list_head *hook; 61 struct set_var *variable; 62 struct rp_key *key; 63 int gravity; 64}; 65 66struct cmdarg { 67 int type; 68 char *string; 69 union arg_union arg; 70 struct list_head node; 71}; 72#define ARG_STRING(elt) args[elt]->string 73#define ARG(elt, type) args[elt]->arg.type 74 75struct argspec { 76 int type; 77 char *prompt; 78}; 79 80struct set_var { 81 char *var; 82 cmdret *(*set_fn)(struct cmdarg **); 83 int nargs; 84 struct argspec *args; 85 struct list_head node; 86}; 87 88struct user_command { 89 char *name; 90 cmdret *(*func)(int, struct cmdarg **); 91 struct argspec *args; 92 int num_args; 93 /* 94 * The number of required arguments. Any arguments after that are 95 * optional and won't be filled in when called interactively. 96 * ni_required_args is used when called non-interactively, 97 * i_required_args when called interactively. 98 */ 99 int ni_required_args, i_required_args; 100 101 struct list_head node; 102}; 103 104typedef struct { 105 char *name; 106 char *alias; 107} alias_t; 108 109typedef struct rp_frame_undo { 110 char *frames; 111 rp_vscreen *vscreen; 112 struct list_head node; 113} rp_frame_undo; 114 115static LIST_HEAD(user_commands); 116static LIST_HEAD(rp_keymaps); 117static LIST_HEAD(set_vars); 118static LIST_HEAD(rp_frame_undos); 119static LIST_HEAD(rp_frame_redos); 120 121static alias_t *alias_list; 122static int alias_list_size; 123static int alias_list_last; 124 125static const char invalid_negative_arg[] = "invalid negative argument"; 126 127/* setter function prototypes */ 128static cmdret *set_barborder(struct cmdarg **args); 129static cmdret *set_barbordercolor(struct cmdarg **args); 130static cmdret *set_bargravity(struct cmdarg **args); 131static cmdret *set_barinpadding(struct cmdarg **args); 132static cmdret *set_barpadding(struct cmdarg **args); 133static cmdret *set_barsticky(struct cmdarg **args); 134static cmdret *set_bgcolor(struct cmdarg **args); 135static cmdret *set_border(struct cmdarg **args); 136static cmdret *set_bwcolor(struct cmdarg **args); 137static cmdret *set_fgcolor(struct cmdarg **args); 138static cmdret *set_font(struct cmdarg **args); 139static cmdret *set_framefmt(struct cmdarg **args); 140static cmdret *set_framemsgwait(struct cmdarg **args); 141static cmdret *set_framesels(struct cmdarg **args); 142static cmdret *set_fwcolor(struct cmdarg **args); 143static cmdret *set_gap(struct cmdarg **args); 144static cmdret *set_historysize(struct cmdarg **args); 145static cmdret *set_ignoreresizehints(struct cmdarg **args); 146static cmdret *set_infofmt(struct cmdarg **args); 147static cmdret *set_inputwidth(struct cmdarg **args); 148static cmdret *set_maxsizegravity(struct cmdarg **args); 149static cmdret *set_maxundos(struct cmdarg **args); 150static cmdret *set_msgwait(struct cmdarg **args); 151static cmdret *set_onlyborder(struct cmdarg **args); 152static cmdret *set_padding(struct cmdarg **args); 153static cmdret *set_resizefmt(struct cmdarg **args); 154static cmdret *set_resizeunit(struct cmdarg **args); 155static cmdret *set_rudeness(struct cmdarg **args); 156static cmdret *set_startupmessage(struct cmdarg **args); 157static cmdret *set_stickyfmt(struct cmdarg **args); 158static cmdret *set_topkmap(struct cmdarg **args); 159static cmdret *set_transgravity(struct cmdarg **args); 160static cmdret *set_vscreens(struct cmdarg **args); 161static cmdret *set_waitcursor(struct cmdarg **args); 162static cmdret *set_warp(struct cmdarg **args); 163static cmdret *set_winfmt(struct cmdarg **args); 164static cmdret *set_wingravity(struct cmdarg **args); 165static cmdret *set_winliststyle(struct cmdarg **args); 166static cmdret *set_winname(struct cmdarg **args); 167static cmdret *set_winaddcurvscreen(struct cmdarg **args); 168 169/* command function prototypes. */ 170static cmdret *cmd_abort(int interactive, struct cmdarg **args); 171static cmdret *cmd_addhook(int interactive, struct cmdarg **args); 172static cmdret *cmd_alias(int interactive, struct cmdarg **args); 173static cmdret *cmd_banish(int interactive, struct cmdarg **args); 174static cmdret *cmd_banishrel(int interactive, struct cmdarg **args); 175static cmdret *cmd_chdir(int interactive, struct cmdarg **args); 176static cmdret *cmd_clrunmanaged(int interactive, struct cmdarg **args); 177static cmdret *cmd_cnext(int interactive, struct cmdarg **args); 178static cmdret *cmd_colon(int interactive, struct cmdarg **args); 179static cmdret *cmd_commands(int interactive, struct cmdarg **args); 180static cmdret *cmd_cother(int interactive, struct cmdarg **args); 181static cmdret *cmd_cprev(int interactive, struct cmdarg **args); 182static cmdret *cmd_curframe(int interactive, struct cmdarg **args); 183static cmdret *cmd_dedicate(int interactive, struct cmdarg **args); 184static cmdret *cmd_definekey(int interactive, struct cmdarg **args); 185static cmdret *cmd_delete(int interactive, struct cmdarg **args); 186static cmdret *cmd_delkmap(int interactive, struct cmdarg **args); 187static cmdret *cmd_describekey(int interactive, struct cmdarg **args); 188static cmdret *cmd_echo(int interactive, struct cmdarg **args); 189static cmdret *cmd_escape(int interactive, struct cmdarg **args); 190static cmdret *cmd_exchangedown(int interactive, struct cmdarg **args); 191static cmdret *cmd_exchangeleft(int interactive, struct cmdarg **args); 192static cmdret *cmd_exchangeright(int interactive, struct cmdarg **args); 193static cmdret *cmd_exchangeup(int interactive, struct cmdarg **args); 194static cmdret *cmd_exec(int interactive, struct cmdarg **args); 195static cmdret *cmd_execa(int interactive, struct cmdarg **args); 196static cmdret *cmd_execf(int interactive, struct cmdarg **args); 197static cmdret *cmd_execv(int interactive, struct cmdarg **args); 198static cmdret *cmd_execw(int interactive, struct cmdarg **args); 199static cmdret *cmd_fdump(int interactive, struct cmdarg **args); 200static cmdret *cmd_focusdown(int interactive, struct cmdarg **args); 201static cmdret *cmd_focuslast(int interactive, struct cmdarg **args); 202static cmdret *cmd_focusleft(int interactive, struct cmdarg **args); 203static cmdret *cmd_focusright(int interactive, struct cmdarg **args); 204static cmdret *cmd_focusup(int interactive, struct cmdarg **args); 205static cmdret *cmd_frestore(int interactive, struct cmdarg **args); 206static cmdret *cmd_fselect(int interactive, struct cmdarg **args); 207static cmdret *cmd_getenv(int interactive, struct cmdarg **args); 208static cmdret *cmd_getsel(int interactive, struct cmdarg **args); 209static cmdret *cmd_gravity(int interactive, struct cmdarg **args); 210static cmdret *cmd_hsplit(int interactive, struct cmdarg **args); 211static cmdret *cmd_help(int interactive, struct cmdarg **args); 212static cmdret *cmd_inext(int interactive, struct cmdarg **args); 213static cmdret *cmd_info(int interactive, struct cmdarg **args); 214static cmdret *cmd_iother(int interactive, struct cmdarg **args); 215static cmdret *cmd_iprev(int interactive, struct cmdarg **args); 216static cmdret *cmd_kill(int interactive, struct cmdarg **args); 217static cmdret *cmd_lastmsg(int interactive, struct cmdarg **args); 218static cmdret *cmd_link(int interactive, struct cmdarg **args); 219static cmdret *cmd_listhook(int interactive, struct cmdarg **args); 220static cmdret *cmd_meta(int interactive, struct cmdarg **args); 221static cmdret *cmd_newkmap(int interactive, struct cmdarg **args); 222static cmdret *cmd_next(int interactive, struct cmdarg **args); 223static cmdret *cmd_nextframe(int interactive, struct cmdarg **args); 224static cmdret *cmd_nextscreen(int interactive, struct cmdarg **args); 225static cmdret *cmd_number(int interactive, struct cmdarg **args); 226static cmdret *cmd_only(int interactive, struct cmdarg **args); 227static cmdret *cmd_other(int interactive, struct cmdarg **args); 228static cmdret *cmd_prev(int interactive, struct cmdarg **args); 229static cmdret *cmd_prevframe(int interactive, struct cmdarg **args); 230static cmdret *cmd_prevscreen(int interactive, struct cmdarg **args); 231static cmdret *cmd_prompt(int interactive, struct cmdarg **args); 232static cmdret *cmd_putsel(int interactive, struct cmdarg **args); 233static cmdret *cmd_quit(int interactive, struct cmdarg **args); 234static cmdret *cmd_ratclick(int interactive, struct cmdarg **args); 235static cmdret *cmd_rathold(int interactive, struct cmdarg **args); 236static cmdret *cmd_ratinfo(int interactive, struct cmdarg **args); 237static cmdret *cmd_ratrelinfo(int interactive, struct cmdarg **args); 238static cmdret *cmd_ratrelwarp(int interactive, struct cmdarg **args); 239static cmdret *cmd_ratwarp(int interactive, struct cmdarg **args); 240static cmdret *cmd_readkey(int interactive, struct cmdarg **args); 241static cmdret *cmd_redisplay(int interactive, struct cmdarg **args); 242static cmdret *cmd_redo(int interactive, struct cmdarg **args); 243static cmdret *cmd_remhook(int interactive, struct cmdarg **args); 244static cmdret *cmd_remove(int interactive, struct cmdarg **args); 245static cmdret *cmd_rename(int interactive, struct cmdarg **args); 246static cmdret *cmd_resize(int interactive, struct cmdarg **args); 247static cmdret *cmd_restart(int interactive, struct cmdarg **args); 248static cmdret *cmd_sdump(int interactive, struct cmdarg **args); 249static cmdret *cmd_select(int interactive, struct cmdarg **args); 250static cmdret *cmd_set(int interactive, struct cmdarg **args); 251static cmdret *cmd_setenv(int interactive, struct cmdarg **args); 252static cmdret *cmd_sfdump(int interactive, struct cmdarg **args); 253static cmdret *cmd_sfrestore(int interactive, struct cmdarg **args); 254static cmdret *cmd_shrink(int interactive, struct cmdarg **args); 255static cmdret *cmd_smove(int interactive, struct cmdarg **args); 256static cmdret *cmd_source(int interactive, struct cmdarg **args); 257static cmdret *cmd_sselect(int interactive, struct cmdarg **args); 258static cmdret *cmd_stick(int interactive, struct cmdarg **args); 259static cmdret *cmd_swap(int interactive, struct cmdarg **args); 260static cmdret *cmd_unalias(int interactive, struct cmdarg **args); 261static cmdret *cmd_undefinekey(int interactive, struct cmdarg **args); 262static cmdret *cmd_undo(int interactive, struct cmdarg **args); 263static cmdret *cmd_unmanage(int interactive, struct cmdarg **args); 264static cmdret *cmd_unsetenv(int interactive, struct cmdarg **args); 265static cmdret *cmd_unstick(int interactive, struct cmdarg **args); 266static cmdret *cmd_vsplit(int interactive, struct cmdarg **args); 267static cmdret *cmd_verbexec(int interactive, struct cmdarg **args); 268static cmdret *cmd_version(int interactive, struct cmdarg **args); 269static cmdret *cmd_vmove(int interactive, struct cmdarg **args); 270static cmdret *cmd_vnext(int interactive, struct cmdarg **args); 271static cmdret *cmd_vother(int interactive, struct cmdarg **args); 272static cmdret *cmd_vprev(int interactive, struct cmdarg **args); 273static cmdret *cmd_vrename(int interactive, struct cmdarg **args); 274static cmdret *cmd_vscreens(int interactive, struct cmdarg **args); 275static cmdret *cmd_vselect(int interactive, struct cmdarg **args); 276static cmdret *cmd_windows(int interactive, struct cmdarg **args); 277 278static void 279add_set_var(char *name, cmdret *(*fn)(struct cmdarg **), int nargs, ...) 280{ 281 int i = 0; 282 struct set_var *var; 283 va_list va; 284 285 var = xmalloc(sizeof(struct set_var)); 286 var->var = name; 287 var->set_fn = fn; 288 var->nargs = nargs; 289 var->args = xmalloc(sizeof(struct argspec) * nargs); 290 291 /* Fill var->args */ 292 va_start(va, nargs); 293 for (i = 0; i < nargs; i++) { 294 var->args[i].prompt = va_arg(va, char *); 295 var->args[i].type = va_arg(va, int); 296 } 297 va_end(va); 298 299 list_add_tail(&var->node, &set_vars); 300} 301 302static void 303set_var_free(struct set_var *var) 304{ 305 if (var == NULL) 306 return; 307 308 free(var->args); 309 free(var); 310} 311 312static void 313init_set_vars(void) 314{ 315 /* Keep this sorted alphabetically. */ 316 add_set_var("barborder", set_barborder, 1, "", arg_NUMBER); 317 add_set_var("barbordercolor", set_barbordercolor, 1, "", arg_STRING); 318 add_set_var("bargravity", set_bargravity, 1, "", arg_GRAVITY); 319 add_set_var("barinpadding", set_barinpadding, 1, "", arg_NUMBER); 320 add_set_var("barpadding", set_barpadding, 2, "", arg_NUMBER, "", 321 arg_NUMBER); 322 add_set_var("barsticky", set_barsticky, 1, "", arg_NUMBER); 323 add_set_var("bgcolor", set_bgcolor, 1, "", arg_STRING); 324 add_set_var("border", set_border, 1, "", arg_NUMBER); 325 add_set_var("bwcolor", set_bwcolor, 1, "", arg_STRING); 326 add_set_var("fgcolor", set_fgcolor, 1, "", arg_STRING); 327 add_set_var("font", set_font, 1, "", arg_STRING); 328 add_set_var("framefmt", set_framefmt, 1, "", arg_REST); 329 add_set_var("framemsgwait", set_framemsgwait, 1, "", arg_NUMBER); 330 add_set_var("framesels", set_framesels, 1, "", arg_STRING); 331 add_set_var("fwcolor", set_fwcolor, 1, "", arg_STRING); 332 add_set_var("gap", set_gap, 1, "", arg_NUMBER); 333 add_set_var("historysize", set_historysize, 1, "", arg_NUMBER); 334 add_set_var("ignoreresizehints", set_ignoreresizehints, 1, "", 335 arg_NUMBER); 336 add_set_var("infofmt", set_infofmt, 1, "", arg_REST); 337 add_set_var("inputwidth", set_inputwidth, 1, "", arg_NUMBER); 338 add_set_var("maxsizegravity", set_maxsizegravity, 1, "", arg_GRAVITY); 339 add_set_var("maxundos", set_maxundos, 1, "", arg_NUMBER); 340 add_set_var("msgwait", set_msgwait, 1, "", arg_NUMBER); 341 add_set_var("onlyborder", set_onlyborder, 1, "", arg_NUMBER); 342 add_set_var("padding", set_padding, 4, "", arg_NUMBER, "", arg_NUMBER, 343 "", arg_NUMBER, "", arg_NUMBER); 344 add_set_var("resizefmt", set_resizefmt, 1, "", arg_REST); 345 add_set_var("resizeunit", set_resizeunit, 1, "", arg_NUMBER); 346 add_set_var("rudeness", set_rudeness, 1, "", arg_NUMBER); 347 add_set_var("startupmessage", set_startupmessage, 1, "", arg_NUMBER); 348 add_set_var("stickyfmt", set_stickyfmt, 1, "", arg_REST); 349 add_set_var("topkmap", set_topkmap, 1, "", arg_STRING); 350 add_set_var("transgravity", set_transgravity, 1, "", arg_GRAVITY); 351 add_set_var("vscreens", set_vscreens, 1, "", arg_NUMBER); 352 add_set_var("waitcursor", set_waitcursor, 1, "", arg_NUMBER); 353 add_set_var("warp", set_warp, 1, "", arg_NUMBER); 354 add_set_var("winfmt", set_winfmt, 1, "", arg_REST); 355 add_set_var("wingravity", set_wingravity, 1, "", arg_GRAVITY); 356 add_set_var("winliststyle", set_winliststyle, 1, "", arg_STRING); 357 add_set_var("winname", set_winname, 1, "", arg_STRING); 358 add_set_var("winaddcurvscreen", set_winaddcurvscreen, 1, "", arg_NUMBER); 359} 360 361/* 362 * i_nrequired is the number required when called interactively. ni_nrequired 363 * is when called non-interactively. 364 */ 365static void 366add_command(char *name, cmdret *(*fn)(int, struct cmdarg **), int nargs, 367 int i_nrequired, int ni_nrequired, ...) 368{ 369 int i = 0; 370 struct user_command *cmd; 371 va_list va; 372 373 cmd = xmalloc(sizeof(struct user_command)); 374 cmd->name = name; 375 cmd->func = fn; 376 cmd->num_args = nargs; 377 cmd->ni_required_args = ni_nrequired; 378 cmd->i_required_args = i_nrequired; 379 cmd->args = nargs ? xmalloc(nargs * sizeof(struct argspec)) : NULL; 380 381 /* Fill cmd->args */ 382 va_start(va, ni_nrequired); 383 for (i = 0; i < nargs; i++) { 384 cmd->args[i].prompt = va_arg(va, char *); 385 cmd->args[i].type = va_arg(va, int); 386 } 387 va_end(va); 388 389 list_add(&cmd->node, &user_commands); 390} 391 392static void 393user_command_free(struct user_command *cmd) 394{ 395 if (cmd == NULL) 396 return; 397 398 free(cmd->args); 399 free(cmd); 400} 401 402void 403init_user_commands(void) 404{ 405 /* @begin (tag required for genrpbindings) */ 406 add_command("abort", cmd_abort, 0, 0, 0); 407 add_command("addhook", cmd_addhook, 2, 2, 2, 408 "Hook: ", arg_HOOK, 409 "Command: ", arg_COMMAND); 410 add_command("alias", cmd_alias, 2, 2, 2, 411 "Alias: ", arg_STRING, 412 "Command: ", arg_COMMAND); 413 add_command("banish", cmd_banish, 0, 0, 0); 414 add_command("chdir", cmd_chdir, 1, 0, 0, 415 "Dir: ", arg_REST); 416 add_command("clrunmanaged", cmd_clrunmanaged, 0, 0, 0); 417 add_command("cnext", cmd_cnext, 0, 0, 0); 418 add_command("colon", cmd_colon, 1, 0, 0, 419 "", arg_REST); 420 add_command("commands", cmd_commands, 0, 0, 0); 421 add_command("cother", cmd_cother, 0, 0, 0); 422 add_command("cprev", cmd_cprev, 0, 0, 0); 423 add_command("curframe", cmd_curframe, 0, 0, 0); 424 add_command("dedicate", cmd_dedicate, 1, 0, 0, 425 "", arg_NUMBER); 426 add_command("definekey", cmd_definekey, 3, 3, 3, 427 "Keymap: ", arg_KEYMAP, 428 "Key: ", arg_KEY, 429 "Command: ", arg_COMMAND); 430 add_command("delete", cmd_delete, 0, 0, 0); 431 add_command("delkmap", cmd_delkmap, 1, 1, 1, 432 "Keymap: ", arg_KEYMAP); 433 add_command("describekey", cmd_describekey, 1, 1, 1, 434 "Keymap: ", arg_KEYMAP); 435 add_command("echo", cmd_echo, 1, 1, 1, 436 "Echo: ", arg_RAW); 437 add_command("escape", cmd_escape, 1, 1, 1, 438 "Key: ", arg_KEY); 439 add_command("exchangedown", cmd_exchangedown, 0, 0, 0); 440 add_command("exchangeleft", cmd_exchangeleft, 0, 0, 0); 441 add_command("exchangeright", cmd_exchangeright, 0, 0, 0); 442 add_command("exchangeup", cmd_exchangeup, 0, 0, 0); 443 add_command("exec", cmd_exec, 1, 1, 1, 444 "/bin/sh -c ", arg_SHELLCMD); 445 add_command("execa", cmd_execa, 1, 1, 1, 446 "/bin/sh -c ", arg_SHELLCMD); 447 add_command("execf", cmd_execf, 2, 2, 2, 448 "frame to execute in:", arg_FRAME, 449 "/bin/sh -c ", arg_SHELLCMD); 450 add_command("execv", cmd_execv, 2, 2, 2, 451 "vscreen to execute in:", arg_VSCREEN, 452 "/bin/sh -c ", arg_SHELLCMD); 453 add_command("execw", cmd_execw, 1, 1, 1, 454 "/bin/sh -c ", arg_SHELLCMD); 455 add_command("fdump", cmd_fdump, 1, 0, 0, 456 "", arg_NUMBER); 457 add_command("focus", cmd_nextframe, 0, 0, 0); 458 add_command("focusdown", cmd_focusdown, 0, 0, 0); 459 add_command("focusprev", cmd_prevframe, 0, 0, 0); 460 add_command("focuslast", cmd_focuslast, 0, 0, 0); 461 add_command("focusleft", cmd_focusleft, 0, 0, 0); 462 add_command("focusright", cmd_focusright, 0, 0, 0); 463 add_command("focusup", cmd_focusup, 0, 0, 0); 464 add_command("frestore", cmd_frestore, 1, 1, 1, 465 "Frames: ", arg_REST); 466 add_command("fselect", cmd_fselect, 1, 1, 1, 467 "", arg_FRAME); 468 add_command("getenv", cmd_getenv, 1, 1, 1, 469 "Variable: ", arg_STRING); 470 add_command("getsel", cmd_getsel, 0, 0, 0); 471 add_command("gravity", cmd_gravity, 1, 0, 0, 472 "Gravity: ", arg_GRAVITY); 473 add_command("help", cmd_help, 1, 0, 0, 474 "Keymap: ", arg_KEYMAP); 475 add_command("hsplit", cmd_hsplit, 1, 0, 0, 476 "Split: ", arg_STRING); 477 add_command("inext", cmd_inext, 0, 0, 0); 478 add_command("info", cmd_info, 1, 0, 0, 479 "Format: ", arg_REST); 480 add_command("iother", cmd_iother, 0, 0, 0); 481 add_command("iprev", cmd_iprev, 0, 0, 0); 482 add_command("kill", cmd_kill, 0, 0, 0); 483 add_command("lastmsg", cmd_lastmsg, 0, 0, 0); 484 add_command("link", cmd_link, 2, 1, 1, 485 "Key: ", arg_STRING, 486 "Keymap: ", arg_KEYMAP); 487 add_command("listhook", cmd_listhook, 1, 1, 1, 488 "Hook: ", arg_HOOK); 489 add_command("meta", cmd_meta, 1, 0, 0, 490 "key: ", arg_KEY); 491 add_command("newkmap", cmd_newkmap, 1, 1, 1, 492 "Keymap: ", arg_STRING); 493 add_command("next", cmd_next, 0, 0, 0); 494 add_command("nextscreen", cmd_nextscreen, 0, 0, 0); 495 add_command("number", cmd_number, 2, 1, 1, 496 "Number: ", arg_NUMBER, 497 "Number: ", arg_NUMBER); 498 add_command("only", cmd_only, 0, 0, 0); 499 add_command("other", cmd_other, 0, 0, 0); 500 add_command("prev", cmd_prev, 0, 0, 0); 501 add_command("prevscreen", cmd_prevscreen, 0, 0, 0); 502 add_command("prompt", cmd_prompt, 1, 0, 0, 503 "", arg_REST); 504 add_command("putsel", cmd_putsel, 1, 1, 1, 505 "Text: ", arg_RAW); 506 add_command("quit", cmd_quit, 0, 0, 0); 507 add_command("ratinfo", cmd_ratinfo, 0, 0, 0); 508 add_command("ratrelinfo", cmd_ratrelinfo, 0, 0, 0); 509 add_command("banishrel", cmd_banishrel, 0, 0, 0); 510 add_command("ratwarp", cmd_ratwarp, 2, 2, 2, 511 "X: ", arg_NUMBER, 512 "Y: ", arg_NUMBER); 513 add_command("ratrelwarp", cmd_ratrelwarp, 2, 2, 2, 514 "X: ", arg_NUMBER, 515 "Y: ", arg_NUMBER); 516 add_command("ratclick", cmd_ratclick, 1, 0, 0, 517 "Button: ", arg_NUMBER); 518 add_command("rathold", cmd_rathold, 2, 1, 1, 519 "State: ", arg_STRING, 520 "Button: ", arg_NUMBER); 521 add_command("readkey", cmd_readkey, 1, 1, 1, 522 "Keymap: ", arg_KEYMAP); 523 add_command("redisplay", cmd_redisplay, 0, 0, 0); 524 add_command("redo", cmd_redo, 0, 0, 0); 525 add_command("remhook", cmd_remhook, 2, 2, 2, 526 "Hook: ", arg_HOOK, 527 "Command: ", arg_COMMAND); 528 add_command("remove", cmd_remove, 0, 0, 0); 529 add_command("resize", cmd_resize, 2, 0, 2, 530 "", arg_NUMBER, 531 "", arg_NUMBER); 532 add_command("restart", cmd_restart, 0, 0, 0); 533 add_command("sdump", cmd_sdump, 0, 0, 0); 534 add_command("select", cmd_select, 1, 0, 1, 535 "Select window: ", arg_REST); 536 add_command("set", cmd_set, 2, 0, 0, 537 "", arg_VARIABLE, 538 "", arg_REST); 539 add_command("setenv", cmd_setenv, 2, 2, 2, 540 "Variable: ", arg_STRING, 541 "Value: ", arg_REST); 542 add_command("sfdump", cmd_sfdump, 0, 0, 0); 543 add_command("sfrestore", cmd_sfrestore, 1, 1, 1, 544 "Frames: ", arg_REST); 545 add_command("shrink", cmd_shrink, 0, 0, 0); 546 add_command("source", cmd_source, 1, 1, 1, 547 "File: ", arg_REST); 548 add_command("smove", cmd_smove, 1, 1, 1, 549 "Screen: ", arg_NUMBER); 550 add_command("sselect", cmd_sselect, 1, 1, 1, 551 "Screen: ", arg_NUMBER); 552 add_command("stick", cmd_stick, 0, 0, 0); 553 add_command("swap", cmd_swap, 2, 1, 1, 554 "destination frame: ", arg_FRAME, 555 "source frame: ", arg_FRAME); 556 add_command("title", cmd_rename, 1, 1, 1, 557 "Set window's title to: ", arg_REST); 558 add_command("unalias", cmd_unalias, 1, 1, 1, 559 "Alias: ", arg_STRING); 560 add_command("undefinekey", cmd_undefinekey, 2, 2, 2, 561 "Keymap: ", arg_KEYMAP, 562 "Key: ", arg_KEY); 563 add_command("undo", cmd_undo, 0, 0, 0); 564 add_command("unmanage", cmd_unmanage, 1, 1, 0, 565 "Unmanage: ", arg_REST); 566 add_command("unsetenv", cmd_unsetenv, 1, 1, 1, 567 "Variable: ", arg_STRING); 568 add_command("unstick", cmd_unstick, 0, 0, 0); 569 add_command("verbexec", cmd_verbexec, 1, 1, 1, 570 "/bin/sh -c ", arg_SHELLCMD); 571 add_command("version", cmd_version, 0, 0, 0); 572 add_command("vmove", cmd_vmove, 1, 1, 1, 573 "Virtual Screen: ", arg_VSCREEN); 574 add_command("vnext", cmd_vnext, 0, 0, 0); 575 add_command("vother", cmd_vother, 0, 0, 0); 576 add_command("vprev", cmd_vprev, 0, 0, 0); 577 add_command("vrename", cmd_vrename, 1, 1, 1, 578 "Change virtual screen name to: ", arg_REST); 579 add_command("vscreens", cmd_vscreens, 0, 0, 0); 580 add_command("vselect", cmd_vselect, 1, 1, 1, 581 "Virtual Screen: ", arg_VSCREEN); 582 add_command("vsplit", cmd_vsplit, 1, 0, 0, 583 "Split: ", arg_STRING); 584 add_command("windows", cmd_windows, 1, 0, 0, 585 "", arg_REST); 586 /* @end (tag required for genrpbindings) */ 587 588 init_set_vars(); 589} 590 591/* Delete all entries in the redo list. */ 592static void 593clear_frame_redos(void) 594{ 595 rp_frame_undo *cur; 596 struct list_head *tmp, *iter; 597 598 list_for_each_safe_entry(cur, iter, tmp, &rp_frame_redos, node) { 599 free(cur->frames); 600 list_del(&(cur->node)); 601 } 602} 603 604static void 605del_frame_undo(rp_frame_undo *u) 606{ 607 if (!u) 608 return; 609 610 free(u->frames); 611 list_del(&(u->node)); 612 free(u); 613} 614 615void 616clear_frame_undos(void) 617{ 618 while (list_size(&rp_frame_undos) > 0) { 619 /* Delete the oldest node */ 620 rp_frame_undo *cur; 621 list_last(cur, &rp_frame_undos, node); 622 del_frame_undo(cur); 623 } 624} 625 626static void 627push_frame_undo(rp_vscreen *vscreen) 628{ 629 rp_frame_undo *cur; 630 631 if (list_size(&rp_frame_undos) > defaults.maxundos) { 632 /* Delete the oldest node */ 633 list_last(cur, &rp_frame_undos, node); 634 del_frame_undo(cur); 635 } 636 cur = xmalloc(sizeof(rp_frame_undo)); 637 cur->frames = fdump(vscreen); 638 cur->vscreen = vscreen; 639 list_add(&cur->node, &rp_frame_undos); 640 /* 641 * Since we're creating new frames the redo list is now invalid, so 642 * clear it. 643 */ 644 clear_frame_redos(); 645} 646 647static rp_frame_undo * 648pop_frame_list(struct list_head *undo_list, struct list_head *redo_list) 649{ 650 rp_vscreen *vscreen = rp_current_vscreen; 651 rp_frame_undo *first, *new; 652 653 /* Is there something to restore? */ 654 list_first(first, undo_list, node); 655 if (!first) 656 return NULL; 657 658 /* First save the current layout into undo */ 659 new = xmalloc(sizeof(rp_frame_undo)); 660 new->frames = fdump(vscreen); 661 new->vscreen = vscreen; 662 list_add(&new->node, redo_list); 663 664 list_del(&(first->node)); 665 return first; 666} 667 668/* Pop the head of the frame undo list off and put it in the redo list. */ 669static rp_frame_undo * 670pop_frame_undo(void) 671{ 672 return pop_frame_list(&rp_frame_undos, &rp_frame_redos); 673} 674 675/* Pop the head of the frame redo list off and put it in the undo list. */ 676static rp_frame_undo * 677pop_frame_redo(void) 678{ 679 return pop_frame_list(&rp_frame_redos, &rp_frame_undos); 680} 681 682rp_action * 683find_keybinding_by_action(char *action, rp_keymap *map) 684{ 685 int i; 686 687 for (i = 0; i < map->actions_last; i++) { 688 if (!strcmp(map->actions[i].data, action)) { 689 return &map->actions[i]; 690 } 691 } 692 693 return NULL; 694} 695 696rp_action * 697find_keybinding(KeySym keysym, unsigned int state, rp_keymap *map) 698{ 699 int i; 700 for (i = 0; i < map->actions_last; i++) { 701 if (map->actions[i].key == keysym && 702 map->actions[i].state == state) 703 return &map->actions[i]; 704 } 705 return NULL; 706} 707 708static char * 709find_command_by_keydesc(char *desc, rp_keymap *map) 710{ 711 int i = 0; 712 char *keysym_name; 713 714 while (i < map->actions_last) { 715 keysym_name = keysym_to_string(map->actions[i].key, 716 map->actions[i].state); 717 if (!strcmp(keysym_name, desc)) { 718 free(keysym_name); 719 return map->actions[i].data; 720 } 721 free(keysym_name); 722 i++; 723 } 724 725 return NULL; 726} 727 728static char * 729resolve_command_from_keydesc(char *desc, int depth, rp_keymap *map) 730{ 731 char *cmd, *c; 732 733 c = find_command_by_keydesc(desc, map); 734 if (!c) 735 return NULL; 736 737 /* is it a link? */ 738 if (strncmp(c, "link", 4) || depth > MAX_LINK_DEPTH) 739 /* it is not */ 740 return c; 741 742 cmd = resolve_command_from_keydesc(&c[5], depth + 1, map); 743 return (cmd != NULL) ? cmd : c; 744} 745 746static void 747add_keybinding(KeySym keysym, int state, char *cmd, rp_keymap *map) 748{ 749 if (map->actions_last >= map->actions_size) { 750 /* double the key table size */ 751 map->actions_size *= 2; 752 map->actions = xrealloc(map->actions, 753 sizeof(rp_action) * map->actions_size); 754 PRINT_DEBUG(("realloc()ed key_table %d\n", map->actions_size)); 755 } 756 map->actions[map->actions_last].key = keysym; 757 map->actions[map->actions_last].state = state; 758 /* free this on shutdown, or re/unbinding */ 759 map->actions[map->actions_last].data = xstrdup(cmd); 760 761 map->actions_last++; 762} 763 764static void 765replace_keybinding(rp_action * key_action, char *newcmd) 766{ 767 free(key_action->data); 768 key_action->data = xstrdup(newcmd); 769} 770 771static int 772remove_keybinding(KeySym keysym, unsigned int state, rp_keymap *map) 773{ 774 int i; 775 int found = -1; 776 777 for (i = 0; i < map->actions_last; i++) { 778 if (map->actions[i].key == keysym && 779 map->actions[i].state == state) { 780 found = i; 781 break; 782 } 783 } 784 785 if (found >= 0) { 786 free(map->actions[found].data); 787 788 memmove(&map->actions[found], &map->actions[found + 1], 789 sizeof(rp_action) * (map->actions_last - found - 1)); 790 map->actions_last--; 791 792 return 1; 793 } 794 795 return 0; 796} 797 798static rp_keymap * 799keymap_new(char *name) 800{ 801 rp_keymap *map; 802 803 /* All keymaps must have a name. */ 804 if (name == NULL) 805 return NULL; 806 807 map = xmalloc(sizeof(rp_keymap)); 808 map->name = xstrdup(name); 809 map->actions_size = 1; 810 map->actions = xmalloc(sizeof(rp_action) * map->actions_size); 811 map->actions_last = 0; 812 813 return map; 814} 815 816rp_keymap * 817find_keymap(char *name) 818{ 819 rp_keymap *cur; 820 821 list_for_each_entry(cur, &rp_keymaps, node) { 822 if (!strcmp(name, cur->name)) { 823 return cur; 824 } 825 } 826 827 return NULL; 828} 829 830/* 831 * Search the alias table for a match. If a match is found, return its index 832 * into the table. Otherwise return -1. 833 */ 834static int 835find_alias_index(char *name) 836{ 837 int i; 838 839 for (i = 0; i < alias_list_last; i++) 840 if (!strcmp(name, alias_list[i].name)) 841 return i; 842 843 return -1; 844} 845 846static void 847add_alias(char *name, char *alias) 848{ 849 int i; 850 851 /* Are we updating an existing alias, or creating a new one? */ 852 i = find_alias_index(name); 853 if (i >= 0) { 854 free(alias_list[i].alias); 855 alias_list[i].alias = xstrdup(alias); 856 } else { 857 if (alias_list_last >= alias_list_size) { 858 alias_list_size *= 2; 859 alias_list = xrealloc(alias_list, 860 sizeof(alias_t) * alias_list_size); 861 } 862 alias_list[alias_list_last].name = xstrdup(name); 863 alias_list[alias_list_last].alias = xstrdup(alias); 864 alias_list_last++; 865 } 866} 867 868void 869initialize_default_keybindings(void) 870{ 871 rp_keymap *map, *top; 872 873 map = keymap_new(ROOT_KEYMAP); 874 list_add(&map->node, &rp_keymaps); 875 876 top = keymap_new(defaults.top_kmap); 877 list_add(&top->node, &rp_keymaps); 878 879 /* Initialize the alias list. */ 880 alias_list_size = 5; 881 alias_list_last = 0; 882 alias_list = xmalloc(sizeof(alias_t) * alias_list_size); 883 884 prefix_key.sym = KEY_PREFIX; 885 prefix_key.state = MODIFIER_PREFIX; 886 887 /* Add the prefix key to the top-level map. */ 888 add_keybinding(prefix_key.sym, prefix_key.state, "readkey " ROOT_KEYMAP, 889 top); 890 891 add_keybinding(prefix_key.sym, prefix_key.state, "other", map); 892 add_keybinding(prefix_key.sym, 0, "meta", map); 893 add_keybinding(XK_g, RP_CONTROL_MASK, "abort", map); 894 add_keybinding(XK_0, 0, "select 0", map); 895 add_keybinding(XK_1, 0, "select 1", map); 896 add_keybinding(XK_2, 0, "select 2", map); 897 add_keybinding(XK_3, 0, "select 3", map); 898 add_keybinding(XK_4, 0, "select 4", map); 899 add_keybinding(XK_5, 0, "select 5", map); 900 add_keybinding(XK_6, 0, "select 6", map); 901 add_keybinding(XK_7, 0, "select 7", map); 902 add_keybinding(XK_8, 0, "select 8", map); 903 add_keybinding(XK_9, 0, "select 9", map); 904 add_keybinding(XK_minus, 0, "select -", map); 905 add_keybinding(XK_A, 0, "title", map); 906 add_keybinding(XK_A, RP_CONTROL_MASK, "title", map); 907 add_keybinding(XK_K, 0, "kill", map); 908 add_keybinding(XK_K, RP_CONTROL_MASK, "kill", map); 909 add_keybinding(XK_Return, 0, "next", map); 910 add_keybinding(XK_Return, RP_CONTROL_MASK, "next", map); 911 add_keybinding(XK_b, 0, "banish", map); 912 add_keybinding(XK_b, RP_CONTROL_MASK, "banish", map); 913 add_keybinding(XK_c, 0, "exec " TERM_PROG, map); 914 add_keybinding(XK_c, RP_CONTROL_MASK, "exec " TERM_PROG, map); 915 add_keybinding(XK_colon, 0, "colon", map); 916 add_keybinding(XK_exclam, 0, "exec", map); 917 add_keybinding(XK_exclam, RP_CONTROL_MASK, 918 "colon exec " TERM_PROG " -e ", map); 919 add_keybinding(XK_i, 0, "info", map); 920 add_keybinding(XK_i, RP_CONTROL_MASK, "info", map); 921 add_keybinding(XK_k, 0, "delete", map); 922 add_keybinding(XK_k, RP_CONTROL_MASK, "delete", map); 923 add_keybinding(XK_l, 0, "redisplay", map); 924 add_keybinding(XK_l, RP_CONTROL_MASK, "redisplay", map); 925 add_keybinding(XK_m, 0, "lastmsg", map); 926 add_keybinding(XK_m, RP_CONTROL_MASK, "lastmsg", map); 927 add_keybinding(XK_n, 0, "next", map); 928 add_keybinding(XK_n, RP_CONTROL_MASK, "next", map); 929 add_keybinding(XK_p, 0, "prev", map); 930 add_keybinding(XK_p, RP_CONTROL_MASK, "prev", map); 931 add_keybinding(XK_quoteright, 0, "select", map); 932 add_keybinding(XK_quoteright, RP_CONTROL_MASK, "select", map); 933 add_keybinding(XK_space, 0, "next", map); 934 add_keybinding(XK_space, RP_CONTROL_MASK, "next", map); 935 add_keybinding(XK_v, 0, "version", map); 936 add_keybinding(XK_v, RP_CONTROL_MASK, "version", map); 937 add_keybinding(XK_w, 0, "windows", map); 938 add_keybinding(XK_w, RP_CONTROL_MASK, "windows", map); 939 add_keybinding(XK_s, 0, "split", map); 940 add_keybinding(XK_s, RP_CONTROL_MASK, "split", map); 941 add_keybinding(XK_S, 0, "hsplit", map); 942 add_keybinding(XK_S, RP_CONTROL_MASK, "hsplit", map); 943 add_keybinding(XK_Tab, 0, "focus", map); 944 add_keybinding(XK_Tab, RP_META_MASK, "focuslast", map); 945 add_keybinding(XK_Left, RP_CONTROL_MASK, "exchangeleft", map); 946 add_keybinding(XK_Right, RP_CONTROL_MASK, "exchangeright", map); 947 add_keybinding(XK_Up, RP_CONTROL_MASK, "exchangeup", map); 948 add_keybinding(XK_Down, RP_CONTROL_MASK, "exchangedown", map); 949 add_keybinding(XK_Left, 0, "focusleft", map); 950 add_keybinding(XK_Right, 0, "focusright", map); 951 add_keybinding(XK_Up, 0, "focusup", map); 952 add_keybinding(XK_Down, 0, "focusdown", map); 953 add_keybinding(XK_Q, 0, "only", map); 954 add_keybinding(XK_R, 0, "remove", map); 955 add_keybinding(XK_f, 0, "fselect", map); 956 add_keybinding(XK_f, RP_CONTROL_MASK, "fselect", map); 957 add_keybinding(XK_F, 0, "curframe", map); 958 add_keybinding(XK_r, 0, "resize", map); 959 add_keybinding(XK_r, RP_CONTROL_MASK, "resize", map); 960 add_keybinding(XK_question, 0, "help " ROOT_KEYMAP, map); 961 add_keybinding(XK_underscore, RP_CONTROL_MASK, "undo", map); 962 add_keybinding(XK_u, 0, "undo", map); 963 add_keybinding(XK_u, RP_CONTROL_MASK, "undo", map); 964 add_keybinding(XK_U, 0, "redo", map); 965 add_keybinding(XK_x, 0, "swap", map); 966 add_keybinding(XK_x, RP_CONTROL_MASK, "swap", map); 967 add_keybinding(XK_N, 0, "nextscreen", map); 968 add_keybinding(XK_P, 0, "prevscreen", map); 969 add_keybinding(XK_F1, 0, "vselect 0", map); 970 add_keybinding(XK_F2, 0, "vselect 1", map); 971 add_keybinding(XK_F3, 0, "vselect 2", map); 972 add_keybinding(XK_F4, 0, "vselect 3", map); 973 add_keybinding(XK_F5, 0, "vselect 4", map); 974 add_keybinding(XK_F6, 0, "vselect 5", map); 975 add_keybinding(XK_F7, 0, "vselect 6", map); 976 add_keybinding(XK_F8, 0, "vselect 7", map); 977 add_keybinding(XK_F9, 0, "vselect 8", map); 978 add_keybinding(XK_F10, 0, "vselect 9", map); 979 add_keybinding(XK_F11, 0, "vselect 10", map); 980 add_keybinding(XK_F12, 0, "vselect 11", map); 981 982 add_alias("unbind", "undefinekey " ROOT_KEYMAP); 983 add_alias("bind", "definekey " ROOT_KEYMAP); 984 add_alias("split", "vsplit"); 985} 986 987cmdret * 988cmdret_new(int success, char *fmt,...) 989{ 990 cmdret *ret; 991 va_list ap; 992 993 ret = xmalloc(sizeof(cmdret)); 994 ret->success = success; 995 996 if (fmt) { 997 va_start(ap, fmt); 998 ret->output = xvsprintf(fmt, ap); 999 va_end(ap); 1000 } else 1001 ret->output = NULL; 1002 1003 return ret; 1004} 1005 1006void 1007cmdret_free(cmdret *ret) 1008{ 1009 free(ret->output); 1010 free(ret); 1011} 1012 1013static void 1014keymap_free(rp_keymap *map) 1015{ 1016 int i; 1017 1018 /* Free the data in the actions. */ 1019 for (i = 0; i < map->actions_last; i++) { 1020 free(map->actions[i].data); 1021 } 1022 1023 /* Free the map data. */ 1024 free(map->actions); 1025 free(map->name); 1026 1027 /* ...and the map itself. */ 1028 free(map); 1029} 1030 1031void 1032free_keymaps(void) 1033{ 1034 rp_keymap *cur; 1035 struct list_head *tmp, *iter; 1036 1037 list_for_each_safe_entry(cur, iter, tmp, &rp_keymaps, node) { 1038 list_del(&cur->node); 1039 keymap_free(cur); 1040 } 1041} 1042 1043void 1044free_aliases(void) 1045{ 1046 int i; 1047 1048 /* Free the alias data. */ 1049 for (i = 0; i < alias_list_last; i++) { 1050 free(alias_list[i].name); 1051 free(alias_list[i].alias); 1052 } 1053 1054 /* Free the alias list. */ 1055 free(alias_list); 1056} 1057 1058void 1059free_user_commands(void) 1060{ 1061 struct user_command *cur; 1062 struct set_var *var; 1063 struct list_head *tmp, *iter; 1064 1065 list_for_each_safe_entry(cur, iter, tmp, &user_commands, node) { 1066 list_del(&cur->node); 1067 user_command_free(cur); 1068 } 1069 list_for_each_safe_entry(var, iter, tmp, &set_vars, node) { 1070 list_del(&var->node); 1071 set_var_free(var); 1072 } 1073} 1074 1075/* 1076 * return a KeySym from a string that contains either a hex value or an X 1077 * keysym description 1078 */ 1079static int 1080string_to_keysym(char *str) 1081{ 1082 int retval; 1083 int keysym; 1084 1085 retval = sscanf(str, "0x%x", &keysym); 1086 1087 if (!retval || retval == EOF) 1088 keysym = XStringToKeysym(str); 1089 1090 return keysym; 1091} 1092 1093static cmdret * 1094parse_keydesc(char *keydesc, struct rp_key *key) 1095{ 1096 char *token, *next_token; 1097 1098 if (keydesc == NULL) 1099 return NULL; 1100 1101 key->state = 0; 1102 key->sym = 0; 1103 1104 if (!strchr(keydesc, '-')) { 1105 /* Its got no hyphens in it, so just grab the keysym */ 1106 key->sym = string_to_keysym(keydesc); 1107 1108 if (key->sym == NoSymbol) 1109 return cmdret_new(RET_FAILURE, 1110 "parse_keydesc: Unknown key '%s'", keydesc); 1111 } else if (keydesc[strlen(keydesc) - 1] == '-') { 1112 /* A key description can't end in a -. */ 1113 return cmdret_new(RET_FAILURE, 1114 "parse_keydesc: Can't parse key '%s'", keydesc); 1115 } else { 1116 /* Its got hyphens, so parse out the modifiers and keysym */ 1117 char *copy; 1118 1119 copy = xstrdup(keydesc); 1120 1121 token = strtok(copy, "-"); 1122 if (token == NULL) { 1123 /* It was nothing but hyphens */ 1124 free(copy); 1125 return cmdret_new(RET_FAILURE, 1126 "parse_keydesc: Can't parse key '%s'", keydesc); 1127 } 1128 do { 1129 next_token = strtok(NULL, "-"); 1130 1131 if (next_token == NULL) { 1132 /* 1133 * There is nothing more to parse and token 1134 * contains the keysym name. 1135 */ 1136 key->sym = string_to_keysym(token); 1137 1138 if (key->sym == NoSymbol) { 1139 cmdret *ret = cmdret_new(RET_FAILURE, 1140 "parse_keydesc: Unknown key '%s'", 1141 token); 1142 free(copy); 1143 return ret; 1144 } 1145 } else { 1146 /* 1147 * Which modifier is it? Only accept modifiers 1148 * that are present. ie don't accept a hyper 1149 * modifier if the keymap has no hyper key. 1150 */ 1151 if (!strcmp(token, "C")) { 1152 key->state |= RP_CONTROL_MASK; 1153 } else if (!strcmp(token, "M")) { 1154 key->state |= RP_META_MASK; 1155 } else if (!strcmp(token, "A")) { 1156 key->state |= RP_ALT_MASK; 1157 } else if (!strcmp(token, "S")) { 1158 key->state |= RP_SHIFT_MASK; 1159 } else if (!strcmp(token, "s")) { 1160 key->state |= RP_SUPER_MASK; 1161 } else if (!strcmp(token, "H")) { 1162 key->state |= RP_HYPER_MASK; 1163 } else { 1164 free(copy); 1165 return cmdret_new(RET_FAILURE, 1166 "parse_keydesc: Unknown modifier '%s'", 1167 token); 1168 } 1169 } 1170 1171 token = next_token; 1172 } while (next_token != NULL); 1173 1174 free(copy); 1175 } 1176 1177 /* Successfully parsed the key. */ 1178 return NULL; 1179} 1180 1181static void 1182grab_rat(void) 1183{ 1184 XGrabPointer(dpy, rp_current_screen->root, True, 0, GrabModeAsync, 1185 GrabModeAsync, None, rp_current_screen->rat, CurrentTime); 1186} 1187 1188static void 1189ungrab_rat(void) 1190{ 1191 XUngrabPointer(dpy, CurrentTime); 1192} 1193 1194/* Unmanage window */ 1195cmdret * 1196cmd_unmanage(int interactive, struct cmdarg **args) 1197{ 1198 if (args[0] == NULL && !interactive) { 1199 cmdret *ret; 1200 char *s = list_unmanaged_windows(); 1201 1202 if (s) 1203 ret = cmdret_new(RET_SUCCESS, "%s", s); 1204 else 1205 ret = cmdret_new(RET_SUCCESS, NULL); 1206 1207 free(s); 1208 return ret; 1209 } 1210 1211 if (!args[0]) 1212 return cmdret_new(RET_FAILURE, 1213 "unmanage: at least one argument required"); 1214 1215 add_unmanaged_window(ARG_STRING(0)); 1216 1217 return cmdret_new(RET_SUCCESS, NULL); 1218} 1219 1220/* Clear the unmanaged window list */ 1221cmdret * 1222cmd_clrunmanaged(int interactive, struct cmdarg **args) 1223{ 1224 clear_unmanaged_list(); 1225 return cmdret_new(RET_SUCCESS, NULL); 1226} 1227 1228cmdret * 1229cmd_undefinekey(int interactive, struct cmdarg **args) 1230{ 1231 cmdret *ret = NULL; 1232 rp_keymap *map; 1233 struct rp_key *key; 1234 1235 map = ARG(0, keymap); 1236 key = ARG(1, key); 1237 1238 /* 1239 * If we're updating the top level map, we'll need to update the keys 1240 * grabbed. 1241 */ 1242 if (map == find_keymap(defaults.top_kmap)) 1243 ungrab_keys_all_wins(); 1244 1245 /* If no comand is specified, then unbind the key. */ 1246 if (!remove_keybinding(key->sym, key->state, map)) 1247 ret = cmdret_new(RET_FAILURE, 1248 "undefinekey: key '%s' is not bound", ARG_STRING(1)); 1249 1250 /* Update the grabbed keys. */ 1251 if (map == find_keymap(defaults.top_kmap)) 1252 grab_keys_all_wins(); 1253 XSync(dpy, False); 1254 1255 if (ret) 1256 return ret; 1257 1258 return cmdret_new(RET_SUCCESS, NULL); 1259} 1260 1261cmdret * 1262cmd_definekey(int interactive, struct cmdarg **args) 1263{ 1264 cmdret *ret = NULL; 1265 rp_keymap *map; 1266 struct rp_key *key; 1267 char *cmd; 1268 rp_action *key_action; 1269 1270 map = ARG(0, keymap); 1271 key = ARG(1, key); 1272 cmd = ARG_STRING(2); 1273 1274 /* 1275 * If we're updating the top level map, we'll need to update the keys 1276 * grabbed. 1277 */ 1278 if (map == find_keymap(defaults.top_kmap)) 1279 ungrab_keys_all_wins(); 1280 1281 if ((key_action = find_keybinding(key->sym, key->state, map))) 1282 replace_keybinding(key_action, cmd); 1283 else 1284 add_keybinding(key->sym, key->state, cmd, map); 1285 1286 /* Update the grabbed keys. */ 1287 if (map == find_keymap(defaults.top_kmap)) 1288 grab_keys_all_wins(); 1289 XSync(dpy, False); 1290 1291 if (ret) 1292 return ret; 1293 1294 return cmdret_new(RET_SUCCESS, NULL); 1295} 1296 1297cmdret * 1298cmd_source(int interactive, struct cmdarg **args) 1299{ 1300 FILE *fileptr; 1301 1302 if ((fileptr = fopen(ARG_STRING(0), "r")) == NULL) 1303 return cmdret_new(RET_FAILURE, "source: %s: %s", ARG_STRING(0), 1304 strerror(errno)); 1305 1306 set_close_on_exec(fileno(fileptr)); 1307 read_rc_file(fileptr); 1308 fclose(fileptr); 1309 1310 return cmdret_new(RET_SUCCESS, NULL); 1311} 1312 1313cmdret * 1314cmd_meta(int interactive, struct cmdarg **args) 1315{ 1316 XEvent ev; 1317 1318 memset(&ev, 0, sizeof(ev)); 1319 /* 1320 * Redundant with the line above, but points out that passing some 1321 * garbage time value trips up some clients 1322 */ 1323 ev.xkey.time = CurrentTime; 1324 1325 if (current_window() == NULL) 1326 return cmdret_new(RET_FAILURE, NULL); 1327 1328 ev.xkey.type = KeyPress; 1329 ev.xkey.display = dpy; 1330 ev.xkey.window = current_window()->w; 1331 1332 if (args[0]) { 1333 struct rp_key key; 1334 cmdret *ret; 1335 1336 memset(&key, 0, sizeof(key)); 1337 ret = parse_keydesc(ARG_STRING(0), &key); 1338 if (ret != NULL) 1339 return ret; 1340 1341 ev.xkey.state = rp_mask_to_x11_mask(key.state); 1342 ev.xkey.keycode = XKeysymToKeycode(dpy, key.sym); 1343 if (ev.xkey.keycode == NoSymbol) 1344 return cmdret_new(RET_FAILURE, 1345 "meta: Couldn't convert keysym to keycode"); 1346 } else { 1347 ev.xkey.state = rp_mask_to_x11_mask(prefix_key.state); 1348 ev.xkey.keycode = XKeysymToKeycode(dpy, prefix_key.sym); 1349 } 1350 1351 XSendEvent(dpy, current_window()->w, False, KeyPressMask, &ev); 1352 XSync(dpy, False); 1353 1354 return cmdret_new(RET_SUCCESS, NULL); 1355} 1356 1357cmdret * 1358cmd_prev(int interactive, struct cmdarg **args) 1359{ 1360 rp_window *cur, *win; 1361 cur = current_window(); 1362 win = vscreen_prev_window(rp_current_vscreen, cur); 1363 1364 if (win) 1365 set_active_window(win); 1366 else if (cur) 1367 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 1368 else 1369 return cmdret_new(RET_FAILURE, "%s", 1370 MESSAGE_NO_MANAGED_WINDOWS); 1371 1372 return cmdret_new(RET_SUCCESS, NULL); 1373} 1374 1375cmdret * 1376cmd_prevframe(int interactive, struct cmdarg **args) 1377{ 1378 rp_frame *frame; 1379 1380 frame = find_frame_prev(current_frame(rp_current_vscreen)); 1381 if (!frame) 1382 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_FRAME); 1383 1384 set_active_frame(frame, 0); 1385 1386 return cmdret_new(RET_SUCCESS, NULL); 1387} 1388 1389cmdret * 1390cmd_next(int interactive, struct cmdarg **args) 1391{ 1392 rp_window *cur, *win; 1393 cur = current_window(); 1394 win = vscreen_next_window(rp_current_vscreen, cur); 1395 1396 if (win) 1397 set_active_window(win); 1398 else if (cur) 1399 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 1400 else 1401 return cmdret_new(RET_FAILURE, "%s", 1402 MESSAGE_NO_MANAGED_WINDOWS); 1403 1404 return cmdret_new(RET_SUCCESS, NULL); 1405} 1406 1407cmdret * 1408cmd_nextframe(int interactive, struct cmdarg **args) 1409{ 1410 rp_frame *frame; 1411 1412 frame = find_frame_next(current_frame(rp_current_vscreen)); 1413 if (!frame) 1414 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_FRAME); 1415 1416 set_active_frame(frame, 0); 1417 1418 return cmdret_new(RET_SUCCESS, NULL); 1419} 1420 1421cmdret * 1422cmd_other(int interactive, struct cmdarg **args) 1423{ 1424 rp_window *w; 1425 1426 /* w = find_window_other (); */ 1427 w = vscreen_last_window(rp_current_vscreen); 1428 if (!w) 1429 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 1430 1431 set_active_window_force(w); 1432 1433 return cmdret_new(RET_SUCCESS, NULL); 1434} 1435 1436/* Parse a positive or null number, returns -1 on failure. */ 1437static int 1438string_to_positive_int(char *str) 1439{ 1440 char *ep; 1441 long lval; 1442 1443 errno = 0; 1444 lval = strtol(str, &ep, 10); 1445 if (str[0] == '\0' || *ep != '\0') 1446 return -1; 1447 if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || 1448 (lval > INT_MAX || lval < 0)) 1449 return -1; 1450 1451 return (int) lval; 1452} 1453 1454static struct list_head * 1455trivial_completions(char *str) 1456{ 1457 struct list_head *list; 1458 1459 /* Initialize our list. */ 1460 list = xmalloc(sizeof(struct list_head)); 1461 INIT_LIST_HEAD(list); 1462 1463 return list; 1464} 1465 1466static struct list_head * 1467keymap_completions(char *str) 1468{ 1469 rp_keymap *cur; 1470 struct list_head *list; 1471 1472 /* Initialize our list. */ 1473 list = xmalloc(sizeof(struct list_head)); 1474 INIT_LIST_HEAD(list); 1475 1476 list_for_each_entry(cur, &rp_keymaps, node) { 1477 struct sbuf *name; 1478 1479 name = sbuf_new(0); 1480 sbuf_copy(name, cur->name); 1481 list_add_tail(&name->node, list); 1482 } 1483 1484 return list; 1485} 1486 1487static struct list_head * 1488window_completions(char *str) 1489{ 1490 rp_window_elem *cur; 1491 struct list_head *list; 1492 1493 /* Initialize our list. */ 1494 list = xmalloc(sizeof(struct list_head)); 1495 INIT_LIST_HEAD(list); 1496 1497 /* Gather the names of all the windows. */ 1498 list_for_each_entry(cur, &rp_current_vscreen->mapped_windows, node) { 1499 struct sbuf *name; 1500 1501 name = sbuf_new(0); 1502 sbuf_copy(name, window_name(cur->win)); 1503 list_add_tail(&name->node, list); 1504 } 1505 1506 return list; 1507} 1508 1509/* switch to window number or name */ 1510cmdret * 1511cmd_select(int interactive, struct cmdarg **args) 1512{ 1513 cmdret *ret = NULL; 1514 char *str; 1515 int n; 1516 1517 /* 1518 * FIXME: This is manually done because of the kinds of things select 1519 * accepts. 1520 */ 1521 if (args[0] == NULL) 1522 str = get_more_input(MESSAGE_PROMPT_SWITCH_TO_WINDOW, "", 1523 hist_SELECT, SUBSTRING, window_completions); 1524 else 1525 str = xstrdup(ARG_STRING(0)); 1526 1527 /* User aborted. */ 1528 if (str == NULL) 1529 return cmdret_new(RET_FAILURE, NULL); 1530 1531 /* Only search if the string contains something to search for. */ 1532 if (strlen(str) > 0) { 1533 if (strlen(str) == 1 && str[0] == '-') { 1534 blank_frame(current_frame(rp_current_vscreen)); 1535 ret = cmdret_new(RET_SUCCESS, NULL); 1536 } else if ((n = string_to_positive_int(str)) >= 0) { 1537 /* try by number */ 1538 rp_window_elem *elem = vscreen_find_window_by_number( 1539 rp_current_vscreen, n); 1540 1541 if (elem) { 1542 goto_window(elem->win); 1543 ret = cmdret_new(RET_SUCCESS, NULL); 1544 } else { 1545 if (interactive) { 1546 /* show the window list as feedback */ 1547 show_bar(rp_current_screen, 1548 defaults.window_fmt); 1549 ret = cmdret_new(RET_SUCCESS, NULL); 1550 } else { 1551 ret = cmdret_new(RET_FAILURE, 1552 "select: unknown window number '%d'", 1553 n); 1554 } 1555 } 1556 } else { 1557 /* try by name */ 1558 rp_window *win = find_window_name(str, 1); 1559 1560 if (!win) 1561 win = find_window_name(str, 0); 1562 1563 if (win) { 1564 goto_window(win); 1565 ret = cmdret_new(RET_SUCCESS, NULL); 1566 } else 1567 ret = cmdret_new(RET_FAILURE, 1568 "select: unknown window '%s'", str); 1569 } 1570 } else 1571 /* Silently fail, since the user didn't provide a window spec */ 1572 ret = cmdret_new(RET_SUCCESS, NULL); 1573 1574 free(str); 1575 1576 return ret; 1577} 1578 1579cmdret * 1580cmd_rename(int interactive, struct cmdarg **args) 1581{ 1582 if (current_window() == NULL) 1583 return cmdret_new(RET_FAILURE, NULL); 1584 1585 free(current_window()->user_name); 1586 current_window()->user_name = xstrdup(ARG_STRING(0)); 1587 current_window()->named = 1; 1588 hook_run(&rp_title_changed_hook); 1589 1590 /* Update the program bar. */ 1591 update_window_names(rp_current_screen, defaults.window_fmt); 1592 1593 return cmdret_new(RET_SUCCESS, NULL); 1594} 1595 1596cmdret * 1597cmd_delete(int interactive, struct cmdarg **args) 1598{ 1599 XEvent ev; 1600 int status; 1601 1602 if (current_window() == NULL) 1603 return cmdret_new(RET_FAILURE, NULL); 1604 1605 ev.xclient.type = ClientMessage; 1606 ev.xclient.window = current_window()->w; 1607 ev.xclient.message_type = wm_protocols; 1608 ev.xclient.format = 32; 1609 ev.xclient.data.l[0] = wm_delete; 1610 ev.xclient.data.l[1] = CurrentTime; 1611 1612 status = XSendEvent(dpy, current_window()->w, False, 0, &ev); 1613 if (status == 0) 1614 PRINT_DEBUG(("Delete window failed\n")); 1615 1616 return cmdret_new(RET_SUCCESS, NULL); 1617} 1618 1619cmdret * 1620cmd_kill(int interactive, struct cmdarg **args) 1621{ 1622 if (current_window() == NULL) 1623 return cmdret_new(RET_FAILURE, NULL); 1624 1625 if (XKillClient(dpy, current_window()->w) == BadValue) 1626 return cmdret_new(RET_FAILURE, 1627 "kill failed (got BadValue, this may be a bug)"); 1628 1629 return cmdret_new(RET_SUCCESS, NULL); 1630} 1631 1632cmdret * 1633cmd_version(int interactive, struct cmdarg **args) 1634{ 1635 return cmdret_new(RET_SUCCESS, "%s %s", PROGNAME, VERSION); 1636} 1637 1638static char * 1639frame_selector(unsigned int n) 1640{ 1641 if (n < strlen(defaults.frame_selectors)) { 1642 return xsprintf(" %c ", defaults.frame_selectors[n]); 1643 } else { 1644 return xsprintf(" %d ", n); 1645 } 1646} 1647 1648/* Return true if ch is nth frame selector. */ 1649static int 1650frame_selector_match(char ch) 1651{ 1652 size_t i; 1653 1654 /* Is it in the frame selector string? */ 1655 for (i = 0; i < strlen(defaults.frame_selectors); i++) { 1656 if (ch == defaults.frame_selectors[i]) 1657 return i; 1658 } 1659 1660 /* 1661 * Maybe it's a number less than 9 and the frame selector doesn't 1662 * define that many selectors. 1663 */ 1664 if (ch >= '0' && ch <= '9' 1665 && (size_t) (ch - '0') >= strlen(defaults.frame_selectors)) { 1666 return ch - '0'; 1667 } 1668 return -1; 1669} 1670 1671static cmdret * 1672read_string(struct argspec *spec, struct sbuf *s, int history_id, 1673 completion_fn fn, struct cmdarg ** arg) 1674{ 1675 char *input; 1676 1677 if (s) 1678 input = xstrdup(sbuf_get(s)); 1679 else 1680 input = get_input(spec->prompt, history_id, fn); 1681 1682 if (input) { 1683 *arg = xmalloc(sizeof(struct cmdarg)); 1684 (*arg)->type = spec->type; 1685 (*arg)->string = input; 1686 return NULL; 1687 } 1688 1689 *arg = NULL; 1690 return cmdret_new(RET_SUCCESS, NULL); 1691} 1692 1693static cmdret * 1694read_keymap(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 1695{ 1696 char *input; 1697 1698 if (s) 1699 input = xstrdup(sbuf_get(s)); 1700 else 1701 input = get_input(spec->prompt, hist_KEYMAP, keymap_completions); 1702 1703 if (input) { 1704 rp_keymap *map; 1705 1706 map = find_keymap(input); 1707 if (map == NULL) { 1708 cmdret *ret = cmdret_new(RET_FAILURE, 1709 "unknown keymap '%s'", input); 1710 free(input); 1711 return ret; 1712 } 1713 1714 *arg = xmalloc(sizeof(struct cmdarg)); 1715 (*arg)->type = spec->type; 1716 (*arg)->arg.keymap = map; 1717 (*arg)->string = input; 1718 1719 return NULL; 1720 } 1721 1722 *arg = NULL; 1723 return cmdret_new(RET_SUCCESS, NULL); 1724} 1725 1726static cmdret * 1727read_keydesc(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 1728{ 1729 char *input; 1730 1731 if (s) 1732 input = xstrdup(sbuf_get(s)); 1733 else 1734 input = get_input(spec->prompt, hist_KEY, trivial_completions); 1735 1736 if (input) { 1737 cmdret *ret; 1738 struct rp_key *key = xmalloc(sizeof(struct rp_key)); 1739 1740 ret = parse_keydesc(input, key); 1741 if (ret) { 1742 free(key); 1743 return ret; 1744 } 1745 1746 *arg = xmalloc(sizeof(struct cmdarg)); 1747 (*arg)->type = spec->type; 1748 (*arg)->arg.key = key; 1749 (*arg)->string = input; 1750 1751 return NULL; 1752 } 1753 1754 *arg = NULL; 1755 return cmdret_new(RET_SUCCESS, NULL); 1756} 1757 1758static struct list_head * 1759vscreen_completions(char *str) 1760{ 1761 struct list_head *list; 1762 rp_vscreen *cur; 1763 1764 /* Initialize our list. */ 1765 list = xmalloc(sizeof(struct list_head)); 1766 INIT_LIST_HEAD(list); 1767 1768 /* Grab all the vscreen names. */ 1769 list_for_each_entry(cur, &(rp_current_screen)->vscreens, node) { 1770 struct sbuf *s; 1771 1772 s = sbuf_new(0); 1773 if (cur->name) { 1774 sbuf_copy(s, cur->name); 1775 } else { 1776 sbuf_printf(s, "%d", cur->number); 1777 } 1778 1779 list_add_tail(&s->node, list); 1780 } 1781 1782 return list; 1783} 1784 1785static struct list_head * 1786colon_completions(char *str) 1787{ 1788 int i; 1789 struct user_command *uc; 1790 struct sbuf *s; 1791 struct list_head *list; 1792 1793 /* Initialize our list. */ 1794 list = xmalloc(sizeof(struct list_head)); 1795 INIT_LIST_HEAD(list); 1796 1797 /* Put all the aliases in our list. */ 1798 for (i = 0; i < alias_list_last; ++i) { 1799 s = sbuf_new(0); 1800 sbuf_copy(s, alias_list[i].name); 1801 /* 1802 * The space is so when the user completes a space is 1803 * conveniently inserted after the command. 1804 */ 1805 sbuf_concat(s, " "); 1806 list_add_tail(&s->node, list); 1807 } 1808 1809 /* Put all the commands in our list. */ 1810 list_for_each_entry(uc, &user_commands, node) { 1811 s = sbuf_new(0); 1812 sbuf_copy(s, uc->name); 1813 /* 1814 * The space is so when the user completes a space is 1815 * conveniently inserted after the command. 1816 */ 1817 sbuf_concat(s, " "); 1818 list_add_tail(&s->node, list); 1819 } 1820 1821 return list; 1822} 1823 1824static cmdret * 1825read_command(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 1826{ 1827 return read_string(spec, s, hist_COMMAND, colon_completions, arg); 1828} 1829 1830static struct list_head * 1831exec_completions(char *str) 1832{ 1833 size_t n = 256; 1834 char *partial; 1835 struct sbuf *line; 1836 FILE *file; 1837 struct list_head *head; 1838 char *completion_string; 1839 1840 /* Initialize our list. */ 1841 head = xmalloc(sizeof(struct list_head)); 1842 INIT_LIST_HEAD(head); 1843 1844 /* FIXME: A Bash dependancy?? */ 1845 completion_string = xsprintf("bash -c \"compgen -ac %s|sort\"", str); 1846 file = popen(completion_string, "r"); 1847 free(completion_string); 1848 if (!file) { 1849 warn("popen failed"); 1850 return head; 1851 } 1852 partial = xmalloc(n); 1853 1854 /* 1855 * Read data from the file, split it into lines and store it in a list. 1856 */ 1857 line = sbuf_new(0); 1858 while (fgets(partial, n, file) != NULL) { 1859 /* Read a chunk from the file into our line accumulator. */ 1860 sbuf_concat(line, partial); 1861 1862 if (feof(file) || 1863 (*(sbuf_get(line) + strlen(sbuf_get(line)) - 1) == '\n')) { 1864 char *s; 1865 struct sbuf *elem; 1866 1867 s = sbuf_get(line); 1868 1869 /* Frob the newline into */ 1870 if (*(s + strlen(s) - 1) == '\n') 1871 *(s + strlen(s) - 1) = '\0'; 1872 1873 /* Add our line to the list. */ 1874 elem = sbuf_new(0); 1875 sbuf_copy(elem, s); 1876 list_add_tail(&elem->node, head); 1877 1878 sbuf_clear(line); 1879 } 1880 } 1881 1882 sbuf_free(line); 1883 1884 free(partial); 1885 pclose(file); 1886 1887 return head; 1888} 1889 1890static cmdret * 1891read_shellcmd(struct argspec *spec, struct sbuf *s, struct cmdarg **arg, 1892 const char *command_name) 1893{ 1894 cmdret *ret; 1895 1896 ret = read_string(spec, s, hist_SHELLCMD, exec_completions, arg); 1897 if (command_name && !s && !ret && (*arg)->string) { 1898 /* store for command history */ 1899 struct sbuf *buf; 1900 1901 buf = sbuf_new(0); 1902 sbuf_printf(buf, "%s %s", command_name, (*arg)->string); 1903 history_add(hist_COMMAND, sbuf_get(buf)); 1904 sbuf_free(buf); 1905 } 1906 1907 return ret; 1908} 1909 1910static cmdret * 1911read_frame(struct sbuf *s, struct cmdarg **arg) 1912{ 1913 rp_frame *frame; 1914 XSetWindowAttributes attr; 1915 int fnum = -1; 1916 KeySym c; 1917 char keysym_buf[513]; 1918 int keysym_bufsize = sizeof(keysym_buf); 1919 unsigned int mod; 1920 Window *wins; 1921 int i = 0; 1922 rp_frame *cur_frame; 1923 rp_screen *cur_screen = rp_current_screen; 1924 int frames; 1925 1926 if (s == NULL) { 1927 frames = num_frames(rp_current_vscreen); 1928 wins = xmalloc(sizeof(Window) * frames); 1929 1930 /* 1931 * Loop through each frame and display its number in its top 1932 * left corner. 1933 */ 1934 attr.border_pixel = rp_glob_screen.fgcolor; 1935 attr.background_pixel = rp_glob_screen.bgcolor; 1936 attr.override_redirect = True; 1937 1938 list_for_each_entry(cur_frame, &rp_current_vscreen->frames, 1939 node) { 1940 int width, height; 1941 char *num; 1942 1943 /* 1944 * Create the string to be displayed in the 1945 * window and determine the height and width of 1946 * the window. 1947 */ 1948 num = frame_selector(cur_frame->number); 1949 width = defaults.bar_x_padding * 2 + 1950 rp_text_width(cur_screen, num, -1, NULL); 1951 height = (FONT_HEIGHT(cur_screen) + 1952 defaults.bar_y_padding * 2); 1953 1954 /* Create and map the window. */ 1955 wins[i] = XCreateWindow(dpy, cur_screen->root, 1956 cur_frame->x, 1957 cur_frame->y, width, 1958 height, defaults.bar_border_width, 1959 CopyFromParent, CopyFromParent, 1960 CopyFromParent, 1961 CWOverrideRedirect|CWBorderPixel|CWBackPixel, 1962 &attr); 1963 XMapWindow(dpy, wins[i]); 1964 XClearWindow(dpy, wins[i]); 1965 1966 /* Display the frame's number inside the window. */ 1967 rp_draw_string(cur_screen, wins[i], STYLE_NORMAL, 1968 defaults.bar_x_padding, 1969 defaults.bar_y_padding + 1970 FONT_ASCENT(cur_screen), num, -1, 1971 NULL, NULL); 1972 1973 free(num); 1974 i++; 1975 } 1976 XSync(dpy, False); 1977 1978 /* Read a key. */ 1979 read_single_key(&c, &mod, keysym_buf, keysym_bufsize); 1980 1981 /* Destroy our number windows and free the array. */ 1982 for (i = 0; i < frames; i++) 1983 XDestroyWindow(dpy, wins[i]); 1984 1985 free(wins); 1986 1987 /* FIXME: We only handle one character long keysym names. */ 1988 if (strlen(keysym_buf) == 1) { 1989 fnum = frame_selector_match(keysym_buf[0]); 1990 if (fnum == -1) 1991 return cmdret_new(RET_FAILURE, 1992 "unknown frame selector `%s'", keysym_buf); 1993 } else { 1994 return cmdret_new(RET_FAILURE, 1995 "frame selector too long `%s'", keysym_buf); 1996 } 1997 } else { 1998 fnum = string_to_positive_int(sbuf_get(s)); 1999 if (fnum == -1) 2000 return cmdret_new(RET_FAILURE, 2001 "invalid frame selector `%s', negative or too big", 2002 sbuf_get(s)); 2003 } 2004 2005 /* 2006 * Now that we have a frame number to go to, let's try to jump to it. 2007 */ 2008 frame = find_frame_number(rp_current_vscreen, fnum); 2009 if (frame) { 2010 /* 2011 * We have to return a string, because commands get lists of 2012 * strings. Sucky, yes. The command is simply going to parse 2013 * it back into an rp_frame. 2014 */ 2015 *arg = xmalloc(sizeof(struct cmdarg)); 2016 (*arg)->type = arg_FRAME; 2017 (*arg)->string = NULL; 2018 (*arg)->arg.frame = frame; 2019 return NULL; 2020 } 2021 2022 return cmdret_new(RET_FAILURE, "frame not found"); 2023} 2024 2025static cmdret * 2026read_window(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2027{ 2028 rp_window *win = NULL; 2029 char *name; 2030 int n; 2031 2032 if (s) 2033 name = xstrdup(sbuf_get(s)); 2034 else 2035 name = get_input(spec->prompt, hist_WINDOW, window_completions); 2036 2037 if (name) { 2038 /* try by number */ 2039 if ((n = string_to_positive_int(name)) >= 0) { 2040 rp_window_elem *elem = vscreen_find_window_by_number( 2041 rp_current_vscreen, n); 2042 if (elem) 2043 win = elem->win; 2044 } else { 2045 /* try by name */ 2046 win = find_window_name(name, 1); 2047 if (win == NULL) 2048 win = find_window_name(name, 0); 2049 } 2050 2051 if (win) { 2052 *arg = xmalloc(sizeof(struct cmdarg)); 2053 (*arg)->type = arg_WINDOW; 2054 (*arg)->arg.win = win; 2055 (*arg)->string = name; 2056 return NULL; 2057 } 2058 2059 free(name); 2060 *arg = NULL; 2061 return cmdret_new(RET_SUCCESS, NULL); 2062 } 2063 2064 /* user abort. */ 2065 *arg = NULL; 2066 return cmdret_new(RET_SUCCESS, NULL); 2067} 2068 2069static int 2070parse_wingravity(char *data) 2071{ 2072 int ret = -1; 2073 2074 if (!strcasecmp(data, "northwest") || !strcasecmp(data, "nw") || !strcmp(data, "7")) 2075 ret = NorthWestGravity; 2076 if (!strcasecmp(data, "north") || !strcasecmp(data, "n") || !strcmp(data, "8")) 2077 ret = NorthGravity; 2078 if (!strcasecmp(data, "northeast") || !strcasecmp(data, "ne") || !strcmp(data, "9")) 2079 ret = NorthEastGravity; 2080 if (!strcasecmp(data, "west") || !strcasecmp(data, "w") || !strcmp(data, "4")) 2081 ret = WestGravity; 2082 if (!strcasecmp(data, "center") || !strcasecmp(data, "c") || !strcmp(data, "5")) 2083 ret = CenterGravity; 2084 if (!strcasecmp(data, "east") || !strcasecmp(data, "e") || !strcmp(data, "6")) 2085 ret = EastGravity; 2086 if (!strcasecmp(data, "southwest") || !strcasecmp(data, "sw") || !strcmp(data, "1")) 2087 ret = SouthWestGravity; 2088 if (!strcasecmp(data, "south") || !strcasecmp(data, "s") || !strcmp(data, "2")) 2089 ret = SouthGravity; 2090 if (!strcasecmp(data, "southeast") || !strcasecmp(data, "se") || !strcmp(data, "3")) 2091 ret = SouthEastGravity; 2092 2093 return ret; 2094} 2095 2096static cmdret * 2097read_gravity(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2098{ 2099 char *input; 2100 2101 if (s) 2102 input = xstrdup(sbuf_get(s)); 2103 else 2104 input = get_input(spec->prompt, hist_GRAVITY, 2105 trivial_completions); 2106 2107 if (input) { 2108 int g = parse_wingravity(input); 2109 2110 if (g == -1) { 2111 cmdret *ret = cmdret_new(RET_FAILURE, 2112 "bad gravity '%s'", input); 2113 free(input); 2114 return ret; 2115 } 2116 2117 *arg = xmalloc(sizeof(struct cmdarg)); 2118 (*arg)->type = arg_GRAVITY; 2119 (*arg)->arg.gravity = g; 2120 (*arg)->string = input; 2121 2122 return NULL; 2123 } 2124 2125 *arg = NULL; 2126 return cmdret_new(RET_SUCCESS, NULL); 2127} 2128 2129/* 2130 * Given a string, find a matching vscreen. First check if the string exactly 2131 * matches a vscreen name, then check if it is a number & lastly check if it 2132 * partially matches the name of a vscreen. 2133 */ 2134static rp_vscreen * 2135find_vscreen(char *str) 2136{ 2137 rp_vscreen *vscreen; 2138 int n; 2139 2140 /* Exact matches are special cases. */ 2141 if ((vscreen = screen_find_vscreen_by_name(rp_current_screen, str, 1))) 2142 return vscreen; 2143 2144 /* Check if the user typed a vsceen number. */ 2145 n = string_to_positive_int(str); 2146 if (n >= 0) { 2147 vscreen = screen_find_vscreen_by_number(rp_current_screen, n); 2148 if (vscreen) 2149 return vscreen; 2150 } 2151 2152 vscreen = screen_find_vscreen_by_name(rp_current_screen, str, 0); 2153 return vscreen; 2154} 2155 2156static cmdret * 2157read_vscreen(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2158{ 2159 char *input; 2160 2161 if (s) 2162 input = xstrdup(sbuf_get(s)); 2163 else 2164 input = get_input(spec->prompt, hist_VSCREEN, 2165 vscreen_completions); 2166 2167 if (input) { 2168 rp_vscreen *v = find_vscreen(input); 2169 if (v) { 2170 *arg = xmalloc(sizeof(struct cmdarg)); 2171 (*arg)->type = arg_VSCREEN; 2172 (*arg)->arg.vscreen = v; 2173 (*arg)->string = input; 2174 return NULL; 2175 } 2176 2177 cmdret *ret = cmdret_new(RET_FAILURE, "unknown vscreen '%s'", 2178 input); 2179 free(input); 2180 return ret; 2181 } 2182 2183 *arg = NULL; 2184 return cmdret_new(RET_SUCCESS, NULL); 2185} 2186 2187static struct list_head * 2188hook_completions(char *str) 2189{ 2190 struct list_head *list; 2191 struct rp_hook_db_entry *entry; 2192 2193 /* Initialize our list. */ 2194 list = xmalloc(sizeof(struct list_head)); 2195 INIT_LIST_HEAD(list); 2196 2197 for (entry = rp_hook_db; entry->name; entry++) { 2198 struct sbuf *hookname; 2199 2200 hookname = sbuf_new(0); 2201 sbuf_copy(hookname, entry->name); 2202 list_add_tail(&hookname->node, list); 2203 } 2204 2205 return list; 2206} 2207 2208static cmdret * 2209read_hook(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2210{ 2211 char *input; 2212 2213 if (s) 2214 input = xstrdup(sbuf_get(s)); 2215 else 2216 input = get_input(spec->prompt, hist_HOOK, hook_completions); 2217 2218 if (input) { 2219 struct list_head *hook = hook_lookup(input); 2220 2221 if (hook) { 2222 *arg = xmalloc(sizeof(struct cmdarg)); 2223 (*arg)->type = arg_HOOK; 2224 (*arg)->arg.hook = hook; 2225 (*arg)->string = input; 2226 return NULL; 2227 } 2228 2229 cmdret *ret = cmdret_new(RET_FAILURE, "unknown hook '%s'", 2230 input); 2231 free(input); 2232 return ret; 2233 } 2234 2235 *arg = NULL; 2236 return cmdret_new(RET_SUCCESS, NULL); 2237} 2238 2239static struct set_var * 2240find_variable(char *str) 2241{ 2242 struct set_var *cur; 2243 2244 list_for_each_entry(cur, &set_vars, node) { 2245 if (!strcmp(str, cur->var)) 2246 return cur; 2247 } 2248 2249 return NULL; 2250} 2251 2252static struct list_head * 2253var_completions(char *str) 2254{ 2255 struct list_head *list; 2256 struct set_var *cur; 2257 2258 /* Initialize our list. */ 2259 list = xmalloc(sizeof(struct list_head)); 2260 INIT_LIST_HEAD(list); 2261 2262 /* Grab all the vscreen names. */ 2263 list_for_each_entry(cur, &set_vars, node) { 2264 struct sbuf *s; 2265 2266 s = sbuf_new(0); 2267 sbuf_copy(s, cur->var); 2268 list_add_tail(&s->node, list); 2269 } 2270 2271 return list; 2272} 2273 2274static cmdret * 2275read_variable(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2276{ 2277 char *input; 2278 2279 if (s) 2280 input = xstrdup(sbuf_get(s)); 2281 else 2282 input = get_input(spec->prompt, hist_VARIABLE, var_completions); 2283 2284 if (input) { 2285 struct set_var *var = find_variable(input); 2286 2287 if (var == NULL) { 2288 cmdret *ret = cmdret_new(RET_FAILURE, 2289 "unknown variable '%s'", input); 2290 free(input); 2291 return ret; 2292 } 2293 2294 *arg = xmalloc(sizeof(struct cmdarg)); 2295 (*arg)->type = arg_VARIABLE; 2296 (*arg)->arg.variable = var; 2297 (*arg)->string = input; 2298 2299 return NULL; 2300 } 2301 2302 *arg = NULL; 2303 return cmdret_new(RET_SUCCESS, NULL); 2304} 2305 2306static cmdret * 2307read_number(struct argspec *spec, struct sbuf *s, struct cmdarg **arg) 2308{ 2309 char *input; 2310 2311 if (s) 2312 input = xstrdup(sbuf_get(s)); 2313 else 2314 /* numbers should perhaps be more fine grained, or hist_NONE */ 2315 input = get_input(spec->prompt, hist_OTHER, 2316 trivial_completions); 2317 2318 if (input) { 2319 char *ep; 2320 long lval; 2321 2322 errno = 0; 2323 lval = strtol(input, &ep, 10); 2324 if (input[0] == '\0' || *ep != '\0') 2325 return cmdret_new(RET_FAILURE, "malformed number `%s'", 2326 input); 2327 if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || 2328 (lval > INT_MAX || lval < INT_MIN)) 2329 return cmdret_new(RET_FAILURE, "out of range number `%s'", 2330 input); 2331 2332 *arg = xmalloc(sizeof(struct cmdarg)); 2333 (*arg)->type = arg_NUMBER; 2334 (*arg)->arg.number = lval; 2335 (*arg)->string = input; 2336 2337 return NULL; 2338 } 2339 2340 *arg = NULL; 2341 return cmdret_new(RET_SUCCESS, NULL); 2342} 2343 2344static cmdret * 2345read_arg(struct argspec *spec, struct sbuf *s, struct cmdarg **arg, 2346 const char *command_name) 2347{ 2348 cmdret *ret = NULL; 2349 2350 switch (spec->type) { 2351 case arg_STRING: 2352 case arg_REST: 2353 case arg_RAW: 2354 ret = read_string(spec, s, hist_OTHER, trivial_completions, arg); 2355 break; 2356 case arg_KEYMAP: 2357 ret = read_keymap(spec, s, arg); 2358 break; 2359 case arg_KEY: 2360 ret = read_keydesc(spec, s, arg); 2361 break; 2362 case arg_NUMBER: 2363 ret = read_number(spec, s, arg); 2364 break; 2365 case arg_GRAVITY: 2366 ret = read_gravity(spec, s, arg); 2367 break; 2368 case arg_COMMAND: 2369 ret = read_command(spec, s, arg); 2370 break; 2371 case arg_SHELLCMD: 2372 ret = read_shellcmd(spec, s, arg, command_name); 2373 break; 2374 case arg_WINDOW: 2375 ret = read_window(spec, s, arg); 2376 break; 2377 case arg_FRAME: 2378 ret = read_frame(s, arg); 2379 break; 2380 case arg_VSCREEN: 2381 ret = read_vscreen(spec, s, arg); 2382 break; 2383 case arg_HOOK: 2384 ret = read_hook(spec, s, arg); 2385 break; 2386 case arg_VARIABLE: 2387 ret = read_variable(spec, s, arg); 2388 break; 2389 } 2390 2391 return ret; 2392} 2393 2394/* Return -1 on failure. Return the number of args on success. */ 2395static cmdret * 2396parsed_input_to_args(int num_args, struct argspec *argspec, 2397 struct list_head *list, struct list_head *args, int *parsed_args, 2398 const char *command_name) 2399{ 2400 struct sbuf *s; 2401 struct cmdarg *arg; 2402 cmdret *ret; 2403 2404 PRINT_DEBUG(("list len: %d\n", list_size(list))); 2405 2406 *parsed_args = 0; 2407 2408 /* Convert the existing entries to cmdarg's. */ 2409 list_for_each_entry(s, list, node) { 2410 if (*parsed_args >= num_args) 2411 break; 2412 2413 ret = read_arg(&argspec[*parsed_args], s, &arg, command_name); 2414 /* If there was an error, then abort. */ 2415 if (ret) 2416 return ret; 2417 2418 list_add_tail(&arg->node, args); 2419 (*parsed_args)++; 2420 } 2421 2422 return NULL; 2423} 2424 2425/* 2426 * Prompt the user for missing arguments. Returns non-zero on failure. 0 on 2427 * success. 2428 */ 2429static cmdret * 2430fill_in_missing_args(struct user_command *cmd, struct list_head *list, 2431 struct list_head *args, const char *command_name) 2432{ 2433 cmdret *ret; 2434 struct cmdarg *arg; 2435 int i = 0; 2436 2437 ret = parsed_input_to_args(cmd->num_args, cmd->args, list, args, &i, 2438 command_name); 2439 if (ret) 2440 return ret; 2441 2442 /* Fill in the rest of the required arguments. */ 2443 for (; i < cmd->i_required_args; i++) { 2444 ret = read_arg(&cmd->args[i], NULL, &arg, command_name); 2445 if (ret) 2446 return ret; 2447 list_add_tail(&arg->node, args); 2448 } 2449 2450 return NULL; 2451} 2452 2453/* 2454 * Stick a list of sbuf's in list. if nargs >= 0 then only parse nargs 2455 * arguments and and the rest of the string to the list. Return 0 on success. 2456 * non-zero on failure. When raw is true, then when we hit nargs, we should 2457 * keep any whitespace at the beginning. When false, gobble the whitespace. 2458 */ 2459static cmdret * 2460parse_args(char *str, struct list_head * list, int nargs, int raw) 2461{ 2462 cmdret *ret = NULL; 2463 char *i; 2464 char *tmp; 2465 int len = 0; 2466 int str_escape = 0; 2467 int in_str = 0; 2468 int gobble = 1; 2469 int parsed_args = 0; 2470 2471 if (str == NULL) 2472 return NULL; 2473 2474 tmp = xmalloc(strlen(str) + 1); 2475 2476 for (i = str; *i; i++) { 2477 /* Have we hit the arg limit? */ 2478 if (raw && parsed_args >= nargs) { 2479 struct sbuf *s = sbuf_new(0); 2480 if (!raw) { 2481 while (*i && isspace((unsigned char) *i)) 2482 i++; 2483 } 2484 if (*i) { 2485 sbuf_concat(s, i); 2486 list_add_tail(&s->node, list); 2487 } 2488 len = 0; 2489 break; 2490 } 2491 2492 /* Should we eat the whitespace? */ 2493 if (gobble) { 2494 while (*i && isspace((unsigned char) *i)) 2495 i++; 2496 gobble = 0; 2497 } 2498 2499 /* Escaped characters always get added. */ 2500 if (str_escape) { 2501 tmp[len] = *i; 2502 len++; 2503 str_escape = 0; 2504 } else if (*i == '\\') { 2505 str_escape = 1; 2506 } else if (*i == '"') { 2507 if (in_str) { 2508 /* End the arg. */ 2509 struct sbuf *s = sbuf_new(0); 2510 2511 sbuf_nconcat(s, tmp, len); 2512 list_add_tail(&s->node, list); 2513 len = 0; 2514 gobble = 1; 2515 in_str = 0; 2516 parsed_args++; 2517 } else if (len == 0) { 2518 /* 2519 * A string open can only start at the 2520 * beginning of an argument. 2521 */ 2522 in_str = 1; 2523 } else { 2524 ret = cmdret_new(RET_FAILURE, 2525 "parse error in '%s'", str); 2526 break; 2527 } 2528 } else if (isspace((unsigned char) *i) && !in_str) { 2529 /* End the current arg, and start a new one. */ 2530 struct sbuf *s = sbuf_new(0); 2531 sbuf_nconcat(s, tmp, len); 2532 list_add_tail(&s->node, list); 2533 len = 0; 2534 gobble = 1; 2535 parsed_args++; 2536 } else { 2537 /* Add the character to the argument. */ 2538 tmp[len] = *i; 2539 len++; 2540 } 2541 } 2542 2543 /* Add the remaining text in tmp. */ 2544 if (ret == NULL && len) { 2545 struct sbuf *s = sbuf_new(0); 2546 sbuf_nconcat(s, tmp, len); 2547 list_add_tail(&s->node, list); 2548 } 2549 2550 free(tmp); 2551 return ret; 2552} 2553 2554/* Convert the list to an array, for easier access in commands. */ 2555static struct cmdarg ** 2556arg_array(struct list_head *head) 2557{ 2558 int i = 0; 2559 struct cmdarg **args, *cur; 2560 2561 args = xmalloc(sizeof(struct cmdarg *) * (list_size(head) + 1)); 2562 list_for_each_entry(cur, head, node) { 2563 args[i] = cur; 2564 i++; 2565 } 2566 2567 /* NULL terminate the array. */ 2568 args[list_size(head)] = NULL; 2569 return args; 2570} 2571 2572static void 2573arg_free(struct cmdarg *arg) 2574{ 2575 if (!arg) 2576 return; 2577 2578 /* read_frame doesn't fill in string. */ 2579 free(arg->string); 2580 2581 switch (arg->type) { 2582 case arg_KEY: 2583 free(arg->arg.key); 2584 break; 2585 case arg_REST: 2586 case arg_STRING: 2587 case arg_NUMBER: 2588 case arg_WINDOW: 2589 case arg_FRAME: 2590 case arg_COMMAND: 2591 case arg_SHELLCMD: 2592 case arg_KEYMAP: 2593 case arg_GRAVITY: 2594 case arg_VSCREEN: 2595 case arg_HOOK: 2596 case arg_VARIABLE: 2597 case arg_RAW: 2598 /* Do nothing */ 2599 break; 2600 default: 2601 warnx("unknown arg type %d\n", arg->type); 2602 break; 2603 } 2604 2605 free(arg); 2606} 2607 2608cmdret * 2609command(int interactive, char *data) 2610{ 2611 /* This static counter is used to exit from recursive alias calls. */ 2612 static int alias_recursive_depth = 0; 2613 cmdret *result = NULL; 2614 char *cmd, *rest; 2615 char *input; 2616 struct user_command *uc; 2617 int i; 2618 2619 if (data == NULL) 2620 return cmdret_new(RET_FAILURE, NULL); 2621 2622 /* get a writable copy for strtok() */ 2623 input = xstrdup(data); 2624 2625 cmd = input; 2626 /* skip beginning whitespace. */ 2627 while (*cmd && isspace((unsigned char) *cmd)) 2628 cmd++; 2629 rest = cmd; 2630 /* skip til we get to whitespace */ 2631 while (*rest && !isspace((unsigned char) *rest)) 2632 rest++; 2633 /* 2634 * mark that spot as the end of the command and make rest point to the 2635 * rest of the string. 2636 */ 2637 if (*rest) { 2638 *rest = 0; 2639 rest++; 2640 } 2641 PRINT_DEBUG(("cmd==%s rest==%s\n", cmd, rest ? rest : "NULL")); 2642 2643 /* Look for it in the aliases, first. */ 2644 for (i = 0; i < alias_list_last; i++) { 2645 if (strcmp(cmd, alias_list[i].name) != 0) 2646 continue; 2647 2648 struct sbuf *s; 2649 2650 /* 2651 * Append any arguments onto the end of the alias' 2652 * command. 2653 */ 2654 s = sbuf_new(0); 2655 sbuf_concat(s, alias_list[i].alias); 2656 if (rest != NULL && *rest) 2657 sbuf_printf_concat(s, " %s", rest); 2658 2659 alias_recursive_depth++; 2660 if (alias_recursive_depth >= MAX_ALIAS_RECURSIVE_DEPTH) 2661 result = cmdret_new(RET_FAILURE, 2662 "command: alias recursion has exceeded " 2663 "maximum depth"); 2664 else 2665 result = command(interactive, sbuf_get(s)); 2666 alias_recursive_depth--; 2667 2668 sbuf_free(s); 2669 goto done; 2670 } 2671 2672 /* If it wasn't an alias, maybe its a command. */ 2673 list_for_each_entry(uc, &user_commands, node) { 2674 if (strcmp(cmd, uc->name) != 0) 2675 continue; 2676 2677 struct sbuf *scur; 2678 struct cmdarg *acur; 2679 struct list_head *iter, *tmp; 2680 struct list_head head, args; 2681 int nargs = 0, raw = 0; 2682 2683 INIT_LIST_HEAD(&args); 2684 INIT_LIST_HEAD(&head); 2685 2686 /* 2687 * We need to tell parse_args about arg_REST and 2688 * arg_SHELLCMD. 2689 */ 2690 for (i = 0; i < uc->num_args; i++) 2691 if (uc->args[i].type == arg_REST || 2692 uc->args[i].type == arg_COMMAND || 2693 uc->args[i].type == arg_SHELLCMD || 2694 uc->args[i].type == arg_RAW) { 2695 raw = 1; 2696 nargs = i; 2697 break; 2698 } 2699 2700 /* Parse the arguments and call the function. */ 2701 result = parse_args(rest, &head, nargs, raw); 2702 if (result) 2703 goto free_lists; 2704 2705 /* Interactive commands prompt the user for missing args. */ 2706 if (interactive) 2707 result = fill_in_missing_args(uc, &head, &args, 2708 uc->name); 2709 else { 2710 int parsed_args; 2711 result = parsed_input_to_args(uc->num_args, 2712 uc->args, &head, &args, &parsed_args, 2713 uc->name); 2714 } 2715 2716 if (result == NULL) { 2717 if ((interactive && list_size(&args) < uc->i_required_args) || 2718 (!interactive && list_size(&args) < uc->ni_required_args)) { 2719 result = cmdret_new(RET_FAILURE, 2720 "not enough arguments."); 2721 goto free_lists; 2722 } else if (list_size(&head) > uc->num_args) { 2723 result = cmdret_new(RET_FAILURE, 2724 "command: too many arguments."); 2725 goto free_lists; 2726 } else { 2727 struct cmdarg **cmdargs = arg_array(&args); 2728 result = uc->func(interactive, cmdargs); 2729 free(cmdargs); 2730 } 2731 } 2732free_lists: 2733 /* Free the parsed strings */ 2734 list_for_each_safe_entry(scur, iter, tmp, &head, node) 2735 sbuf_free(scur); 2736 2737 /* Free the args */ 2738 list_for_each_safe_entry(acur, iter, tmp, &args, node) 2739 arg_free(acur); 2740 2741 goto done; 2742 } 2743 2744 result = cmdret_new(RET_FAILURE, MESSAGE_UNKNOWN_COMMAND, cmd); 2745 2746done: 2747 free(input); 2748 return result; 2749} 2750 2751cmdret * 2752cmd_colon(int interactive, struct cmdarg **args) 2753{ 2754 cmdret *result; 2755 char *input; 2756 2757 if (args[0] == NULL) 2758 input = get_input(MESSAGE_PROMPT_COMMAND, hist_COMMAND, 2759 colon_completions); 2760 else 2761 input = get_more_input(MESSAGE_PROMPT_COMMAND, ARG_STRING(0), 2762 hist_COMMAND, BASIC, colon_completions); 2763 2764 /* User aborted. */ 2765 if (input == NULL) 2766 return cmdret_new(RET_FAILURE, NULL); 2767 2768 result = command(1, input); 2769 free(input); 2770 return result; 2771} 2772 2773cmdret * 2774cmd_exec(int interactive, struct cmdarg **args) 2775{ 2776 spawn(ARG_STRING(0), current_frame(rp_current_vscreen)); 2777 return cmdret_new(RET_SUCCESS, NULL); 2778} 2779 2780cmdret * 2781cmd_execw(int interactive, struct cmdarg **args) 2782{ 2783 int status = -1; 2784 pid_t pid = spawn(ARG_STRING(0), current_frame(rp_current_vscreen)); 2785 if (waitpid(pid, &status, 0) == -1) 2786 perror("cmd_execw"); 2787 else 2788 status = WEXITSTATUS(status); 2789 return cmdret_new(status == 0? RET_SUCCESS: RET_FAILURE, NULL); 2790} 2791 2792cmdret * 2793cmd_execa(int interactive, struct cmdarg **args) 2794{ 2795 spawn(ARG_STRING(0), NULL); 2796 return cmdret_new(RET_SUCCESS, NULL); 2797} 2798 2799cmdret * 2800cmd_execf(int interactive, struct cmdarg **args) 2801{ 2802 /* 2803 * Tell spawn's shell to exec the command it finds, reusing the pid 2804 * that fork() returned so matching to its NET_WM_PID later works 2805 * properly. 2806 */ 2807 char *cmd = xsprintf("exec %s", ARG_STRING(1)); 2808 spawn(cmd, ARG(0, frame)); 2809 return cmdret_new(RET_SUCCESS, NULL); 2810} 2811 2812cmdret * 2813cmd_execv(int interactive, struct cmdarg **args) 2814{ 2815 rp_vscreen *vscreen; 2816 if (!(vscreen = find_vscreen(ARG_STRING(0)))) 2817 return cmdret_new(RET_FAILURE, NULL); 2818 vspawn(ARG_STRING(1), current_frame(vscreen), vscreen); 2819 return cmdret_new(RET_SUCCESS, NULL); 2820} 2821 2822int 2823spawn(char *cmd, rp_frame *frame) { return vspawn(cmd, frame, NULL); } 2824int 2825vspawn(char *cmd, rp_frame *frame, rp_vscreen *vscreen) 2826{ 2827 rp_child_info *child; 2828 int pid; 2829 2830 pid = fork(); 2831 if (pid == 0) { 2832 /* 2833 * Some process setup to make sure the spawned process runs in 2834 * its own session. 2835 */ 2836 putenv(rp_current_screen->display_string); 2837 if (setsid() == -1) 2838 { 2839 int ctty; 2840 2841 ctty = open("/dev/tty", O_RDONLY); 2842 if (ctty != -1) { 2843 ioctl(ctty, TIOCNOTTY); 2844 close(ctty); 2845 } 2846 2847 setpgid(0, 0); 2848 } 2849 2850 execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); 2851 _exit(1); 2852 } 2853 2854 /* wait((int *) 0); */ 2855 PRINT_DEBUG(("spawned %s, pid %d, frame %d, vscreen %d, screen %d\n", 2856 cmd, pid, frame ? frame->number : -1, 2857 (vscreen? vscreen: rp_current_vscreen)->number, 2858 rp_current_screen->number)); 2859 2860 /* Add this child process to our list. */ 2861 child = xmalloc(sizeof(rp_child_info)); 2862 child->cmd = xstrdup(cmd); 2863 child->pid = pid; 2864 child->terminated = 0; 2865 child->frame = frame; 2866 child->vscreen = vscreen? vscreen: rp_current_vscreen; 2867 child->screen = rp_current_screen; 2868 child->window_mapped = 0; 2869 2870 list_add(&child->node, &rp_children); 2871 2872 return pid; 2873} 2874 2875cmdret * 2876cmd_quit(int interactive, struct cmdarg **args) 2877{ 2878 kill_signalled = 1; 2879 return cmdret_new(RET_SUCCESS, NULL); 2880} 2881 2882/* Assign a new number to a window ala screen's number command. */ 2883cmdret * 2884cmd_number(int interactive, struct cmdarg **args) 2885{ 2886 int old_number, new_number; 2887 rp_window_elem *other_win, *win; 2888 2889 /* Gather the args. */ 2890 new_number = ARG(0, number); 2891 if (args[1]) 2892 win = vscreen_find_window_by_number(rp_current_vscreen, 2893 ARG(1, number)); 2894 else 2895 win = vscreen_find_window(&rp_current_vscreen->mapped_windows, 2896 current_window()); 2897 2898 /* Make the switch. */ 2899 if (new_number >= 0 && win) { 2900 /* Find other window with same number and give it old number. */ 2901 other_win = vscreen_find_window_by_number(rp_current_vscreen, 2902 new_number); 2903 if (other_win != NULL) { 2904 old_number = win->number; 2905 other_win->number = old_number; 2906 2907 /* Resort the window in the list */ 2908 vscreen_resort_window(rp_current_vscreen, other_win); 2909 } else { 2910 numset_release(rp_current_vscreen->numset, win->number); 2911 } 2912 2913 win->number = new_number; 2914 numset_add_num(rp_current_vscreen->numset, new_number); 2915 2916 /* resort the the window in the list */ 2917 vscreen_resort_window(rp_current_vscreen, win); 2918 2919 /* Update the window list. */ 2920 update_window_names(win->win->vscreen->screen, 2921 defaults.window_fmt); 2922 } 2923 2924 return cmdret_new(RET_SUCCESS, NULL); 2925} 2926 2927/* Toggle the display of the program bar */ 2928cmdret * 2929cmd_windows(int interactive, struct cmdarg **args) 2930{ 2931 struct sbuf *window_list = NULL; 2932 int dummy; 2933 char *fmt; 2934 cmdret *ret; 2935 2936 if (args[0] == NULL) 2937 fmt = defaults.window_fmt; 2938 else 2939 fmt = ARG_STRING(0); 2940 2941 if (interactive) { 2942 rp_screen *s; 2943 s = rp_current_screen; 2944 ret = cmdret_new(RET_SUCCESS, NULL); 2945 if (defaults.bar_timeout == 0 && s->bar_is_raised) { 2946 hide_bar(s, 0); 2947 return ret; 2948 } 2949 show_bar(s, fmt); 2950 } else { 2951 window_list = sbuf_new(0); 2952 get_window_list(fmt, "\n", window_list, &dummy, &dummy); 2953 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(window_list)); 2954 sbuf_free(window_list); 2955 } 2956 return ret; 2957} 2958 2959cmdret * 2960cmd_abort(int interactive, struct cmdarg **args) 2961{ 2962 return cmdret_new(RET_SUCCESS, NULL); 2963} 2964 2965/* Redisplay the current window by sending 2 resize events. */ 2966cmdret * 2967cmd_redisplay(int interactive, struct cmdarg **args) 2968{ 2969 force_maximize(current_window()); 2970 return cmdret_new(RET_SUCCESS, NULL); 2971} 2972 2973/* Reassign the prefix key. */ 2974cmdret * 2975cmd_escape(int interactive, struct cmdarg **args) 2976{ 2977 struct rp_key *key; 2978 rp_action *action; 2979 rp_keymap *map, *top; 2980 2981 top = find_keymap(defaults.top_kmap); 2982 map = find_keymap(ROOT_KEYMAP); 2983 key = ARG(0, key); 2984 2985 /* Update the "other" keybinding */ 2986 action = find_keybinding(prefix_key.sym, prefix_key.state, map); 2987 if (action != NULL && !strcmp(action->data, "other")) { 2988 action->key = key->sym; 2989 action->state = key->state; 2990 } 2991 2992 /* Update the "meta" keybinding */ 2993 action = find_keybinding(prefix_key.sym, 0, map); 2994 if (action != NULL && !strcmp(action->data, "meta")) { 2995 action->key = key->sym; 2996 if (key->state != 0) 2997 action->state = 0; 2998 else 2999 action->state = RP_CONTROL_MASK; 3000 } 3001 3002 /* Remove the grab on the current prefix key */ 3003 ungrab_keys_all_wins(); 3004 3005 action = find_keybinding(prefix_key.sym, prefix_key.state, top); 3006 if (action != NULL && !strcmp(action->data, "readkey " ROOT_KEYMAP)) { 3007 action->key = key->sym; 3008 action->state = key->state; 3009 } 3010 3011 /* Add the grab for the new prefix key */ 3012 grab_keys_all_wins(); 3013 3014 /* Finally, keep track of the current prefix. */ 3015 prefix_key.sym = key->sym; 3016 prefix_key.state = key->state; 3017 3018 return cmdret_new(RET_SUCCESS, NULL); 3019} 3020 3021/* User accessible call to display the passed in string. */ 3022cmdret * 3023cmd_echo(int interactive, struct cmdarg **args) 3024{ 3025 marked_message_printf(0, 0, "%s", ARG_STRING(0)); 3026 3027 return cmdret_new(RET_SUCCESS, NULL); 3028} 3029 3030 3031static cmdret * 3032read_split(char *str, int max, int *p) 3033{ 3034 int a, b; 3035 3036 if (sscanf(str, "%d/%d", &a, &b) == 2) { 3037 *p = (int) (max * (float) (a) / (float) (b)); 3038 } else if (sscanf(str, "%d", p) == 1) { 3039 if (*p < 0) 3040 *p = max + *p; 3041 } else { 3042 /* Failed to read input. */ 3043 return cmdret_new(RET_FAILURE, "bad split '%s'", str); 3044 } 3045 3046 return NULL; 3047} 3048 3049cmdret * 3050cmd_vsplit(int interactive, struct cmdarg **args) 3051{ 3052 cmdret *ret; 3053 rp_frame *frame; 3054 int pixels; 3055 3056 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 3057 frame = current_frame(rp_current_vscreen); 3058 3059 /* Default to dividing the frame in half. */ 3060 if (args[0] == NULL) 3061 pixels = frame->height / 2; 3062 else { 3063 ret = read_split(ARG_STRING(0), frame->height, &pixels); 3064 if (ret) 3065 return ret; 3066 } 3067 3068 if (pixels > 0) 3069 h_split_frame(frame, pixels); 3070 else 3071 return cmdret_new(RET_FAILURE, "vsplit: %s", 3072 invalid_negative_arg); 3073 3074 return cmdret_new(RET_SUCCESS, NULL); 3075} 3076 3077cmdret * 3078cmd_hsplit(int interactive, struct cmdarg **args) 3079{ 3080 cmdret *ret; 3081 rp_frame *frame; 3082 int pixels; 3083 3084 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 3085 frame = current_frame(rp_current_vscreen); 3086 3087 /* Default to dividing the frame in half. */ 3088 if (args[0] == NULL) 3089 pixels = frame->width / 2; 3090 else { 3091 ret = read_split(ARG_STRING(0), frame->width, &pixels); 3092 if (ret) 3093 return ret; 3094 } 3095 3096 if (pixels > 0) 3097 v_split_frame(frame, pixels); 3098 else 3099 return cmdret_new(RET_FAILURE, "hsplit: %s", 3100 invalid_negative_arg); 3101 3102 return cmdret_new(RET_SUCCESS, NULL); 3103} 3104 3105cmdret * 3106cmd_only(int interactive, struct cmdarg **args) 3107{ 3108 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 3109 remove_all_splits(); 3110 maximize(current_window()); 3111 3112 return cmdret_new(RET_SUCCESS, NULL); 3113} 3114 3115cmdret * 3116cmd_remove(int interactive, struct cmdarg **args) 3117{ 3118 rp_frame *frame; 3119 3120 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 3121 3122 if (num_frames(rp_current_vscreen) <= 1) 3123 return cmdret_new(RET_FAILURE, 3124 "remove: cannot remove only frame"); 3125 3126 frame = find_frame_next(current_frame(rp_current_vscreen)); 3127 if (frame) { 3128 remove_frame(current_frame(rp_current_vscreen)); 3129 set_active_frame(frame, 0); 3130 show_frame_indicator(0); 3131 } 3132 3133 return cmdret_new(RET_SUCCESS, NULL); 3134} 3135 3136cmdret * 3137cmd_shrink(int interactive, struct cmdarg **args) 3138{ 3139 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 3140 resize_shrink_to_window(current_frame(rp_current_vscreen)); 3141 return cmdret_new(RET_SUCCESS, NULL); 3142} 3143 3144typedef struct resize_binding resize_binding; 3145 3146struct resize_binding { 3147 struct rp_key key; 3148 enum resize_action { 3149 RESIZE_UNKNOWN = 0, 3150 RESIZE_VGROW, 3151 RESIZE_VSHRINK, 3152 RESIZE_HGROW, 3153 RESIZE_HSHRINK, 3154 RESIZE_TO_WINDOW, 3155 RESIZE_ABORT, 3156 RESIZE_END 3157 } action; 3158}; 3159 3160static resize_binding resize_bindings[] = { 3161 { { INPUT_ABORT_KEY, INPUT_ABORT_MODIFIER }, RESIZE_ABORT}, 3162 { { RESIZE_VGROW_KEY, RESIZE_VGROW_MODIFIER }, RESIZE_VGROW}, 3163 { { RESIZE_VSHRINK_KEY, RESIZE_VSHRINK_MODIFIER }, RESIZE_VSHRINK}, 3164 { { RESIZE_HGROW_KEY, RESIZE_HGROW_MODIFIER }, RESIZE_HGROW}, 3165 { { RESIZE_HSHRINK_KEY, RESIZE_HSHRINK_MODIFIER }, RESIZE_HSHRINK}, 3166 { { RESIZE_SHRINK_TO_WINDOW_KEY, RESIZE_SHRINK_TO_WINDOW_MODIFIER }, RESIZE_TO_WINDOW}, 3167 { { RESIZE_END_KEY, RESIZE_END_MODIFIER }, RESIZE_END}, 3168 3169 /* 3170 * Some more default keys (after the values from conf.h, so that they have lower 3171 * priority): first the arrow keys: 3172 */ 3173 { {XK_Escape, 0 }, RESIZE_ABORT}, 3174 { {XK_Down, 0 }, RESIZE_VGROW}, 3175 { {XK_Up, 0 }, RESIZE_VSHRINK}, 3176 { {XK_Right, 0 }, RESIZE_HGROW}, 3177 { {XK_Left, 0 }, RESIZE_HSHRINK}, 3178 3179 /* some vi-like bindings: */ 3180 { {XK_j, 0 }, RESIZE_VGROW}, 3181 { {XK_k, 0 }, RESIZE_VSHRINK}, 3182 { {XK_l, 0 }, RESIZE_HGROW}, 3183 { {XK_h, 0 }, RESIZE_HSHRINK}, 3184 3185 { {0, 0 }, RESIZE_UNKNOWN}, 3186}; 3187 3188cmdret * 3189cmd_resize(int interactive, struct cmdarg **args) 3190{ 3191 rp_screen *s = rp_current_screen; 3192 3193 /* 3194 * If the user calls resize with arguments, treat it like the 3195 * non-interactive version. 3196 */ 3197 if (interactive && args[0] == NULL) { 3198 char buffer[513]; 3199 unsigned int mod; 3200 KeySym c; 3201 struct list_head *bk; 3202 3203 /* 3204 * If we haven't got at least 2 frames, there isn't anything to 3205 * scale. 3206 */ 3207 if (num_frames(rp_current_vscreen) < 2) 3208 return cmdret_new(RET_FAILURE, NULL); 3209 3210 /* Save the frameset in case the user aborts. */ 3211 bk = vscreen_copy_frameset(rp_current_vscreen); 3212 3213 /* Get ready to read keys. */ 3214 grab_rat(); 3215 XGrabKeyboard(dpy, s->key_window, False, GrabModeAsync, 3216 GrabModeAsync, CurrentTime); 3217 3218 while (1) { 3219 struct resize_binding *binding; 3220 3221 show_frame_message(defaults.resize_fmt); 3222 read_key(&c, &mod, buffer, sizeof(buffer)); 3223 3224 /* Convert the mask to be compatible with us. */ 3225 mod = x11_mask_to_rp_mask(mod); 3226 3227 for (binding = resize_bindings; binding->action; binding++) { 3228 if (c == binding->key.sym && 3229 mod == binding->key.state) 3230 break; 3231 } 3232 3233 if (binding->action == RESIZE_VGROW) 3234 resize_frame_vertically( 3235 current_frame(rp_current_vscreen), 3236 defaults.frame_resize_unit); 3237 else if (binding->action == RESIZE_VSHRINK) 3238 resize_frame_vertically( 3239 current_frame(rp_current_vscreen), 3240 -defaults.frame_resize_unit); 3241 else if (binding->action == RESIZE_HGROW) 3242 resize_frame_horizontally( 3243 current_frame(rp_current_vscreen), 3244 defaults.frame_resize_unit); 3245 else if (binding->action == RESIZE_HSHRINK) 3246 resize_frame_horizontally( 3247 current_frame(rp_current_vscreen), 3248 -defaults.frame_resize_unit); 3249 else if (binding->action == RESIZE_TO_WINDOW) 3250 resize_shrink_to_window( 3251 current_frame(rp_current_vscreen)); 3252 else if (binding->action == RESIZE_ABORT) { 3253 rp_frame *cur; 3254 3255 vscreen_restore_frameset(rp_current_vscreen, bk); 3256 list_for_each_entry(cur, 3257 &(rp_current_vscreen->frames), node) { 3258 maximize_all_windows_in_frame(cur); 3259 } 3260 break; 3261 } else if (binding->action == RESIZE_END) { 3262 frameset_free(bk); 3263 break; 3264 } 3265 } 3266 3267 /* It is our responsibility to free this. */ 3268 free(bk); 3269 3270 hide_frame_indicator(); 3271 ungrab_rat(); 3272 XUngrabKeyboard(dpy, CurrentTime); 3273 } else { 3274 if (args[0] && args[1]) { 3275 resize_frame_horizontally( 3276 current_frame(rp_current_vscreen), 3277 ARG(0, number)); 3278 resize_frame_vertically( 3279 current_frame(rp_current_vscreen), 3280 ARG(1, number)); 3281 } else 3282 return cmdret_new(RET_FAILURE, 3283 "resize: two numeric arguments required"); 3284 } 3285 3286 return cmdret_new(RET_SUCCESS, NULL); 3287} 3288 3289static cmdret * 3290set_resizeunit(struct cmdarg **args) 3291{ 3292 if (args[0] == NULL) 3293 return cmdret_new(RET_SUCCESS, "%d", 3294 defaults.frame_resize_unit); 3295 3296 if (ARG(0, number) >= 0) 3297 defaults.frame_resize_unit = ARG(0, number); 3298 else 3299 return cmdret_new(RET_FAILURE, "set resizeunit: %s", 3300 invalid_negative_arg); 3301 3302 return cmdret_new(RET_SUCCESS, NULL); 3303} 3304 3305/* banish the rat pointer */ 3306cmdret * 3307cmd_banish(int interactive, struct cmdarg **args) 3308{ 3309 rp_screen *s; 3310 3311 s = rp_current_screen; 3312 3313 XWarpPointer(dpy, None, s->root, 0, 0, 0, 0, s->left + s->width - 2, 3314 s->top + s->height - 2); 3315 3316 return cmdret_new(RET_SUCCESS, NULL); 3317} 3318 3319cmdret * 3320cmd_banishrel(int interactive, struct cmdarg **args) 3321{ 3322 rp_screen *s = rp_current_screen; 3323 rp_window *w = current_window(); 3324 rp_frame *f = current_frame(rp_current_vscreen); 3325 3326 if (w) 3327 XWarpPointer(dpy, None, w->w, 0, 0, 0, 0, w->x + w->width - 2, 3328 w->y + w->height - 2); 3329 else 3330 XWarpPointer(dpy, None, s->root, 0, 0, 0, 0, f->x + f->width, 3331 f->y + f->height); 3332 3333 return cmdret_new(RET_SUCCESS, NULL); 3334} 3335 3336cmdret * 3337cmd_ratinfo(int interactive, struct cmdarg **args) 3338{ 3339 rp_screen *s; 3340 Window root_win, child_win; 3341 int mouse_x, mouse_y, root_x, root_y; 3342 unsigned int mask; 3343 3344 s = rp_current_screen; 3345 XQueryPointer(dpy, s->root, &root_win, &child_win, &mouse_x, &mouse_y, 3346 &root_x, &root_y, &mask); 3347 3348 return cmdret_new(RET_SUCCESS, "%d %d", mouse_x, mouse_y); 3349} 3350 3351cmdret * 3352cmd_ratrelinfo(int interactive, struct cmdarg **args) 3353{ 3354 rp_screen *s; 3355 rp_window *rpw; 3356 rp_frame *f; 3357 Window root_win, child_win; 3358 int mouse_x, mouse_y, root_x, root_y; 3359 unsigned int mask; 3360 3361 s = rp_current_screen; 3362 rpw = current_window(); 3363 f = current_frame(rp_current_vscreen); 3364 3365 if (rpw) 3366 XQueryPointer(dpy, rpw->w, &root_win, &child_win, &mouse_x, 3367 &mouse_y, &root_x, &root_y, &mask); 3368 else { 3369 XQueryPointer(dpy, s->root, &root_win, &child_win, &mouse_x, 3370 &mouse_y, &root_x, &root_y, &mask); 3371 root_x -= f->x; 3372 root_y -= f->y; 3373 } 3374 3375 return cmdret_new(RET_SUCCESS, "%d %d", root_x, root_y); 3376} 3377 3378cmdret * 3379cmd_ratwarp(int interactive, struct cmdarg **args) 3380{ 3381 rp_screen *s; 3382 3383 s = rp_current_screen; 3384 XWarpPointer(dpy, None, s->root, 0, 0, 0, 0, ARG(0, number), 3385 ARG(1, number)); 3386 return cmdret_new(RET_SUCCESS, NULL); 3387} 3388 3389cmdret * 3390cmd_ratrelwarp(int interactive, struct cmdarg **args) 3391{ 3392 XWarpPointer(dpy, None, None, 0, 0, 0, 0, ARG(0, number), 3393 ARG(1, number)); 3394 return cmdret_new(RET_SUCCESS, NULL); 3395} 3396 3397cmdret * 3398cmd_ratclick(int interactive, struct cmdarg **args) 3399{ 3400 int button = 1; 3401 3402 if (args[0]) { 3403 button = ARG(0, number); 3404 if (button < 1 || button > 3) 3405 return cmdret_new(RET_SUCCESS, 3406 "ratclick: invalid argument"); 3407 } 3408 3409 XTestFakeButtonEvent(dpy, button, True, CurrentTime); 3410 XTestFakeButtonEvent(dpy, button, False, CurrentTime); 3411 return cmdret_new(RET_SUCCESS, NULL); 3412} 3413 3414cmdret * 3415cmd_rathold(int interactive, struct cmdarg **args) 3416{ 3417 int button = 1; 3418 3419 if (args[1]) { 3420 button = ARG(1, number); 3421 if (button < 1 || button > 3) 3422 return cmdret_new(RET_SUCCESS, 3423 "ratclick: invalid argument"); 3424 } 3425 3426 if (!strcmp(ARG_STRING(0), "down")) 3427 XTestFakeButtonEvent(dpy, button, True, CurrentTime); 3428 else if (!strcmp(ARG_STRING(0), "up")) 3429 XTestFakeButtonEvent(dpy, button, False, CurrentTime); 3430 else 3431 return cmdret_new(RET_FAILURE, 3432 "rathold: '%s' invalid argument", ARG_STRING(0)); 3433 3434 return cmdret_new(RET_SUCCESS, NULL); 3435} 3436 3437cmdret * 3438cmd_curframe(int interactive, struct cmdarg **args) 3439{ 3440 if (interactive) { 3441 show_frame_indicator(1); 3442 return cmdret_new(RET_SUCCESS, NULL); 3443 } 3444 3445 return cmdret_new(RET_SUCCESS, "%d", 3446 current_frame(rp_current_vscreen)->number); 3447} 3448 3449cmdret * 3450cmd_help(int interactive, struct cmdarg **args) 3451{ 3452 rp_keymap *map; 3453 3454 if (args[0]) 3455 map = ARG(0, keymap); 3456 else 3457 map = find_keymap(ROOT_KEYMAP); 3458 3459 if (interactive) { 3460 rp_screen *s = rp_current_screen; 3461 int i, old_i; 3462 int x = 20; 3463 int y = 20; 3464 int header_offset; 3465 int width, max_width = 0; 3466 /* 1 if we are drawing keys, 0 if we are drawing commands */ 3467 int drawing_keys = 1; 3468 char *keysym_name; 3469 3470 /* Switch to the default colormap. */ 3471 if (current_window()) 3472 XUninstallColormap(dpy, current_window()->colormap); 3473 XInstallColormap(dpy, s->def_cmap); 3474 3475 XMapRaised(dpy, s->help_window); 3476 3477 rp_draw_string(s, s->help_window, STYLE_NORMAL, 3478 x, y + FONT_ASCENT(s), PROGNAME " key bindings", -1, NULL, 3479 NULL); 3480 3481 y += FONT_HEIGHT(s) * 2; 3482 3483 /* Only print the "Command key" for the root keymap */ 3484 if (map == find_keymap(ROOT_KEYMAP)) { 3485 rp_draw_string(s, s->help_window, STYLE_NORMAL, 3486 x, y + FONT_ASCENT(s), 3487 "Command key: ", -1, NULL, NULL); 3488 3489 keysym_name = keysym_to_string(prefix_key.sym, 3490 prefix_key.state); 3491 rp_draw_string(s, s->help_window, STYLE_NORMAL, 3492 x + rp_text_width(s, "Command key: ", -1, NULL), 3493 y + FONT_ASCENT(s), 3494 keysym_name, -1, NULL, NULL); 3495 free(keysym_name); 3496 3497 y += FONT_HEIGHT(s) * 2; 3498 } 3499 header_offset = y; 3500 3501 i = old_i = 0; 3502 while (i < map->actions_last && old_i < map->actions_last) { 3503 if (drawing_keys) { 3504 keysym_name = keysym_to_string(map->actions[i].key, 3505 map->actions[i].state); 3506 3507 rp_draw_string(s, s->help_window, STYLE_NORMAL, 3508 x, y + FONT_ASCENT(s), 3509 keysym_name, -1, NULL, NULL); 3510 3511 width = rp_text_width(s, keysym_name, -1, NULL); 3512 if (width > max_width) 3513 max_width = width; 3514 3515 free(keysym_name); 3516 } else { 3517 rp_draw_string(s, s->help_window, STYLE_NORMAL, 3518 x, y + FONT_ASCENT(s), 3519 map->actions[i].data, -1, NULL, NULL); 3520 3521 width = rp_text_width(s, map->actions[i].data, 3522 -1, NULL); 3523 if (width > max_width) 3524 max_width = width; 3525 } 3526 3527 y += FONT_HEIGHT(s); 3528 /* Make sure the next line fits entirely within the window. */ 3529 if (y + FONT_HEIGHT(s) >= (s->top + s->height)) { 3530 if (drawing_keys) { 3531 x += max_width + 10; 3532 drawing_keys = 0; 3533 i = old_i; 3534 } else { 3535 x += max_width + 20; 3536 drawing_keys = 1; 3537 i++; 3538 old_i = i; 3539 } 3540 3541 max_width = 0; 3542 y = header_offset; 3543 } else { 3544 i++; 3545 if (i == map->actions_last && drawing_keys) { 3546 x += max_width + 10; 3547 drawing_keys = 0; 3548 y = header_offset; 3549 i = old_i; 3550 max_width = 0; 3551 } 3552 } 3553 } 3554 3555 read_any_key(); 3556 XUnmapWindow(dpy, s->help_window); 3557 3558 /* Possibly restore colormap. */ 3559 if (current_window()) { 3560 XUninstallColormap(dpy, s->def_cmap); 3561 XInstallColormap(dpy, current_window()->colormap); 3562 } 3563 /* The help window overlaps the bar, so redraw it. */ 3564 if (rp_current_screen->bar_is_raised) 3565 redraw_last_message(); 3566 3567 return cmdret_new(RET_SUCCESS, NULL); 3568 } else { 3569 struct sbuf *help_list; 3570 char *keysym_name; 3571 int i; 3572 cmdret *ret; 3573 3574 help_list = sbuf_new(0); 3575 3576 for (i = 0; i < map->actions_last; i++) { 3577 keysym_name = keysym_to_string(map->actions[i].key, 3578 map->actions[i].state); 3579 sbuf_concat(help_list, keysym_name); 3580 free(keysym_name); 3581 sbuf_concat(help_list, " "); 3582 sbuf_concat(help_list, map->actions[i].data); 3583 if (i < map->actions_last - 1) 3584 sbuf_concat(help_list, "\n"); 3585 } 3586 3587 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(help_list)); 3588 sbuf_free(help_list); 3589 return ret; 3590 } 3591 3592 return cmdret_new(RET_SUCCESS, NULL); 3593} 3594 3595cmdret * 3596set_rudeness(struct cmdarg **args) 3597{ 3598 int num; 3599 3600 if (args[0] == NULL) 3601 return cmdret_new(RET_SUCCESS, "%d", 3602 rp_honour_transient_raise | 3603 (rp_honour_normal_raise << 1) | 3604 (rp_honour_transient_map << 2) | 3605 (rp_honour_normal_map << 3) | 3606 (rp_honour_vscreen_switch << 4)); 3607 3608 num = ARG(0, number); 3609 if (num < 0 || num > 31) 3610 return cmdret_new(RET_FAILURE, "rudeness: invalid level '%s'", 3611 ARG_STRING(0)); 3612 3613 rp_honour_transient_raise = num & 1 ? 1 : 0; 3614 rp_honour_normal_raise = num & 2 ? 1 : 0; 3615 rp_honour_transient_map = num & 4 ? 1 : 0; 3616 rp_honour_normal_map = num & 8 ? 1 : 0; 3617 rp_honour_vscreen_switch = num & 16 ? 1 : 0; 3618 3619 return cmdret_new(RET_SUCCESS, NULL); 3620} 3621 3622char * 3623wingravity_to_string(int g) 3624{ 3625 switch (g) { 3626 case NorthWestGravity: 3627 return "nw"; 3628 case WestGravity: 3629 return "w"; 3630 case SouthWestGravity: 3631 return "sw"; 3632 case NorthGravity: 3633 return "n"; 3634 case CenterGravity: 3635 return "c"; 3636 case SouthGravity: 3637 return "s"; 3638 case NorthEastGravity: 3639 return "ne"; 3640 case EastGravity: 3641 return "e"; 3642 case SouthEastGravity: 3643 return "se"; 3644 } 3645 3646 PRINT_DEBUG(("Unknown gravity!\n")); 3647 return "Unknown"; 3648} 3649 3650cmdret * 3651cmd_gravity(int interactive, struct cmdarg **args) 3652{ 3653 int gravity; 3654 rp_window *win; 3655 3656 win = current_window(); 3657 if (!win) 3658 return cmdret_new(RET_FAILURE, NULL); 3659 3660 if (args[0] == NULL) 3661 return cmdret_new(RET_SUCCESS, "%s", 3662 wingravity_to_string(win->gravity)); 3663 3664 if ((gravity = parse_wingravity(ARG_STRING(0))) < 0) 3665 return cmdret_new(RET_FAILURE, "gravity: unknown gravity"); 3666 else { 3667 win->gravity = gravity; 3668 maximize(win); 3669 } 3670 3671 return cmdret_new(RET_SUCCESS, NULL); 3672} 3673 3674static cmdret * 3675set_wingravity(struct cmdarg **args) 3676{ 3677 if (args[0] == NULL) 3678 return cmdret_new(RET_SUCCESS, "%s", 3679 wingravity_to_string(defaults.win_gravity)); 3680 3681 defaults.win_gravity = ARG(0, gravity); 3682 3683 return cmdret_new(RET_SUCCESS, NULL); 3684} 3685 3686static cmdret * 3687set_transgravity(struct cmdarg **args) 3688{ 3689 if (args[0] == NULL) 3690 return cmdret_new(RET_SUCCESS, "%s", 3691 wingravity_to_string(defaults.trans_gravity)); 3692 3693 defaults.trans_gravity = ARG(0, gravity); 3694 3695 return cmdret_new(RET_SUCCESS, NULL); 3696} 3697 3698static cmdret * 3699set_maxsizegravity(struct cmdarg **args) 3700{ 3701 if (args[0] == NULL) 3702 return cmdret_new(RET_SUCCESS, "%s", 3703 wingravity_to_string(defaults.maxsize_gravity)); 3704 3705 defaults.maxsize_gravity = ARG(0, gravity); 3706 3707 return cmdret_new(RET_SUCCESS, NULL); 3708} 3709 3710static cmdret * 3711set_msgwait(struct cmdarg **args) 3712{ 3713 if (args[0] == NULL) 3714 return cmdret_new(RET_SUCCESS, "%d", defaults.bar_timeout); 3715 3716 if (ARG(0, number) < 0) 3717 return cmdret_new(RET_FAILURE, "msgwait: %s", 3718 invalid_negative_arg); 3719 else 3720 defaults.bar_timeout = ARG(0, number); 3721 3722 return cmdret_new(RET_SUCCESS, NULL); 3723} 3724 3725static cmdret * 3726set_framemsgwait(struct cmdarg **args) 3727{ 3728 if (args[0] == NULL) 3729 return cmdret_new(RET_SUCCESS, "%d", 3730 defaults.frame_indicator_timeout); 3731 3732 if (ARG(0, number) < -1) 3733 return cmdret_new(RET_FAILURE, "framemsgwait: %s", 3734 invalid_negative_arg); 3735 else 3736 defaults.frame_indicator_timeout = ARG(0, number); 3737 3738 return cmdret_new(RET_SUCCESS, NULL); 3739} 3740 3741static cmdret * 3742set_bargravity(struct cmdarg **args) 3743{ 3744 rp_screen *s; 3745 3746 if (args[0] == NULL) 3747 return cmdret_new(RET_SUCCESS, "%s", 3748 wingravity_to_string(defaults.bar_location)); 3749 3750 mark_edge_frames(); 3751 3752 defaults.bar_location = ARG(0, gravity); 3753 3754 list_for_each_entry(s, &rp_screens, node) { 3755 screen_update_workarea(s); 3756 screen_update_frames(s); 3757 } 3758 3759 return cmdret_new(RET_SUCCESS, NULL); 3760} 3761 3762static void 3763update_gc(rp_screen * s) 3764{ 3765 XGCValues gcv; 3766 3767 gcv.foreground = rp_glob_screen.fgcolor; 3768 gcv.background = rp_glob_screen.bgcolor; 3769 gcv.function = GXcopy; 3770 gcv.line_width = 1; 3771 gcv.subwindow_mode = IncludeInferiors; 3772 XFreeGC(dpy, s->normal_gc); 3773 s->normal_gc = XCreateGC(dpy, s->root, 3774 GCForeground | GCBackground | GCFunction | GCLineWidth | 3775 GCSubwindowMode, &gcv); 3776 gcv.foreground = rp_glob_screen.bgcolor; 3777 gcv.background = rp_glob_screen.fgcolor; 3778 XFreeGC(dpy, s->inverse_gc); 3779 s->inverse_gc = XCreateGC(dpy, s->root, 3780 GCForeground | GCBackground | GCFunction | GCLineWidth | 3781 GCSubwindowMode, &gcv); 3782} 3783 3784static cmdret * 3785set_historysize(struct cmdarg **args) 3786{ 3787 if (args[0] == NULL) 3788 return cmdret_new(RET_SUCCESS, "%d", defaults.history_size); 3789 3790 if (ARG(0, number) < 0) 3791 return cmdret_new(RET_FAILURE, "set historysize: %s", 3792 invalid_negative_arg); 3793 3794 defaults.history_size = ARG(0, number); 3795 return cmdret_new(RET_SUCCESS, NULL); 3796} 3797 3798static cmdret * 3799set_font(struct cmdarg **args) 3800{ 3801 XftFont *font; 3802 rp_screen *s; 3803 3804 if (args[0] == NULL) 3805 return cmdret_new(RET_SUCCESS, "%s", defaults.font_string); 3806 3807 mark_edge_frames(); 3808 3809 list_for_each_entry(s, &rp_screens, node) { 3810 font = XftFontOpenName(dpy, s->screen_num, ARG_STRING(0)); 3811 if (font == NULL) 3812 return cmdret_new(RET_FAILURE, "set font: unknown font"); 3813 3814 XftFontClose(dpy, s->xft_font); 3815 s->xft_font = font; 3816 } 3817 3818 free(defaults.font_string); 3819 3820 defaults.font_string = xstrdup(ARG_STRING(0)); 3821 3822 list_for_each_entry(s, &rp_screens, node) { 3823 screen_update_frames(s); 3824 } 3825 3826 return cmdret_new(RET_SUCCESS, NULL); 3827} 3828 3829static cmdret * 3830set_padding(struct cmdarg **args) 3831{ 3832 rp_screen *s; 3833 int l, t, r, b; 3834 3835 if (args[0] == NULL) 3836 return cmdret_new(RET_SUCCESS, "%d %d %d %d", 3837 defaults.padding_left, 3838 defaults.padding_top, 3839 defaults.padding_right, 3840 defaults.padding_bottom); 3841 3842 l = ARG(0, number); 3843 t = ARG(1, number); 3844 r = ARG(2, number); 3845 b = ARG(3, number); 3846 3847 if (l < 0 || t < 0 || r < 0 || b < 0) 3848 return cmdret_new(RET_FAILURE, "set padding: %s", 3849 invalid_negative_arg); 3850 3851 mark_edge_frames(); 3852 3853 defaults.padding_left = l; 3854 defaults.padding_right = r; 3855 defaults.padding_top = t; 3856 defaults.padding_bottom = b; 3857 3858 list_for_each_entry(s, &rp_screens, node) { 3859 screen_update_workarea(s); 3860 screen_update_frames(s); 3861 } 3862 3863 return cmdret_new(RET_SUCCESS, NULL); 3864} 3865 3866static cmdret * 3867set_border(struct cmdarg **args) 3868{ 3869 rp_screen *s; 3870 3871 if (args[0] == NULL) 3872 return cmdret_new(RET_SUCCESS, "%d", 3873 defaults.window_border_width); 3874 3875 if (ARG(0, number) < 0) 3876 return cmdret_new(RET_FAILURE, "set border: %s", 3877 invalid_negative_arg); 3878 3879 mark_edge_frames(); 3880 3881 defaults.window_border_width = ARG(0, number); 3882 3883 list_for_each_entry(s, &rp_screens, node) { 3884 screen_update_frames(s); 3885 } 3886 3887 return cmdret_new(RET_SUCCESS, NULL); 3888} 3889 3890static cmdret * 3891set_onlyborder(struct cmdarg **args) 3892{ 3893 rp_screen *s; 3894 3895 if (args[0] == NULL) 3896 return cmdret_new(RET_SUCCESS, "%d", defaults.only_border); 3897 3898 if (ARG(0, number) != 0 && ARG(0, number) != 1) 3899 return cmdret_new(RET_FAILURE, "set onlyborder: invalid argument"); 3900 3901 mark_edge_frames(); 3902 3903 defaults.only_border = ARG(0, number); 3904 3905 list_for_each_entry(s, &rp_screens, node) { 3906 screen_update_frames(s); 3907 } 3908 3909 return cmdret_new(RET_SUCCESS, NULL); 3910} 3911 3912static cmdret * 3913set_barborder(struct cmdarg **args) 3914{ 3915 rp_screen *s; 3916 3917 if (args[0] == NULL) 3918 return cmdret_new(RET_SUCCESS, "%d", defaults.bar_border_width); 3919 3920 if (ARG(0, number) < 0) 3921 return cmdret_new(RET_FAILURE, "set barborder: %s", 3922 invalid_negative_arg); 3923 3924 mark_edge_frames(); 3925 3926 defaults.bar_border_width = ARG(0, number); 3927 3928 /* Update the frame and bar windows. */ 3929 list_for_each_entry(s, &rp_screens, node) { 3930 XSetWindowBorderWidth(dpy, s->bar_window, 3931 defaults.bar_border_width); 3932 XSetWindowBorderWidth(dpy, s->frame_window, 3933 defaults.bar_border_width); 3934 XSetWindowBorderWidth(dpy, s->input_window, 3935 defaults.bar_border_width); 3936 3937 screen_update_workarea(s); 3938 screen_update_frames(s); 3939 } 3940 3941 return cmdret_new(RET_SUCCESS, NULL); 3942} 3943 3944static cmdret * 3945set_barinpadding(struct cmdarg **args) 3946{ 3947 rp_screen *s; 3948 int new_value; 3949 3950 if (args[0] == NULL) 3951 return cmdret_new(RET_SUCCESS, "%d", defaults.bar_in_padding); 3952 3953 new_value = ARG(0, number); 3954 if (new_value != 0 && new_value != 1) 3955 return cmdret_new(RET_FAILURE, 3956 "set barinpadding: invalid argument"); 3957 3958 mark_edge_frames(); 3959 3960 defaults.bar_in_padding = new_value; 3961 3962 list_for_each_entry(s, &rp_screens, node) { 3963 screen_update_workarea(s); 3964 screen_update_frames(s); 3965 } 3966 3967 return cmdret_new(RET_SUCCESS, NULL); 3968} 3969 3970static cmdret * 3971set_inputwidth(struct cmdarg **args) 3972{ 3973 if (args[0] == NULL) 3974 return cmdret_new(RET_SUCCESS, "%d", defaults.input_window_size); 3975 3976 if (ARG(0, number) < 0) 3977 return cmdret_new(RET_FAILURE, "set inputwidth: %s", 3978 invalid_negative_arg); 3979 3980 defaults.input_window_size = ARG(0, number); 3981 return cmdret_new(RET_SUCCESS, NULL); 3982} 3983 3984static cmdret * 3985set_waitcursor(struct cmdarg **args) 3986{ 3987 if (args[0] == NULL) 3988 return cmdret_new(RET_SUCCESS, "%d", 3989 defaults.wait_for_key_cursor); 3990 3991 if (ARG(0, number) != 0 && ARG(0, number) != 1) 3992 return cmdret_new(RET_FAILURE, 3993 "set waitcursor: invalid argument"); 3994 3995 defaults.wait_for_key_cursor = ARG(0, number); 3996 return cmdret_new(RET_SUCCESS, NULL); 3997} 3998 3999static cmdret * 4000set_infofmt(struct cmdarg **args) 4001{ 4002 if (args[0] == NULL) 4003 return cmdret_new(RET_SUCCESS, "%s", defaults.info_fmt); 4004 4005 free(defaults.info_fmt); 4006 defaults.info_fmt = xstrdup(ARG_STRING(0)); 4007 4008 return cmdret_new(RET_SUCCESS, NULL); 4009} 4010 4011static cmdret * 4012set_topkmap(struct cmdarg **args) 4013{ 4014 if (args[0] == NULL) 4015 return cmdret_new(RET_SUCCESS, "%s", defaults.top_kmap); 4016 4017 if (!find_keymap(ARG_STRING(0))) 4018 return cmdret_new(RET_FAILURE, "Unknown keymap %s", 4019 ARG_STRING(0)); 4020 4021 ungrab_keys_all_wins(); 4022 4023 free(defaults.top_kmap); 4024 defaults.top_kmap = xstrdup(ARG_STRING(0)); 4025 4026 grab_keys_all_wins(); 4027 XSync(dpy, False); 4028 4029 return cmdret_new(RET_SUCCESS, NULL); 4030} 4031 4032static cmdret * 4033set_winfmt(struct cmdarg **args) 4034{ 4035 if (args[0] == NULL) 4036 return cmdret_new(RET_SUCCESS, "%s", defaults.window_fmt); 4037 4038 free(defaults.window_fmt); 4039 defaults.window_fmt = xstrdup(ARG_STRING(0)); 4040 4041 return cmdret_new(RET_SUCCESS, NULL); 4042} 4043 4044static cmdret * 4045set_winname(struct cmdarg **args) 4046{ 4047 char *name; 4048 4049 if (args[0] == NULL) 4050 switch (defaults.win_name) { 4051 case WIN_NAME_TITLE: 4052 return cmdret_new(RET_SUCCESS, "title"); 4053 case WIN_NAME_RES_NAME: 4054 return cmdret_new(RET_SUCCESS, "name"); 4055 case WIN_NAME_RES_CLASS: 4056 return cmdret_new(RET_SUCCESS, "class"); 4057 default: 4058 PRINT_DEBUG(("Unknown win_name\n")); 4059 return cmdret_new(RET_FAILURE, "unknown"); 4060 } 4061 4062 name = ARG_STRING(0); 4063 4064 if (!strncmp(name, "title", sizeof("title"))) 4065 defaults.win_name = WIN_NAME_TITLE; 4066 else if (!strncmp(name, "name", sizeof("name"))) 4067 defaults.win_name = WIN_NAME_RES_NAME; 4068 else if (!strncmp(name, "class", sizeof("class"))) 4069 defaults.win_name = WIN_NAME_RES_CLASS; 4070 else 4071 return cmdret_new(RET_FAILURE, 4072 "set winname: invalid argument `%s'", name); 4073 4074 return cmdret_new(RET_SUCCESS, NULL); 4075} 4076 4077static cmdret * 4078set_framefmt(struct cmdarg **args) 4079{ 4080 if (args[0] == NULL) 4081 return cmdret_new(RET_SUCCESS, "%s", defaults.frame_fmt); 4082 4083 free(defaults.frame_fmt); 4084 defaults.frame_fmt = xstrdup(ARG_STRING(0)); 4085 4086 return cmdret_new(RET_SUCCESS, NULL); 4087} 4088 4089static cmdret * 4090set_fgcolor(struct cmdarg **args) 4091{ 4092 XColor color, junk; 4093 rp_screen *s; 4094 4095 if (args[0] == NULL) 4096 return cmdret_new(RET_SUCCESS, "%s", defaults.fgcolor_string); 4097 4098 list_for_each_entry(s, &rp_screens, node) { 4099 if (!XAllocNamedColor(dpy, s->def_cmap, ARG_STRING(0), &color, 4100 &junk)) 4101 return cmdret_new(RET_FAILURE, 4102 "set fgcolor: unknown color"); 4103 4104 rp_glob_screen.fgcolor = color.pixel | (0xff << 24); 4105 update_gc(s); 4106 4107 if (!XftColorAllocName(dpy, DefaultVisual(dpy, s->screen_num), 4108 DefaultColormap(dpy, s->screen_num), ARG_STRING(0), 4109 &s->xft_fgcolor)) 4110 return cmdret_new(RET_FAILURE, 4111 "set fgcolor: unknown color"); 4112 4113 free(defaults.fgcolor_string); 4114 defaults.fgcolor_string = xstrdup(ARG_STRING(0)); 4115 } 4116 4117 redraw_sticky_bar_text(1); 4118 4119 return cmdret_new(RET_SUCCESS, NULL); 4120} 4121 4122static cmdret * 4123set_bgcolor(struct cmdarg **args) 4124{ 4125 XColor color, junk; 4126 rp_screen *s; 4127 4128 if (args[0] == NULL) 4129 return cmdret_new(RET_SUCCESS, "%s", defaults.bgcolor_string); 4130 4131 list_for_each_entry(s, &rp_screens, node) { 4132 if (!XAllocNamedColor(dpy, s->def_cmap, ARG_STRING(0), &color, 4133 &junk)) 4134 return cmdret_new(RET_FAILURE, 4135 "set bgcolor: unknown color"); 4136 4137 color.pixel |= (0xff << 24); 4138 rp_glob_screen.bgcolor = color.pixel; 4139 update_gc(s); 4140 XSetWindowBackground(dpy, s->bar_window, color.pixel); 4141 XSetWindowBackground(dpy, s->input_window, color.pixel); 4142 XSetWindowBackground(dpy, s->frame_window, color.pixel); 4143 XSetWindowBackground(dpy, s->help_window, color.pixel); 4144 4145 if (!XftColorAllocName(dpy, DefaultVisual(dpy, s->screen_num), 4146 DefaultColormap(dpy, s->screen_num), ARG_STRING(0), 4147 &s->xft_bgcolor)) 4148 return cmdret_new(RET_FAILURE, 4149 "set fgcolor: unknown color"); 4150 4151 free(defaults.bgcolor_string); 4152 defaults.bgcolor_string = xstrdup(ARG_STRING(0)); 4153 } 4154 4155 redraw_sticky_bar_text(1); 4156 4157 return cmdret_new(RET_SUCCESS, NULL); 4158} 4159 4160static cmdret * 4161set_fwcolor(struct cmdarg **args) 4162{ 4163 XColor color, junk; 4164 rp_window *win = current_window(); 4165 rp_screen *s; 4166 4167 if (args[0] == NULL) 4168 return cmdret_new(RET_SUCCESS, "%s", defaults.fwcolor_string); 4169 4170 list_for_each_entry(s, &rp_screens, node) { 4171 if (!XAllocNamedColor(dpy, s->def_cmap, ARG_STRING(0), &color, 4172 &junk)) 4173 return cmdret_new(RET_FAILURE, 4174 "set fwcolor: unknown color"); 4175 4176 rp_glob_screen.fwcolor = color.pixel | (0xff << 24); 4177 update_gc(s); 4178 4179 free(defaults.fwcolor_string); 4180 defaults.fwcolor_string = xstrdup(ARG_STRING(0)); 4181 } 4182 4183 /* Update current window. */ 4184 if (win != NULL) 4185 XSetWindowBorder(dpy, win->w, rp_glob_screen.fwcolor); 4186 4187 return cmdret_new(RET_SUCCESS, NULL); 4188} 4189 4190static cmdret * 4191set_bwcolor(struct cmdarg **args) 4192{ 4193 XColor color, junk; 4194 rp_window *win, *cur_win = current_window(); 4195 rp_screen *s; 4196 4197 if (args[0] == NULL) 4198 return cmdret_new(RET_SUCCESS, "%s", defaults.bwcolor_string); 4199 4200 list_for_each_entry(s, &rp_screens, node) { 4201 if (!XAllocNamedColor(dpy, s->def_cmap, ARG_STRING(0), &color, 4202 &junk)) 4203 return cmdret_new(RET_FAILURE, 4204 "set bwcolor: unknown color"); 4205 4206 rp_glob_screen.bwcolor = color.pixel | (0xff << 24); 4207 update_gc(s); 4208 4209 free(defaults.bwcolor_string); 4210 defaults.bwcolor_string = xstrdup(ARG_STRING(0)); 4211 } 4212 4213 /* Update all the visible windows. */ 4214 list_for_each_entry(win, &rp_mapped_window, node) { 4215 if (win != cur_win) 4216 XSetWindowBorder(dpy, win->w, rp_glob_screen.bwcolor); 4217 } 4218 4219 return cmdret_new(RET_SUCCESS, NULL); 4220} 4221 4222static cmdret * 4223set_barbordercolor(struct cmdarg **args) 4224{ 4225 XColor color, junk; 4226 rp_screen *s; 4227 4228 if (args[0] == NULL) 4229 return cmdret_new(RET_SUCCESS, "%s", 4230 defaults.barbordercolor_string); 4231 4232 list_for_each_entry(s, &rp_screens, node) { 4233 if (!XAllocNamedColor(dpy, s->def_cmap, ARG_STRING(0), &color, 4234 &junk)) 4235 return cmdret_new(RET_FAILURE, 4236 "set barbordercolor: unknown color"); 4237 4238 color.pixel |= (0xff << 24); 4239 rp_glob_screen.bar_bordercolor = color.pixel; 4240 update_gc(s); 4241 XSetWindowBorder(dpy, s->bar_window, color.pixel); 4242 XSetWindowBorder(dpy, s->input_window, color.pixel); 4243 XSetWindowBorder(dpy, s->frame_window, color.pixel); 4244 XSetWindowBorder(dpy, s->help_window, color.pixel); 4245 4246 free(defaults.barbordercolor_string); 4247 defaults.barbordercolor_string = xstrdup(ARG_STRING(0)); 4248 } 4249 4250 redraw_sticky_bar_text(1); 4251 4252 return cmdret_new(RET_SUCCESS, NULL); 4253} 4254 4255static cmdret * 4256set_vscreens(struct cmdarg **args) 4257{ 4258 if (args[0] == NULL) 4259 return cmdret_new(RET_SUCCESS, "%d", defaults.vscreens); 4260 4261 if (ARG(0, number) < 1) 4262 return cmdret_new(RET_FAILURE, "vscreens: invalid argument"); 4263 4264 if (vscreens_resize(ARG(0, number)) != 0) 4265 return cmdret_new(RET_FAILURE, "vscreens: failed resizing"); 4266 4267 return cmdret_new(RET_SUCCESS, NULL); 4268} 4269 4270static cmdret * 4271set_gap(struct cmdarg **args) 4272{ 4273 rp_screen *s; 4274 4275 if (args[0] == NULL) 4276 return cmdret_new(RET_SUCCESS, "%d", defaults.gap); 4277 4278 if (ARG(0, number) < 0) 4279 return cmdret_new(RET_FAILURE, "gap: invalid argument"); 4280 4281 mark_edge_frames(); 4282 4283 defaults.gap = ARG(0, number); 4284 4285 list_for_each_entry(s, &rp_screens, node) { 4286 screen_update_workarea(s); 4287 screen_update_frames(s); 4288 } 4289 4290 return cmdret_new(RET_SUCCESS, NULL); 4291} 4292 4293static cmdret * 4294set_ignoreresizehints(struct cmdarg **args) 4295{ 4296 rp_screen *s; 4297 4298 if (args[0] == NULL) 4299 return cmdret_new(RET_SUCCESS, "%d", 4300 defaults.ignore_resize_hints); 4301 4302 if (ARG(0, number) < 0 || ARG(0, number) > 1) 4303 return cmdret_new(RET_FAILURE, 4304 "ignoreresizehints: invalid argument"); 4305 4306 mark_edge_frames(); 4307 4308 defaults.ignore_resize_hints = ARG(0, number); 4309 4310 list_for_each_entry(s, &rp_screens, node) { 4311 screen_update_frames(s); 4312 } 4313 4314 return cmdret_new(RET_SUCCESS, NULL); 4315} 4316 4317static cmdret * 4318set_resizefmt(struct cmdarg **args) 4319{ 4320 if (args[0] == NULL) 4321 return cmdret_new(RET_SUCCESS, "%s", defaults.resize_fmt); 4322 4323 free(defaults.resize_fmt); 4324 defaults.resize_fmt = xstrdup(ARG_STRING(0)); 4325 4326 return cmdret_new(RET_SUCCESS, NULL); 4327} 4328 4329static cmdret * 4330set_winaddcurvscreen(struct cmdarg **args) 4331{ 4332 if (args[0] == NULL) 4333 return cmdret_new(RET_SUCCESS, "%d", 4334 defaults.win_add_cur_vscreen); 4335 4336 if (ARG(0, number) < 0 || ARG(0, number) > 1) 4337 return cmdret_new(RET_FAILURE, 4338 "winaddcurvscreen: invalid argument"); 4339 4340 defaults.win_add_cur_vscreen = ARG(0, number); 4341 4342 return cmdret_new(RET_SUCCESS, NULL); 4343} 4344cmdret * 4345cmd_setenv(int interactive, struct cmdarg **args) 4346{ 4347 const char *var = ARG_STRING(0), *val = ARG_STRING(1); 4348 4349 PRINT_DEBUG(("setenv (\"%s\", \"%s\", 1)\n", var, val)); 4350 if (setenv(var, val, 1) == -1) 4351 return cmdret_new(RET_FAILURE, "cmd_setenv failed: %s", 4352 strerror(errno)); 4353 4354 return cmdret_new(RET_SUCCESS, NULL); 4355} 4356 4357cmdret * 4358cmd_getenv(int interactive, struct cmdarg **args) 4359{ 4360 char *value; 4361 4362 value = getenv(ARG_STRING(0)); 4363 if (value) 4364 return cmdret_new(RET_SUCCESS, "%s", value); 4365 4366 return cmdret_new(RET_FAILURE, NULL); 4367} 4368 4369/* 4370 * Thanks to Gergely Nagy <algernon@debian.org> for the original patch. 4371 */ 4372cmdret * 4373cmd_chdir(int interactive, struct cmdarg **args) 4374{ 4375 const char *dir; 4376 4377 if (args[0] == NULL) { 4378 dir = get_homedir(); 4379 if (dir == NULL) { 4380 return cmdret_new(RET_FAILURE, 4381 "chdir: unable to find your HOME directory"); 4382 } 4383 } else 4384 dir = ARG_STRING(0); 4385 4386 if (chdir(dir) == -1) 4387 return cmdret_new(RET_FAILURE, "chdir: %s: %s", dir, 4388 strerror(errno)); 4389 4390 return cmdret_new(RET_SUCCESS, NULL); 4391} 4392 4393/* 4394 * Thanks to Gergely Nagy <algernon@debian.org> for the original patch. 4395 */ 4396cmdret * 4397cmd_unsetenv(int interactive, struct cmdarg **args) 4398{ 4399 const char *var = ARG_STRING(0); 4400 4401 /* 4402 * Use unsetenv() where possible since putenv("FOO") is not legit 4403 * everywhere 4404 */ 4405 if (unsetenv(var) == -1) 4406 return cmdret_new(RET_FAILURE, "cmd_unsetenv failed: %s", 4407 strerror(errno)); 4408 4409 return cmdret_new(RET_SUCCESS, NULL); 4410} 4411 4412/* 4413 * Thanks to Gergely Nagy <algernon@debian.org> for the original patch. 4414 */ 4415cmdret * 4416cmd_info(int interactive, struct cmdarg **args) 4417{ 4418 struct sbuf *buf; 4419 if (current_window() != NULL) { 4420 rp_window *win = current_window(); 4421 rp_window_elem *win_elem; 4422 win_elem = vscreen_find_window(&rp_current_vscreen->mapped_windows, 4423 win); 4424 if (!win_elem) 4425 win_elem = vscreen_find_window( 4426 &rp_current_vscreen->unmapped_windows, win); 4427 4428 if (win_elem) { 4429 char *s; 4430 cmdret *ret; 4431 4432 if (args[0] == NULL) 4433 s = defaults.info_fmt; 4434 else 4435 s = ARG_STRING(0); 4436 buf = sbuf_new(0); 4437 format_string(s, win_elem, buf); 4438 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(buf)); 4439 sbuf_free(buf); 4440 return ret; 4441 } 4442 } 4443 4444 return cmdret_new(RET_SUCCESS, "No window."); 4445} 4446 4447/* 4448 * Thanks to Gergely Nagy <algernon@debian.org> for the original patch. 4449 */ 4450cmdret * 4451cmd_lastmsg(int interactive, struct cmdarg **args) 4452{ 4453 show_last_message(); 4454 return cmdret_new(RET_SUCCESS, NULL); 4455} 4456 4457cmdret * 4458cmd_focusup(int interactive, struct cmdarg **args) 4459{ 4460 rp_frame *frame; 4461 4462 if ((frame = find_frame_up(current_frame(rp_current_vscreen)))) 4463 set_active_frame(frame, 0); 4464 else 4465 show_frame_indicator(0); 4466 4467 return cmdret_new(RET_SUCCESS, NULL); 4468} 4469 4470cmdret * 4471cmd_focusdown(int interactive, struct cmdarg **args) 4472{ 4473 rp_frame *frame; 4474 4475 if ((frame = find_frame_down(current_frame(rp_current_vscreen)))) 4476 set_active_frame(frame, 0); 4477 else 4478 show_frame_indicator(0); 4479 4480 return cmdret_new(RET_SUCCESS, NULL); 4481} 4482 4483cmdret * 4484cmd_focusleft(int interactive, struct cmdarg **args) 4485{ 4486 rp_frame *frame; 4487 4488 if ((frame = find_frame_left(current_frame(rp_current_vscreen)))) 4489 set_active_frame(frame, 0); 4490 else 4491 show_frame_indicator(0); 4492 4493 return cmdret_new(RET_SUCCESS, NULL); 4494} 4495 4496cmdret * 4497cmd_focusright(int interactive, struct cmdarg **args) 4498{ 4499 rp_frame *frame; 4500 4501 if ((frame = find_frame_right(current_frame(rp_current_vscreen)))) 4502 set_active_frame(frame, 0); 4503 else 4504 show_frame_indicator(0); 4505 4506 return cmdret_new(RET_SUCCESS, NULL); 4507} 4508 4509cmdret * 4510cmd_exchangeup(int interactive, struct cmdarg **args) 4511{ 4512 rp_frame *frame; 4513 4514 if ((frame = find_frame_up(current_frame(rp_current_vscreen)))) 4515 exchange_with_frame(current_frame(rp_current_vscreen), frame); 4516 4517 return cmdret_new(RET_SUCCESS, NULL); 4518} 4519 4520cmdret * 4521cmd_exchangedown(int interactive, struct cmdarg **args) 4522{ 4523 rp_frame *frame; 4524 4525 if ((frame = find_frame_down(current_frame(rp_current_vscreen)))) 4526 exchange_with_frame(current_frame(rp_current_vscreen), frame); 4527 4528 return cmdret_new(RET_SUCCESS, NULL); 4529} 4530 4531cmdret * 4532cmd_exchangeleft(int interactive, struct cmdarg **args) 4533{ 4534 rp_frame *frame; 4535 4536 if ((frame = find_frame_left(current_frame(rp_current_vscreen)))) 4537 exchange_with_frame(current_frame(rp_current_vscreen), frame); 4538 4539 return cmdret_new(RET_SUCCESS, NULL); 4540} 4541 4542cmdret * 4543cmd_exchangeright(int interactive, struct cmdarg **args) 4544{ 4545 rp_frame *frame; 4546 4547 if ((frame = find_frame_right(current_frame(rp_current_vscreen)))) 4548 exchange_with_frame(current_frame(rp_current_vscreen), frame); 4549 4550 return cmdret_new(RET_SUCCESS, NULL); 4551} 4552 4553cmdret * 4554cmd_swap(int interactive, struct cmdarg **args) 4555{ 4556 rp_frame *dest_frame; 4557 rp_frame *src_frame; 4558 4559 dest_frame = ARG(0, frame); 4560 src_frame = args[1] ? ARG(1, frame) : current_frame(rp_current_vscreen); 4561 4562 if (!rp_have_xrandr) { 4563 if (vscreen_find_frame_by_frame(src_frame->vscreen, 4564 dest_frame) == NULL) 4565 return cmdret_new(RET_FAILURE, 4566 "swap: frames on different screens"); 4567 } 4568 exchange_with_frame(src_frame, dest_frame); 4569 4570 return cmdret_new(RET_SUCCESS, NULL); 4571} 4572 4573cmdret * 4574cmd_restart(int interactive, struct cmdarg **args) 4575{ 4576 hup_signalled = 1; 4577 return cmdret_new(RET_SUCCESS, NULL); 4578} 4579 4580static cmdret * 4581set_startupmessage(struct cmdarg **args) 4582{ 4583 if (args[0] == NULL) 4584 return cmdret_new(RET_SUCCESS, "%d", defaults.startup_message); 4585 4586 if (ARG(0, number) != 0 && ARG(0, number) != 1) 4587 return cmdret_new(RET_FAILURE, 4588 "set startupmessage: invalid argument"); 4589 4590 defaults.startup_message = ARG(0, number); 4591 return cmdret_new(RET_SUCCESS, NULL); 4592} 4593 4594cmdret * 4595cmd_focuslast(int interactive, struct cmdarg **args) 4596{ 4597 rp_frame *frame = find_last_frame(rp_current_vscreen); 4598 4599 if (frame) 4600 set_active_frame(frame, 0); 4601 else 4602 return cmdret_new(RET_FAILURE, "focuslast: no other frame"); 4603 4604 return cmdret_new(RET_SUCCESS, NULL); 4605} 4606 4607cmdret * 4608cmd_link(int interactive, struct cmdarg **args) 4609{ 4610 char *cmd = NULL; 4611 rp_keymap *map; 4612 4613 if (args[1]) 4614 map = ARG(1, keymap); 4615 else 4616 map = find_keymap(ROOT_KEYMAP); 4617 4618 cmd = resolve_command_from_keydesc(args[0]->string, 0, map); 4619 if (cmd) 4620 return command(interactive, cmd); 4621 4622 return cmdret_new(RET_SUCCESS, NULL); 4623} 4624 4625/* 4626 * Thanks to Doug Kearns <djkea2@mugc.its.monash.edu.au> for the original patch. 4627 */ 4628static cmdret * 4629set_barpadding(struct cmdarg **args) 4630{ 4631 rp_screen *s; 4632 int x, y; 4633 4634 if (args[0] == NULL) 4635 return cmdret_new(RET_SUCCESS, "%d %d", defaults.bar_x_padding, 4636 defaults.bar_y_padding); 4637 4638 x = ARG(0, number); 4639 y = ARG(1, number); 4640 4641 if (x < 0 || y < 0) 4642 return cmdret_new(RET_FAILURE, "set barpadding: %s", 4643 invalid_negative_arg); 4644 4645 mark_edge_frames(); 4646 4647 defaults.bar_x_padding = x; 4648 defaults.bar_y_padding = y; 4649 4650 list_for_each_entry(s, &rp_screens, node) { 4651 screen_update_workarea(s); 4652 screen_update_frames(s); 4653 } 4654 4655 return cmdret_new(RET_SUCCESS, NULL); 4656} 4657 4658static cmdret * 4659set_barsticky(struct cmdarg **args) 4660{ 4661 rp_screen *s; 4662 4663 if (args[0] == NULL) 4664 return cmdret_new(RET_SUCCESS, "%d", defaults.bar_sticky); 4665 4666 if (ARG(0, number) != 0 && ARG(0, number) != 1) 4667 return cmdret_new(RET_FAILURE, 4668 "set barsticky: invalid argument"); 4669 4670 mark_edge_frames(); 4671 4672 defaults.bar_sticky = ARG(0, number); 4673 4674 list_for_each_entry(s, &rp_screens, node) { 4675 hide_bar(s, 0); 4676 screen_update_workarea(s); 4677 screen_update_frames(s); 4678 } 4679 4680 return cmdret_new(RET_SUCCESS, NULL); 4681} 4682 4683static cmdret * 4684set_stickyfmt(struct cmdarg **args) 4685{ 4686 rp_screen *s; 4687 4688 if (args[0] == NULL) 4689 return cmdret_new(RET_SUCCESS, "%s", defaults.sticky_fmt); 4690 4691 free(defaults.sticky_fmt); 4692 defaults.sticky_fmt = xstrdup(ARG_STRING(0)); 4693 4694 list_for_each_entry(s, &rp_screens, node) { 4695 hide_bar(s, 0); 4696 } 4697 4698 return cmdret_new(RET_SUCCESS, NULL); 4699} 4700 4701cmdret * 4702cmd_alias(int interactive, struct cmdarg **args) 4703{ 4704 /* Add or update the alias. */ 4705 add_alias(ARG_STRING(0), ARG_STRING(1)); 4706 return cmdret_new(RET_SUCCESS, NULL); 4707} 4708 4709cmdret * 4710cmd_unalias(int interactive, struct cmdarg **args) 4711{ 4712 char *tmp; 4713 int i; 4714 4715 /* Are we updating an existing alias, or creating a new one? */ 4716 i = find_alias_index(ARG_STRING(0)); 4717 if (i < 0) 4718 return cmdret_new(RET_SUCCESS, "unalias: alias not found"); 4719 4720 alias_list_last--; 4721 4722 /* 4723 * Free the alias and put the last alias in the the space to 4724 * keep alias_list from becoming sparse. This code must jump 4725 * through some hoops to correctly handle the case when 4726 * alias_list_last == i. 4727 */ 4728 tmp = alias_list[i].alias; 4729 alias_list[i].alias = xstrdup(alias_list[alias_list_last].alias); 4730 free(tmp); 4731 free(alias_list[alias_list_last].alias); 4732 4733 /* Do the same for the name element. */ 4734 tmp = alias_list[i].name; 4735 alias_list[i].name = xstrdup(alias_list[alias_list_last].name); 4736 free(tmp); 4737 free(alias_list[alias_list_last].name); 4738 4739 return cmdret_new(RET_SUCCESS, NULL); 4740} 4741 4742cmdret * 4743cmd_nextscreen(int interactive, struct cmdarg **args) 4744{ 4745 rp_screen *new_screen; 4746 rp_frame *new_frame; 4747 4748 new_screen = screen_next(); 4749 4750 /* No need to go through the motions when we don't have to. */ 4751 if (screen_count() <= 1 || new_screen == rp_current_screen) 4752 return cmdret_new(RET_FAILURE, "nextscreen: no other screen"); 4753 4754 new_frame = vscreen_get_frame(new_screen->current_vscreen, 4755 new_screen->current_vscreen->current_frame); 4756 4757 set_active_frame(new_frame, 1); 4758 4759 return cmdret_new(RET_SUCCESS, NULL); 4760} 4761 4762cmdret * 4763cmd_prevscreen(int interactive, struct cmdarg **args) 4764{ 4765 rp_screen *new_screen; 4766 rp_frame *new_frame; 4767 4768 new_screen = screen_prev(); 4769 4770 /* No need to go through the motions when we don't have to. */ 4771 if (screen_count() <= 1 || new_screen == rp_current_screen) 4772 return cmdret_new(RET_SUCCESS, "prevscreen: no other screen"); 4773 4774 new_frame = vscreen_get_frame(new_screen->current_vscreen, 4775 new_screen->current_vscreen->current_frame); 4776 4777 set_active_frame(new_frame, 1); 4778 4779 return cmdret_new(RET_SUCCESS, NULL); 4780} 4781 4782cmdret * 4783cmd_smove(int interactive, struct cmdarg **args) 4784{ 4785 rp_window *w; 4786 rp_screen *screen; 4787 int new_screen; 4788 4789 if ((w = current_window()) == NULL) 4790 return cmdret_new(RET_FAILURE, "smove: no focused window"); 4791 4792 new_screen = ARG(0, number); 4793 if (new_screen < 0) 4794 return cmdret_new(RET_FAILURE, "smove: out of range"); 4795 4796 screen = screen_number(new_screen); 4797 if (!screen) 4798 return cmdret_new(RET_FAILURE, "smove: screen %d not found", 4799 new_screen); 4800 4801 if (screen == rp_current_screen) 4802 return cmdret_new(RET_SUCCESS, NULL); 4803 4804 vscreen_move_window(screen->current_vscreen, w); 4805 set_active_frame(current_frame(screen->current_vscreen), 1); 4806 set_active_window(w); 4807 return cmdret_new(RET_SUCCESS, NULL); 4808} 4809 4810cmdret * 4811cmd_sselect(int interactive, struct cmdarg **args) 4812{ 4813 int new_screen; 4814 rp_frame *new_frame; 4815 rp_screen *screen; 4816 4817 new_screen = ARG(0, number); 4818 if (new_screen < 0) 4819 return cmdret_new(RET_FAILURE, "sselect: out of range"); 4820 4821 screen = screen_number(new_screen); 4822 if (!screen) 4823 return cmdret_new(RET_FAILURE, "sselect: screen %d not found", 4824 new_screen); 4825 4826 if (screen == rp_current_screen) 4827 return cmdret_new(RET_SUCCESS, NULL); 4828 4829 new_frame = vscreen_get_frame(screen->current_vscreen, 4830 screen->current_vscreen->current_frame); 4831 set_active_frame(new_frame, 1); 4832 4833 return cmdret_new(RET_SUCCESS, NULL); 4834} 4835 4836static cmdret * 4837set_warp(struct cmdarg **args) 4838{ 4839 if (args[0] == NULL) 4840 return cmdret_new(RET_SUCCESS, "%d", defaults.warp); 4841 4842 if (ARG(0, number) != 0 && ARG(0, number) != 1) 4843 return cmdret_new(RET_FAILURE, "set warp: invalid argument"); 4844 4845 defaults.warp = ARG(0, number); 4846 return cmdret_new(RET_SUCCESS, NULL); 4847} 4848 4849/* 4850 * Return a new string with the frame selector or it as a string if no selector 4851 * exists for the number. 4852 */ 4853 4854/* Select a frame by number. */ 4855cmdret * 4856cmd_fselect(int interactive, struct cmdarg **args) 4857{ 4858 set_active_frame(ARG(0, frame), 1); 4859 return cmdret_new(RET_SUCCESS, NULL); 4860} 4861 4862char * 4863fdump(rp_vscreen *vscreen) 4864{ 4865 struct sbuf *dump; 4866 rp_frame *cur; 4867 4868 dump = sbuf_new(0); 4869 4870 list_for_each_entry(cur, &(vscreen->frames), node) { 4871 char *frameset; 4872 4873 frameset = frame_dump(cur, vscreen); 4874 sbuf_concat(dump, frameset); 4875 sbuf_concat(dump, ","); 4876 free(frameset); 4877 } 4878 sbuf_chop(dump); 4879 4880 return sbuf_free_struct(dump); 4881} 4882 4883cmdret * 4884cmd_fdump(int interactively, struct cmdarg **args) 4885{ 4886 rp_screen *screen; 4887 cmdret *ret; 4888 char *dump; 4889 4890 if (args[0] == NULL) 4891 screen = rp_current_screen; 4892 else { 4893 int snum; 4894 snum = ARG(0, number); 4895 4896 if (snum < 0) 4897 return cmdret_new(RET_FAILURE, 4898 "fdump: invalid negative screen number"); 4899 else { 4900 screen = screen_number(snum); 4901 if (!screen) 4902 return cmdret_new(RET_FAILURE, 4903 "fdump: screen %d not found", snum); 4904 } 4905 } 4906 4907 dump = fdump(screen->current_vscreen); 4908 ret = cmdret_new(RET_SUCCESS, "%s", dump); 4909 free(dump); 4910 4911 return ret; 4912} 4913 4914cmdret * 4915frestore(char *data, rp_vscreen *v) 4916{ 4917 char *token; 4918 char *d; 4919 rp_frame *new, *cur; 4920 rp_window *win; 4921 struct list_head fset; 4922 int max = -1; 4923 char *nexttok = NULL; 4924 4925 INIT_LIST_HEAD(&fset); 4926 4927 d = xstrdup(data); 4928 token = strtok_r(d, ",", &nexttok); 4929 if (token == NULL) { 4930 free(d); 4931 return cmdret_new(RET_FAILURE, 4932 "frestore: invalid frame format"); 4933 } 4934 4935 /* Build the new frame set. */ 4936 while (token != NULL) { 4937 new = frame_read(token, v); 4938 if (new == NULL) { 4939 free(d); 4940 return cmdret_new(RET_FAILURE, 4941 "frestore: invalid frame format"); 4942 } 4943 list_add_tail(&new->node, &fset); 4944 token = strtok_r(NULL, ",", &nexttok); 4945 } 4946 4947 free(d); 4948 4949 /* Clear all the frames. */ 4950 list_for_each_entry(cur, &v->frames, node) { 4951 PRINT_DEBUG(("blank %d\n", cur->number)); 4952 blank_frame(cur); 4953 } 4954 4955 /* Get rid of the frames' numbers */ 4956 vscreen_free_nums(v); 4957 4958 /* Splice in our new frameset. */ 4959 vscreen_restore_frameset(v, &fset); 4960 4961 /* Process the frames a bit to make sure everything lines up. */ 4962 list_for_each_entry(cur, &v->frames, node) { 4963 PRINT_DEBUG(("restore %d %d\n", cur->number, cur->win_number)); 4964 4965 /* 4966 * Grab the frame's number, but if it already exists request a 4967 * new one. 4968 */ 4969 if (!numset_add_num(v->frames_numset, cur->number)) { 4970 cur->number = numset_request(v->frames_numset); 4971 } 4972 /* Find the current frame based on last_access. */ 4973 if (cur->last_access > max) { 4974 v->current_frame = cur->number; 4975 max = cur->last_access; 4976 } 4977 /* Update the window the frame points to. */ 4978 if (cur->win_number != EMPTY) { 4979 set_frames_window(cur, 4980 find_window_number(cur->win_number)); 4981 } 4982 } 4983 4984 /* Show the windows in the frames. */ 4985 list_for_each_entry(win, &rp_mapped_window, node) { 4986 if (win->frame_number != EMPTY) { 4987 maximize(win); 4988 unhide_window(win); 4989 } 4990 } 4991 4992 set_active_frame(current_frame(v), 0); 4993 update_bar(v->screen); 4994 show_frame_indicator(0); 4995 4996 PRINT_DEBUG(("Done.\n")); 4997 return cmdret_new(RET_SUCCESS, NULL); 4998} 4999 5000cmdret * 5001cmd_frestore(int interactively, struct cmdarg **args) 5002{ 5003 push_frame_undo(rp_current_vscreen); /* fdump to stack */ 5004 return frestore(ARG_STRING(0), rp_current_vscreen); 5005} 5006 5007cmdret * 5008cmd_verbexec(int interactive, struct cmdarg **args) 5009{ 5010 marked_message_printf(0, 0, "Running %s", ARG_STRING(0)); 5011 spawn(ARG_STRING(0), current_frame(rp_current_vscreen)); 5012 return cmdret_new(RET_SUCCESS, NULL); 5013} 5014 5015static cmdret * 5016set_winliststyle(struct cmdarg **args) 5017{ 5018 if (args[0] == NULL) 5019 return cmdret_new(RET_SUCCESS, "%s", 5020 defaults.window_list_style ? "column" : "row"); 5021 5022 if (!strcmp("column", ARG_STRING(0))) 5023 defaults.window_list_style = STYLE_COLUMN; 5024 else if (!strcmp("row", ARG_STRING(0))) 5025 defaults.window_list_style = STYLE_ROW; 5026 else 5027 return cmdret_new(RET_FAILURE, 5028 "set winliststyle: invalid argument"); 5029 5030 return cmdret_new(RET_SUCCESS, NULL); 5031} 5032 5033cmdret * 5034cmd_vrename(int interactive, struct cmdarg **args) 5035{ 5036 if (screen_find_vscreen_by_name(rp_current_screen, ARG_STRING(0), 1)) 5037 return cmdret_new(RET_FAILURE, "vrename: duplicate vscreen name"); 5038 vscreen_rename(rp_current_vscreen, ARG_STRING(0)); 5039 5040 /* Update the vscreen list. */ 5041 update_vscreen_names(rp_current_screen); 5042 5043 return cmdret_new(RET_SUCCESS, NULL); 5044} 5045 5046cmdret * 5047cmd_vselect(int interactive, struct cmdarg **args) 5048{ 5049 rp_vscreen *v; 5050 5051 v = find_vscreen(ARG_STRING(0)); 5052 if (v) 5053 set_current_vscreen(v); 5054 else 5055 return cmd_vscreens(interactive, NULL); 5056 5057 return cmdret_new(RET_SUCCESS, NULL); 5058} 5059 5060/* Show all the vscreens, with the current one highlighted. */ 5061cmdret * 5062cmd_vscreens(int interactive, struct cmdarg **args) 5063{ 5064 struct sbuf *vscreen_list = NULL; 5065 int dummy; 5066 cmdret *ret; 5067 5068 if (interactive) { 5069 rp_screen *s; 5070 s = rp_current_screen; 5071 ret = cmdret_new(RET_SUCCESS, NULL); 5072 if (defaults.bar_timeout == 0 && s->bar_is_raised) { 5073 hide_bar(s, 0); 5074 return ret; 5075 } 5076 show_vscreen_bar(s); 5077 } else { 5078 vscreen_list = sbuf_new(0); 5079 get_vscreen_list(rp_current_screen, "\n", vscreen_list, &dummy, 5080 &dummy); 5081 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(vscreen_list)); 5082 sbuf_free(vscreen_list); 5083 } 5084 return ret; 5085} 5086 5087cmdret * 5088cmd_vnext(int interactive, struct cmdarg **args) 5089{ 5090 rp_vscreen *v; 5091 v = vscreen_next_vscreen(rp_current_vscreen); 5092 if (!v) 5093 return cmdret_new(RET_FAILURE, "%s", "next vscreen failed"); 5094 5095 set_current_vscreen(v); 5096 return cmdret_new(RET_SUCCESS, NULL); 5097} 5098 5099cmdret * 5100cmd_vprev(int interactive, struct cmdarg **args) 5101{ 5102 rp_vscreen *v; 5103 v = vscreen_prev_vscreen(rp_current_vscreen); 5104 if (!v) 5105 return cmdret_new(RET_FAILURE, "%s", "prev vscreen failed"); 5106 5107 set_current_vscreen(v); 5108 return cmdret_new(RET_SUCCESS, NULL); 5109} 5110 5111cmdret * 5112cmd_vother(int interactive, struct cmdarg **args) 5113{ 5114 rp_vscreen *v; 5115 v = screen_last_vscreen(rp_current_screen); 5116 if (!v) 5117 /* todo: should we just return success here so it's a no-op? */ 5118 return cmdret_new(RET_FAILURE, "%s", "last vscreen failed"); 5119 5120 set_current_vscreen(v); 5121 return cmdret_new(RET_SUCCESS, NULL); 5122} 5123 5124cmdret * 5125cmd_addhook(int interactive, struct cmdarg **args) 5126{ 5127 struct list_head *hook; 5128 struct sbuf *cmd; 5129 5130 hook = hook_lookup(ARG_STRING(0)); 5131 if (hook == NULL) 5132 return cmdret_new(RET_FAILURE, "addhook: unknown hook '%s'", 5133 ARG_STRING(0)); 5134 5135 /* Add the command to the hook */ 5136 cmd = sbuf_new(0); 5137 sbuf_copy(cmd, ARG_STRING(1)); 5138 hook_add(hook, cmd); 5139 5140 return cmdret_new(RET_SUCCESS, NULL); 5141} 5142 5143cmdret * 5144cmd_remhook(int interactive, struct cmdarg **args) 5145{ 5146 struct sbuf *cmd; 5147 5148 /* Remove the command from the hook */ 5149 cmd = sbuf_new(0); 5150 sbuf_copy(cmd, ARG_STRING(1)); 5151 hook_remove(ARG(0, hook), cmd); 5152 sbuf_free(cmd); 5153 5154 return cmdret_new(RET_SUCCESS, NULL); 5155} 5156 5157cmdret * 5158cmd_listhook(int interactive, struct cmdarg **args) 5159{ 5160 cmdret *ret; 5161 struct sbuf *buffer; 5162 struct list_head *hook; 5163 struct sbuf *cur; 5164 5165 hook = hook_lookup(ARG_STRING(0)); 5166 if (hook == NULL) 5167 return cmdret_new(RET_FAILURE, "listhook: unknown hook '%s'", 5168 ARG_STRING(0)); 5169 5170 if (list_empty(hook)) 5171 return cmdret_new(RET_FAILURE, " Nothing defined for %s ", 5172 ARG_STRING(0)); 5173 5174 buffer = sbuf_new(0); 5175 5176 list_for_each_entry(cur, hook, node) { 5177 sbuf_printf_concat(buffer, "%s", sbuf_get(cur)); 5178 if (cur->node.next != hook) 5179 sbuf_printf_concat(buffer, "\n"); 5180 } 5181 5182 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(buffer)); 5183 sbuf_free(buffer); 5184 return ret; 5185} 5186 5187cmdret * 5188cmd_readkey(int interactive, struct cmdarg **args) 5189{ 5190 char *keysym_name; 5191 rp_action *key_action; 5192 KeySym keysym; /* Key pressed */ 5193 unsigned int mod; /* Modifiers */ 5194 int rat_grabbed = 0; 5195 rp_keymap *map; 5196 cmdret *ret; 5197 5198 map = ARG(0, keymap); 5199 5200 /* 5201 * Change the mouse icon to indicate to the user we are waiting for 5202 * more keystrokes 5203 */ 5204 if (defaults.wait_for_key_cursor) { 5205 grab_rat(); 5206 rat_grabbed = 1; 5207 } 5208 read_single_key(&keysym, &mod, NULL, 0); 5209 5210 if (rat_grabbed) 5211 ungrab_rat(); 5212 5213 if ((key_action = find_keybinding(keysym, x11_mask_to_rp_mask(mod), map))) { 5214 return command(1, key_action->data); 5215 } 5216 5217 /* No key match, notify user. */ 5218 keysym_name = keysym_to_string(keysym, x11_mask_to_rp_mask(mod)); 5219 ret = cmdret_new(RET_FAILURE, "readkey: unbound key '%s'", keysym_name); 5220 free(keysym_name); 5221 return ret; 5222} 5223 5224cmdret * 5225cmd_newkmap(int interactive, struct cmdarg **args) 5226{ 5227 rp_keymap *map; 5228 5229 map = find_keymap(ARG_STRING(0)); 5230 if (map) 5231 return cmdret_new(RET_FAILURE, 5232 "newkmap: keymap '%s' already exists", ARG_STRING(0)); 5233 5234 map = keymap_new(ARG_STRING(0)); 5235 list_add_tail(&map->node, &rp_keymaps); 5236 5237 return cmdret_new(RET_SUCCESS, NULL); 5238} 5239 5240cmdret * 5241cmd_delkmap(int interactive, struct cmdarg **args) 5242{ 5243 rp_keymap *map, *top, *root; 5244 5245 top = find_keymap(defaults.top_kmap); 5246 root = find_keymap(ROOT_KEYMAP); 5247 5248 map = ARG(0, keymap); 5249 if (map == root || map == top) 5250 return cmdret_new(RET_FAILURE, 5251 "delkmap: cannot delete keymap '%s'", ARG_STRING(0)); 5252 5253 list_del(&map->node); 5254 5255 return cmdret_new(RET_SUCCESS, NULL); 5256} 5257 5258static cmdret * 5259set_framesels(struct cmdarg **args) 5260{ 5261 if (args[0] == NULL) 5262 return cmdret_new(RET_SUCCESS, "%s", defaults.frame_selectors); 5263 5264 free(defaults.frame_selectors); 5265 defaults.frame_selectors = xstrdup(ARG_STRING(0)); 5266 return cmdret_new(RET_SUCCESS, NULL); 5267} 5268 5269cmdret * 5270cmd_set(int interactive, struct cmdarg **args) 5271{ 5272 struct sbuf *scur; 5273 struct cmdarg *acur; 5274 struct list_head *iter, *tmp; 5275 struct list_head head, arglist; 5276 int i, nargs = 0, raw = 0; 5277 int parsed_args; 5278 cmdret *result = NULL; 5279 struct cmdarg **cmdargs; 5280 char *input; 5281 5282 if (args[0] == NULL) { 5283 /* List all the settings. */ 5284 cmdret *ret; 5285 struct sbuf *s = sbuf_new(0); 5286 struct set_var *cur, *last; 5287 5288 list_last(last, &set_vars, node); 5289 list_for_each_entry(cur, &set_vars, node) { 5290 cmdret *r; 5291 r = cur->set_fn(args); 5292 sbuf_printf_concat(s, "%s: %s", cur->var, r->output); 5293 /* Skip a newline on the last line. */ 5294 if (cur != last) 5295 sbuf_concat(s, "\n"); 5296 cmdret_free(r); 5297 } 5298 5299 /* Return the accumulated string. */ 5300 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(s)); 5301 sbuf_free(s); 5302 return ret; 5303 } 5304 5305 INIT_LIST_HEAD(&arglist); 5306 INIT_LIST_HEAD(&head); 5307 5308 /* We need to tell parse_args about arg_REST and arg_SHELLCMD. */ 5309 for (i = 0; i < ARG(0, variable)->nargs; i++) 5310 if (ARG(0, variable)->args[i].type == arg_REST 5311 || ARG(0, variable)->args[i].type == arg_COMMAND 5312 || ARG(0, variable)->args[i].type == arg_SHELLCMD 5313 || ARG(0, variable)->args[i].type == arg_RAW) { 5314 raw = 1; 5315 nargs = i; 5316 break; 5317 } 5318 5319 /* Parse the arguments and call the function. */ 5320 if (args[1]) 5321 input = xstrdup(args[1]->string); 5322 else 5323 input = xstrdup(""); 5324 5325 result = parse_args(input, &head, nargs, raw); 5326 free(input); 5327 if (result) 5328 goto failed; 5329 5330 result = parsed_input_to_args(ARG(0, variable)->nargs, 5331 ARG(0, variable)->args, &head, &arglist, &parsed_args, NULL); 5332 if (result) 5333 goto failed; 5334 5335 /* 0 or nargs is acceptable */ 5336 if (list_size(&arglist) > 0 && 5337 list_size(&arglist) < ARG(0, variable)->nargs) { 5338 result = cmdret_new(RET_FAILURE, "not enough arguments."); 5339 goto failed; 5340 } else if (list_size(&head) > ARG(0, variable)->nargs) { 5341 result = cmdret_new(RET_FAILURE, "cmd_set: too many args."); 5342 goto failed; 5343 } 5344 5345 cmdargs = arg_array(&arglist); 5346 result = ARG(0, variable)->set_fn(cmdargs); 5347 free(cmdargs); 5348 5349 /* Free the lists. */ 5350failed: 5351 /* Free the parsed strings */ 5352 list_for_each_safe_entry(scur, iter, tmp, &head, node) { 5353 sbuf_free(scur); 5354 } 5355 5356 /* Free the args */ 5357 list_for_each_safe_entry(acur, iter, tmp, &arglist, node) { 5358 arg_free(acur); 5359 } 5360 5361 return result; 5362} 5363 5364cmdret * 5365cmd_sfdump(int interactively, struct cmdarg **args) 5366{ 5367 char screen_suffix[16]; 5368 cmdret *ret; 5369 struct sbuf *dump; 5370 rp_frame *cur_frame; 5371 rp_screen *cur_screen; 5372 5373 dump = sbuf_new(0); 5374 5375 list_for_each_entry(cur_screen, &rp_screens, node) { 5376 snprintf(screen_suffix, sizeof(screen_suffix), " %d,", 5377 cur_screen->number); 5378 5379 list_for_each_entry(cur_frame, 5380 &(cur_screen->current_vscreen->frames), node) { 5381 char *frameset; 5382 5383 frameset = frame_dump(cur_frame, 5384 cur_screen->current_vscreen); 5385 sbuf_concat(dump, frameset); 5386 sbuf_concat(dump, screen_suffix); 5387 free(frameset); 5388 } 5389 } 5390 5391 sbuf_chop(dump); 5392 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(dump)); 5393 sbuf_free(dump); 5394 return ret; 5395} 5396 5397cmdret * 5398cmd_sfrestore(int interactively, struct cmdarg **args) 5399{ 5400 char *copy, *ptr, *token; 5401 rp_screen *screen; 5402 int out_of_screen = 0, restored = 0; 5403 5404 list_for_each_entry(screen, &rp_screens, node) { 5405 sbuf_free(screen->scratch_buffer); 5406 screen->scratch_buffer = sbuf_new(0); 5407 } 5408 5409 copy = xstrdup(ARG_STRING(0)); 5410 5411 token = strtok(copy, ","); 5412 if (token == NULL) { 5413 free(copy); 5414 return cmdret_new(RET_FAILURE, 5415 "sfrestore: invalid frame format"); 5416 } 5417 5418 while (token != NULL) { 5419 int snum; 5420 5421 /* search for end of frameset */ 5422 ptr = token; 5423 while (*ptr != ')') 5424 ptr++; 5425 ptr++; 5426 5427 snum = string_to_positive_int(ptr); 5428 screen = screen_number(snum); 5429 if (screen) { 5430 /* 5431 * clobber screen number here, frestore() doesn't need 5432 * it 5433 */ 5434 *ptr = '\0'; 5435 sbuf_concat(screen->scratch_buffer, token); 5436 sbuf_concat(screen->scratch_buffer, ","); 5437 } else 5438 out_of_screen++; 5439 5440 /* continue with next frameset */ 5441 token = strtok(NULL, ","); 5442 } 5443 5444 free(copy); 5445 5446 /* now restore the frames for each screen */ 5447 list_for_each_entry(screen, &rp_screens, node) { 5448 cmdret *ret; 5449 5450 if (strlen(sbuf_get(screen->scratch_buffer)) == 0) 5451 continue; 5452 5453 push_frame_undo(screen->current_vscreen); /* fdump to stack */ 5454 5455 /* 5456 * XXX save the failure of each frestore and display it in case 5457 * of error 5458 */ 5459 ret = frestore(sbuf_get(screen->scratch_buffer), 5460 screen->current_vscreen); 5461 if (ret->success) 5462 restored++; 5463 cmdret_free(ret); 5464 5465 sbuf_free(screen->scratch_buffer); 5466 screen->scratch_buffer = NULL; 5467 } 5468 5469 if (!out_of_screen) 5470 return cmdret_new(RET_SUCCESS, "screens restored: %d", restored); 5471 5472 return cmdret_new(RET_SUCCESS, 5473 "screens restored: %d, frames out of screen: %d", 5474 restored, out_of_screen); 5475} 5476 5477cmdret * 5478cmd_sdump(int interactive, struct cmdarg **args) 5479{ 5480 cmdret *ret; 5481 struct sbuf *s; 5482 char *tmp; 5483 rp_screen *cur_screen; 5484 5485 s = sbuf_new(0); 5486 list_for_each_entry(cur_screen, &rp_screens, node) { 5487 tmp = screen_dump(cur_screen); 5488 sbuf_concat(s, tmp); 5489 sbuf_concat(s, ","); 5490 free(tmp); 5491 } 5492 sbuf_chop(s); 5493 5494 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(s)); 5495 sbuf_free(s); 5496 return ret; 5497} 5498 5499static cmdret * 5500set_maxundos(struct cmdarg **args) 5501{ 5502 rp_frame_undo *cur; 5503 5504 if (args[0] == NULL) 5505 return cmdret_new(RET_SUCCESS, "%d", defaults.maxundos); 5506 5507 if (ARG(0, number) < 0) 5508 return cmdret_new(RET_FAILURE, "set maxundos: %s", 5509 invalid_negative_arg); 5510 5511 defaults.maxundos = ARG(0, number); 5512 5513 /* Delete any superfluous undos */ 5514 while (list_size(&rp_frame_undos) > defaults.maxundos) { 5515 /* Delete the oldest node */ 5516 list_last(cur, &rp_frame_undos, node); 5517 del_frame_undo(cur); 5518 } 5519 5520 return cmdret_new(RET_SUCCESS, NULL); 5521} 5522 5523cmdret * 5524cmd_cnext(int interactive, struct cmdarg **args) 5525{ 5526 rp_window *cur, *last, *win; 5527 5528 cur = current_window(); 5529 if (!cur || !cur->res_class) /* Can't be done. */ 5530 return cmd_next(interactive, args); 5531 5532 /* CUR !in cycle list, so LAST marks last node. */ 5533 last = vscreen_prev_window(rp_current_vscreen, cur); 5534 5535 if (last) 5536 for (win = vscreen_next_window(rp_current_vscreen, cur); 5537 win; 5538 win = vscreen_next_window(rp_current_vscreen, win)) { 5539 if (win->res_class 5540 && strcmp(cur->res_class, win->res_class)) { 5541 set_active_window_force(win); 5542 return cmdret_new(RET_SUCCESS, NULL); 5543 } 5544 if (win == last) 5545 break; 5546 } 5547 5548 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5549} 5550 5551cmdret * 5552cmd_cprev(int interactive, struct cmdarg **args) 5553{ 5554 rp_window *cur, *last, *win; 5555 5556 cur = current_window(); 5557 if (!cur || !cur->res_class) /* Can't be done. */ 5558 return cmd_next(interactive, args); 5559 5560 /* CUR !in cycle list, so LAST marks last node. */ 5561 last = vscreen_next_window(rp_current_vscreen, cur); 5562 5563 if (last) 5564 for (win = vscreen_prev_window(rp_current_vscreen, cur); 5565 win; 5566 win = vscreen_prev_window(rp_current_vscreen, win)) { 5567 if (win->res_class 5568 && strcmp(cur->res_class, win->res_class)) { 5569 set_active_window_force(win); 5570 return cmdret_new(RET_SUCCESS, NULL); 5571 } 5572 if (win == last) 5573 break; 5574 } 5575 5576 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5577} 5578 5579cmdret * 5580cmd_inext(int interactive, struct cmdarg **args) 5581{ 5582 rp_window *cur, *last, *win; 5583 5584 cur = current_window(); 5585 if (!cur || !cur->res_class) /* Can't be done. */ 5586 return cmd_next(interactive, args); 5587 5588 /* CUR !in cycle list, so LAST marks last node. */ 5589 last = vscreen_prev_window(rp_current_vscreen, cur); 5590 5591 if (last) 5592 for (win = vscreen_next_window(rp_current_vscreen, cur); 5593 win; 5594 win = vscreen_next_window(rp_current_vscreen, win)) { 5595 if (win->res_class 5596 && !strcmp(cur->res_class, win->res_class)) { 5597 set_active_window_force(win); 5598 return cmdret_new(RET_SUCCESS, NULL); 5599 } 5600 if (win == last) 5601 break; 5602 } 5603 5604 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5605} 5606 5607cmdret * 5608cmd_iprev(int interactive, struct cmdarg **args) 5609{ 5610 rp_window *cur, *last, *win; 5611 5612 cur = current_window(); 5613 if (!cur || !cur->res_class) /* Can't be done. */ 5614 return cmd_next(interactive, args); 5615 5616 /* CUR !in cycle list, so LAST marks last node. */ 5617 last = vscreen_next_window(rp_current_vscreen, cur); 5618 5619 if (last) 5620 for (win = vscreen_prev_window(rp_current_vscreen, cur); 5621 win; 5622 win = vscreen_prev_window(rp_current_vscreen, win)) { 5623 if (win->res_class 5624 && !strcmp(cur->res_class, win->res_class)) { 5625 set_active_window_force(win); 5626 return cmdret_new(RET_SUCCESS, NULL); 5627 } 5628 if (win == last) 5629 break; 5630 } 5631 5632 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5633} 5634 5635cmdret * 5636cmd_cother(int interactive, struct cmdarg **args) 5637{ 5638 rp_window *cur, *w = NULL; 5639 5640 cur = current_window(); 5641 if (cur) 5642 w = vscreen_last_window_by_class(rp_current_vscreen, 5643 cur->res_class); 5644 5645 if (!w) 5646 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5647 else 5648 set_active_window_force(w); 5649 5650 return cmdret_new(RET_SUCCESS, NULL); 5651} 5652 5653cmdret * 5654cmd_iother(int interactive, struct cmdarg **args) 5655{ 5656 rp_window *cur, *w = NULL; 5657 5658 cur = current_window(); 5659 if (cur) 5660 w = vscreen_last_window_by_class_complement(rp_current_vscreen, 5661 cur->res_class); 5662 5663 if (!w) 5664 return cmdret_new(RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW); 5665 else 5666 set_active_window_force(w); 5667 5668 return cmdret_new(RET_SUCCESS, NULL); 5669} 5670 5671cmdret * 5672cmd_undo(int interactive, struct cmdarg **args) 5673{ 5674 rp_frame_undo *cur; 5675 5676 cur = pop_frame_undo(); 5677 if (!cur) 5678 return cmdret_new(RET_FAILURE, 5679 "No more undo information available"); 5680 else { 5681 cmdret *ret; 5682 5683 ret = frestore(cur->frames, cur->vscreen); 5684 return ret; 5685 } 5686} 5687 5688cmdret * 5689cmd_redo(int interactive, struct cmdarg **args) 5690{ 5691 rp_frame_undo *cur; 5692 cmdret *ret; 5693 5694 /* The current layout goes on the undo. */ 5695 cur = pop_frame_redo(); 5696 if (!cur) 5697 return cmdret_new(RET_FAILURE, 5698 "No more redo information available"); 5699 5700 ret = frestore(cur->frames, cur->vscreen); 5701 return ret; 5702} 5703 5704cmdret * 5705cmd_prompt(int interactive, struct cmdarg **args) 5706{ 5707 cmdret *ret; 5708 char *output; 5709 5710 if (args[0] == NULL) 5711 output = get_input(MESSAGE_PROMPT_COMMAND, hist_PROMPT, 5712 trivial_completions); 5713 else { 5714 char *arg_str, *prefix; 5715 5716 arg_str = ARG_STRING(0); 5717 prefix = strchr(arg_str, ':'); 5718 5719 if (prefix) { 5720 struct sbuf *query; 5721 5722 prefix++; /* Don't return the colon. */ 5723 query = sbuf_new(prefix - arg_str); 5724 sbuf_nconcat(query, arg_str, prefix - arg_str); 5725 output = get_more_input(sbuf_get(query), prefix, 5726 hist_PROMPT, BASIC, trivial_completions); 5727 sbuf_free(query); 5728 } else { 5729 output = get_input(arg_str, hist_PROMPT, 5730 trivial_completions); 5731 } 5732 } 5733 5734 if (output == NULL) 5735 return cmdret_new(RET_FAILURE, NULL); /* User aborted */ 5736 5737 ret = cmdret_new(RET_SUCCESS, "%s", output); 5738 free(output); 5739 5740 return ret; 5741} 5742 5743cmdret * 5744cmd_describekey(int interactive, struct cmdarg **args) 5745{ 5746 char *keysym_name; 5747 rp_action *key_action; 5748 KeySym keysym; /* Key pressed */ 5749 unsigned int mod; /* Modifiers */ 5750 int rat_grabbed = 0; 5751 rp_keymap *map; 5752 5753 map = ARG(0, keymap); 5754 5755 /* 5756 * Change the mouse icon to indicate to the user we are waiting for 5757 * more keystrokes 5758 */ 5759 if (defaults.wait_for_key_cursor) { 5760 grab_rat(); 5761 rat_grabbed = 1; 5762 } 5763 read_single_key(&keysym, &mod, NULL, 0); 5764 5765 if (rat_grabbed) 5766 ungrab_rat(); 5767 5768 if ((key_action = find_keybinding(keysym, x11_mask_to_rp_mask(mod), 5769 map))) { 5770 cmdret *ret; 5771 keysym_name = keysym_to_string(keysym, 5772 x11_mask_to_rp_mask(mod)); 5773 ret = cmdret_new(RET_SUCCESS, "%s bound to '%s'", keysym_name, 5774 key_action->data); 5775 free(keysym_name); 5776 return ret; 5777 } else { 5778 cmdret *ret; 5779 /* No key match, notify user. */ 5780 keysym_name = keysym_to_string(keysym, 5781 x11_mask_to_rp_mask(mod)); 5782 ret = cmdret_new(RET_SUCCESS, "describekey: unbound key '%s'", 5783 keysym_name); 5784 free(keysym_name); 5785 return ret; 5786 } 5787} 5788 5789cmdret * 5790cmd_dedicate(int interactive, struct cmdarg **args) 5791{ 5792 rp_frame *f; 5793 5794 f = current_frame(rp_current_vscreen); 5795 if (f == NULL) 5796 return cmdret_new(RET_SUCCESS, NULL); 5797 5798 if (args[0] != NULL) { 5799 int dedicated; 5800 5801 dedicated = ARG(0, number); 5802 if (dedicated != 0 && dedicated != 1) 5803 return cmdret_new(RET_FAILURE, 5804 "Invalid \"dedicate\" value, use 0 or 1."); 5805 f->dedicated = dedicated; 5806 } else 5807 /* Just toggle it, rather than on or off. */ 5808 f->dedicated = !(f->dedicated); 5809 5810 return cmdret_new(RET_SUCCESS, "Consider this frame %s.", 5811 f->dedicated ? "chaste" : "promiscuous"); 5812} 5813 5814cmdret * 5815cmd_putsel(int interactive, struct cmdarg **args) 5816{ 5817 set_selection(ARG_STRING(0)); 5818 return cmdret_new(RET_SUCCESS, NULL); 5819} 5820 5821cmdret * 5822cmd_getsel(int interactive, struct cmdarg **args) 5823{ 5824 char *sel; 5825 cmdret *ret; 5826 sel = get_selection(); 5827 if (sel != NULL) { 5828 ret = cmdret_new(RET_SUCCESS, "%s", sel); 5829 free(sel); 5830 return ret; 5831 } 5832 5833 return cmdret_new(RET_FAILURE, "getsel: no X11 selection"); 5834} 5835 5836cmdret * 5837cmd_vmove(int interactive, struct cmdarg **args) 5838{ 5839 rp_vscreen *v; 5840 rp_window *w; 5841 5842 if ((w = current_window()) == NULL) 5843 return cmdret_new(RET_FAILURE, "vmove: no focused window"); 5844 5845 if (!(v = find_vscreen(ARG_STRING(0)))) 5846 return cmdret_new(RET_FAILURE, "vmove: invalid vscreen"); 5847 5848 vscreen_move_window(v, w); 5849 set_current_vscreen(v); 5850 set_active_window(w); 5851 return cmdret_new(RET_SUCCESS, NULL); 5852} 5853 5854cmdret * 5855cmd_stick(int interactive, struct cmdarg **args) 5856{ 5857 rp_window *cur = current_window(); 5858 5859 if (cur == NULL) 5860 return cmdret_new(RET_FAILURE, NULL); 5861 5862 cur->sticky_frame = cur->frame_number; 5863 5864 return cmdret_new(RET_SUCCESS, NULL); 5865} 5866 5867cmdret * 5868cmd_unstick(int interactive, struct cmdarg **args) 5869{ 5870 rp_window *cur = current_window(); 5871 5872 if (cur == NULL) 5873 return cmdret_new(RET_FAILURE, NULL); 5874 5875 cur->sticky_frame = EMPTY; 5876 5877 return cmdret_new(RET_SUCCESS, NULL); 5878} 5879 5880cmdret * 5881cmd_commands(int interactive, struct cmdarg **args) 5882{ 5883 struct sbuf *sb; 5884 struct user_command *cur; 5885 cmdret *ret; 5886 5887 sb = sbuf_new(0); 5888 list_for_each_entry(cur, &user_commands, node) { 5889 sbuf_printf_concat(sb, "%s\n", cur->name); 5890 } 5891 sbuf_chop(sb); 5892 5893 ret = cmdret_new(RET_SUCCESS, "%s", sbuf_get(sb)); 5894 sbuf_free(sb); 5895 return ret; 5896}