jcs ratpoison hax
at master 475 lines 13 kB view raw
1/* Ratpoison. 2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 3 * 4 * This file is part of ratpoison. 5 * 6 * ratpoison is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * ratpoison is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this software; see the file COPYING. If not, write to 18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 19 * Boston, MA 02111-1307 USA 20 */ 21 22#include <X11/X.h> 23#include <X11/Xlib.h> 24#include <X11/Xutil.h> 25#include <X11/Xatom.h> 26#include <X11/Xproto.h> 27#include <X11/cursorfont.h> 28 29#include <errno.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <signal.h> 33#include <unistd.h> 34#include <getopt.h> 35#include <string.h> 36#include <sys/wait.h> 37#include <ctype.h> 38 39#include "ratpoison.h" 40 41/* Command line options */ 42static struct option ratpoison_longopts[] = 43 { {"help", no_argument, 0, 'h'}, 44 {"interactive", no_argument, 0, 'i'}, 45 {"version", no_argument, 0, 'v'}, 46 {"command", required_argument, 0, 'c'}, 47 {"display", required_argument, 0, 'd'}, 48 {"file", required_argument, 0, 'f'}, 49 {0, 0, 0, 0} }; 50 51static char ratpoison_opts[] = "hvic:d:s:f:"; 52 53static void 54sighandler (int signum UNUSED) 55{ 56 kill_signalled++; 57} 58 59static void 60hup_handler (int signum UNUSED) 61{ 62 hup_signalled++; 63} 64 65static void 66alrm_handler (int signum UNUSED) 67{ 68 alarm_signalled++; 69} 70 71static int 72handler (Display *d, XErrorEvent *e) 73{ 74 char error_msg[100]; 75 76 if (e->request_code == X_ChangeWindowAttributes && e->error_code == BadAccess) 77 { 78 fprintf(stderr, "ratpoison: There can be only ONE.\n"); 79 exit(EXIT_FAILURE); 80 } 81 82#ifdef IGNORE_BADWINDOW 83 return 0; 84#else 85 if (ignore_badwindow && e->error_code == BadWindow) return 0; 86#endif 87 88 XGetErrorText (d, e->error_code, error_msg, sizeof (error_msg)); 89 fprintf (stderr, "ratpoison: ERROR: %s!\n", error_msg); 90 91 /* If there is already an error to report, replace it with this new 92 one. */ 93 free (rp_error_msg); 94 rp_error_msg = xstrdup (error_msg); 95 96 return 0; 97} 98 99static void 100print_version (void) 101{ 102 printf ("%s %s\n", PACKAGE, VERSION); 103 printf ("Copyright (C) 2000-2008 Shawn Betts\n\n"); 104 105 exit (EXIT_SUCCESS); 106} 107 108static void 109print_help (void) 110{ 111 printf ("Help for %s %s\n\n", PACKAGE, VERSION); 112 printf ("-h, --help Display this help screen\n"); 113 printf ("-v, --version Display the version\n"); 114 printf ("-d, --display <dpy> Set the X display to use\n"); 115 printf ("-c, --command <cmd> Send ratpoison a colon-command\n"); 116 printf ("-i, --interactive Execute commands in interactive mode\n"); 117 printf ("-f, --file <file> Specify an alternative configuration file\n\n"); 118 119 printf ("Report bugs to %s\n\n", PACKAGE_BUGREPORT); 120 121 exit (EXIT_SUCCESS); 122} 123 124static int 125read_startup_files (const char *alt_rcfile) 126{ 127 FILE *fileptr = NULL; 128 129 if (alt_rcfile) 130 { 131 if ((fileptr = fopen (alt_rcfile, "r")) == NULL) 132 { 133 PRINT_ERROR (("ratpoison: could not open %s (%s)\n", alt_rcfile, 134 strerror (errno))); 135 return -1; 136 } 137 } 138 else 139 { 140 const char *homedir; 141 char *filename; 142 143 /* first check $HOME/.ratpoisonrc */ 144 homedir = get_homedir (); 145 if (!homedir) 146 PRINT_ERROR (("ratpoison: no home directory!?\n")); 147 else 148 { 149 filename = xsprintf ("%s/.ratpoisonrc", homedir); 150 fileptr = fopen (filename, "r"); 151 if (fileptr == NULL && errno != ENOENT) 152 PRINT_ERROR (("ratpoison: could not open %s (%s)\n", 153 filename, strerror (errno))); 154 free (filename); 155 } 156 157 if (fileptr == NULL) 158 { 159 /* couldn't open $HOME/.ratpoisonrc, fall back on system config */ 160 filename = xsprintf ("%s/ratpoisonrc", SYSCONFDIR); 161 162 fileptr = fopen (filename, "r"); 163 if (fileptr == NULL && errno != ENOENT) 164 PRINT_ERROR (("ratpoison: could not open %s (%s)\n", 165 filename, strerror (errno))); 166 free (filename); 167 } 168 } 169 170 if (fileptr != NULL) 171 { 172 set_close_on_exec (fileno (fileptr)); 173 read_rc_file (fileptr); 174 fclose (fileptr); 175 } 176 return 0; 177} 178 179/* Odd that we spend so much code on making sure the silly welcome 180 message is correct. Oh well... */ 181static void 182show_welcome_message (void) 183{ 184 rp_action *help_action; 185 char *prefix, *help; 186 rp_keymap *map; 187 188 prefix = keysym_to_string (prefix_key.sym, prefix_key.state); 189 190 map = find_keymap (ROOT_KEYMAP); 191 192 /* Find the help key binding. */ 193 help_action = find_keybinding_by_action ("help " ROOT_KEYMAP, map); 194 if (help_action) 195 help = keysym_to_string (help_action->key, help_action->state); 196 else 197 help = NULL; 198 199 200 if (help) 201 { 202 /* A little kludge to use ? instead of `question' for the help 203 key. */ 204 if (!strcmp (help, "question")) 205 marked_message_printf (0, 0, MESSAGE_WELCOME, prefix, "?"); 206 else 207 marked_message_printf (0, 0, MESSAGE_WELCOME, prefix, help); 208 209 free (help); 210 } 211 else 212 { 213 marked_message_printf (0, 0, MESSAGE_WELCOME, prefix, ":help"); 214 } 215 216 free (prefix); 217} 218 219static void 220init_defaults (void) 221{ 222 defaults.top_kmap = xstrdup(TOP_KEYMAP); 223 224 defaults.win_gravity = NorthWestGravity; 225 defaults.trans_gravity = CenterGravity; 226 defaults.maxsize_gravity = CenterGravity; 227 228 defaults.input_window_size = 200; 229 defaults.window_border_width = 1; 230 defaults.only_border = 1; 231 defaults.bar_x_padding = 4; 232 defaults.bar_y_padding = 0; 233 defaults.bar_location = NorthEastGravity; 234 defaults.bar_timeout = 5; 235 defaults.bar_border_width = 1; 236 defaults.bar_in_padding = 0; 237 238 defaults.frame_indicator_timeout = 1; 239 defaults.frame_resize_unit = 10; 240 241 defaults.padding_left = 0; 242 defaults.padding_right = 0; 243 defaults.padding_top = 0; 244 defaults.padding_bottom = 0; 245 246#ifdef USE_XFT_FONT 247 defaults.font_string = xstrdup (DEFAULT_XFT_FONT); 248#else 249 /* Attempt to load a font */ 250 defaults.font = load_query_font_set (dpy, DEFAULT_FONT); 251 if (defaults.font == NULL) 252 { 253 PRINT_ERROR (("ratpoison: Cannot load font %s.\n", DEFAULT_FONT)); 254 defaults.font = load_query_font_set (dpy, BACKUP_FONT); 255 if (defaults.font == NULL) 256 { 257 PRINT_ERROR (("ratpoison: Cannot load backup font %s . You lose.\n", BACKUP_FONT)); 258 exit (EXIT_FAILURE); 259 } 260 } 261 262 defaults.font_string = xstrdup (DEFAULT_FONT); 263 set_extents_of_fontset (defaults.font); 264#endif 265 266 defaults.fgcolor_string = xstrdup ("black"); 267 defaults.bgcolor_string = xstrdup ("white"); 268 defaults.fwcolor_string = xstrdup ("black"); 269 defaults.bwcolor_string = xstrdup ("black"); 270 271 defaults.wait_for_key_cursor = 1; 272 273 defaults.window_fmt = xstrdup ("%n%s%t"); 274 defaults.info_fmt = xstrdup ("(%H, %W) %n(%t)"); 275 defaults.frame_fmt = xstrdup ("Current Frame"); 276 277 defaults.win_name = WIN_NAME_TITLE; 278 defaults.startup_message = 1; 279 defaults.warp = 0; 280 defaults.window_list_style = STYLE_COLUMN; 281 282 defaults.history_size = 20; 283 defaults.history_compaction = True; 284 defaults.history_expansion = False; 285 defaults.frame_selectors = xstrdup (""); 286 defaults.maxundos = 20; 287} 288 289int 290main (int argc, char *argv[]) 291{ 292 int c; 293 char **cmd = NULL; 294 int cmd_count = 0; 295 char *display = NULL; 296 unsigned char interactive = 0; 297 char *alt_rcfile = NULL; 298 299 setlocale (LC_CTYPE, ""); 300 utf8_check_locale(); 301 302 if (XSupportsLocale ()) 303 { 304 if (!XSetLocaleModifiers ("")) 305 PRINT_ERROR (("Couldn't set X locale modifiers.\n")); 306 } 307 else 308 PRINT_ERROR (("X doesn't seem to support your locale.\n")); 309 310 /* Parse the arguments */ 311 myargv = argv; 312 while (1) 313 { 314 c = getopt_long (argc, argv, ratpoison_opts, ratpoison_longopts, NULL); 315 if (c == -1) break; 316 317 switch (c) 318 { 319 case 'h': 320 print_help (); 321 break; 322 case 'v': 323 print_version (); 324 break; 325 case 'c': 326 cmd = xrealloc (cmd, sizeof (char *) * (cmd_count + 1)); 327 cmd[cmd_count++] = xstrdup (optarg); 328 break; 329 case 'd': 330 display = optarg; 331 break; 332 case 'i': 333 interactive = 1; 334 break; 335 case 'f': 336 alt_rcfile = optarg; 337 break; 338 339 default: 340 exit (EXIT_FAILURE); 341 } 342 } 343 344 /* Report extra unparsed arguments. */ 345 if (optind < argc) 346 { 347 fprintf (stderr, "Error: junk arguments: "); 348 while (optind < argc) 349 fprintf (stderr, "%s ", argv[optind++]); 350 fputc ('\n', stderr); 351 exit (EXIT_FAILURE); 352 } 353 354 if (!(dpy = XOpenDisplay (display))) 355 { 356 fprintf (stderr, "Can't open display\n"); 357 exit (EXIT_FAILURE); 358 } 359 360 set_close_on_exec (ConnectionNumber (dpy)); 361 362 /* Set ratpoison specific Atoms. */ 363 rp_command = XInternAtom (dpy, "RP_COMMAND", False); 364 rp_command_request = XInternAtom (dpy, "RP_COMMAND_REQUEST", False); 365 rp_command_result = XInternAtom (dpy, "RP_COMMAND_RESULT", False); 366 rp_selection = XInternAtom (dpy, "RP_SELECTION", False); 367 368 /* TEXT atoms */ 369 xa_string = XA_STRING; 370 xa_compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False); 371 xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False); 372 373 if (cmd_count > 0) 374 { 375 int j, exit_status = EXIT_SUCCESS; 376 377 for (j = 0; j < cmd_count; j++) 378 { 379 if (!send_command (interactive, (unsigned char *)cmd[j])) 380 exit_status = EXIT_FAILURE; 381 free (cmd[j]); 382 } 383 384 free (cmd); 385 XCloseDisplay (dpy); 386 return exit_status; 387 } 388 389 /* Set our Atoms */ 390 wm_name = XInternAtom(dpy, "WM_NAME", False); 391 wm_state = XInternAtom(dpy, "WM_STATE", False); 392 wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); 393 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 394 wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 395 wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); 396 wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); 397 398 /* netwm atoms */ 399 _net_wm_pid = XInternAtom(dpy, "_NET_WM_PID", False); 400 PRINT_DEBUG (("_NET_WM_PID = %ld\n", _net_wm_pid)); 401 _net_supported = XInternAtom(dpy, "_NET_SUPPORTED", False); 402 PRINT_DEBUG (("_NET_SUPPORTED = %ld\n", _net_supported)); 403 _net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 404 _net_wm_window_type_dialog = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); 405 _net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False); 406 407 /* Setup signal handlers. */ 408 XSetErrorHandler(handler); 409 set_sig_handler (SIGALRM, alrm_handler); 410 set_sig_handler (SIGTERM, sighandler); 411 set_sig_handler (SIGINT, sighandler); 412 set_sig_handler (SIGHUP, hup_handler); 413 set_sig_handler (SIGCHLD, chld_handler); 414 415 /* Add RATPOISON to the environment */ 416 putenv (xsprintf ("RATPOISON=%s", argv[0])); 417 418 /* Setup ratpoison's internal structures */ 419 init_defaults (); 420 init_xkb (); 421 init_groups (); 422 init_window_stuff (); 423 init_xrandr (); 424 init_screens (); 425 426 init_frame_lists (); 427 update_modifier_map (); 428 init_user_commands(); 429 initialize_default_keybindings (); 430 history_load (); 431 432 scanwins (); 433 434 if (read_startup_files (alt_rcfile) == -1) 435 return EXIT_FAILURE; 436 437 /* Indicate to the user that ratpoison has booted. */ 438 if (defaults.startup_message) 439 show_welcome_message(); 440 441 /* If no window has focus, give the key_window focus. */ 442 if (current_window() == NULL) 443 set_window_focus (rp_current_screen->key_window); 444 445 listen_for_events (); 446 447 return EXIT_SUCCESS; 448} 449 450void 451set_extents_of_fontset (XFontSet font) 452{ 453 XFontSetExtents *extent; 454 extent = XExtentsOfFontSet(font); 455 rp_font_ascent = extent->max_logical_extent.height * 9 / 10; 456 rp_font_descent = extent->max_logical_extent.height / 5; 457 rp_font_width = extent->max_logical_extent.width; 458} 459 460XFontSet load_query_font_set (Display *disp, const char *fontset_name) 461{ 462 XFontSet fontset; 463 int missing_charset_count; 464 char **missing_charset_list; 465 char *def_string; 466 467 fontset = XCreateFontSet(disp, fontset_name, 468 &missing_charset_list, &missing_charset_count, 469 &def_string); 470 if (missing_charset_count) { 471 PRINT_DEBUG (("Missing charsets in FontSet(%s) creation.\n", fontset_name)); 472 XFreeStringList(missing_charset_list); 473 } 474 return fontset; 475}