jcs ratpoison hax
at jcs 488 lines 14 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.gap = 0; 232 defaults.bar_x_padding = 4; 233 defaults.bar_y_padding = 0; 234 defaults.bar_location = NorthEastGravity; 235 defaults.bar_timeout = 5; 236 defaults.bar_border_width = 1; 237 defaults.bar_in_padding = 0; 238 defaults.bar_sticky = 0; 239 defaults.bar_sticky_bleed = 30; 240 241 defaults.frame_indicator_timeout = 1; 242 defaults.frame_resize_unit = 10; 243 244 defaults.padding_left = 0; 245 defaults.padding_right = 0; 246 defaults.padding_top = 0; 247 defaults.padding_bottom = 0; 248 249#ifdef USE_XFT_FONT 250 defaults.font_string = xstrdup (DEFAULT_XFT_FONT); 251#else 252 /* Attempt to load a font */ 253 defaults.font = load_query_font_set (dpy, DEFAULT_FONT); 254 if (defaults.font == NULL) 255 { 256 PRINT_ERROR (("ratpoison: Cannot load font %s.\n", DEFAULT_FONT)); 257 defaults.font = load_query_font_set (dpy, BACKUP_FONT); 258 if (defaults.font == NULL) 259 { 260 PRINT_ERROR (("ratpoison: Cannot load backup font %s . You lose.\n", BACKUP_FONT)); 261 exit (EXIT_FAILURE); 262 } 263 } 264 265 defaults.font_string = xstrdup (DEFAULT_FONT); 266 set_extents_of_fontset (defaults.font); 267#endif 268 269 defaults.fgcolor_string = xstrdup ("black"); 270 defaults.bgcolor_string = xstrdup ("white"); 271 defaults.fwcolor_string = xstrdup ("black"); 272 defaults.bwcolor_string = xstrdup ("black"); 273 274 defaults.wait_for_key_cursor = 1; 275 276 defaults.window_fmt = xstrdup ("%n%s%t"); 277 defaults.info_fmt = xstrdup ("(%H, %W) %n(%t)"); 278 defaults.frame_fmt = xstrdup ("Current Frame"); 279 defaults.resize_fmt = xstrdup ("Resize Frame (%H, %W)"); 280 281 defaults.win_name = WIN_NAME_TITLE; 282 defaults.startup_message = 1; 283 defaults.warp = 0; 284 defaults.window_list_style = STYLE_COLUMN; 285 286 defaults.history_size = 20; 287 defaults.history_compaction = True; 288 defaults.history_expansion = False; 289 defaults.frame_selectors = xstrdup (""); 290 defaults.maxundos = 20; 291 292 defaults.virtuals = 5; 293 294 defaults.ignorehints = 0; 295} 296 297int 298main (int argc, char *argv[]) 299{ 300 int c; 301 char **cmd = NULL; 302 int cmd_count = 0; 303 char *display = NULL; 304 unsigned char interactive = 0; 305 char *alt_rcfile = NULL; 306 307 setlocale (LC_CTYPE, ""); 308 utf8_check_locale(); 309 310 if (XSupportsLocale ()) 311 { 312 if (!XSetLocaleModifiers ("")) 313 PRINT_ERROR (("Couldn't set X locale modifiers.\n")); 314 } 315 else 316 PRINT_ERROR (("X doesn't seem to support your locale.\n")); 317 318 /* Parse the arguments */ 319 myargv = argv; 320 while (1) 321 { 322 c = getopt_long (argc, argv, ratpoison_opts, ratpoison_longopts, NULL); 323 if (c == -1) break; 324 325 switch (c) 326 { 327 case 'h': 328 print_help (); 329 break; 330 case 'v': 331 print_version (); 332 break; 333 case 'c': 334 cmd = xrealloc (cmd, sizeof (char *) * (cmd_count + 1)); 335 cmd[cmd_count++] = xstrdup (optarg); 336 break; 337 case 'd': 338 display = optarg; 339 break; 340 case 'i': 341 interactive = 1; 342 break; 343 case 'f': 344 alt_rcfile = optarg; 345 break; 346 347 default: 348 exit (EXIT_FAILURE); 349 } 350 } 351 352 /* Report extra unparsed arguments. */ 353 if (optind < argc) 354 { 355 fprintf (stderr, "Error: junk arguments: "); 356 while (optind < argc) 357 fprintf (stderr, "%s ", argv[optind++]); 358 fputc ('\n', stderr); 359 exit (EXIT_FAILURE); 360 } 361 362 if (!(dpy = XOpenDisplay (display))) 363 { 364 fprintf (stderr, "Can't open display\n"); 365 exit (EXIT_FAILURE); 366 } 367 368 set_close_on_exec (ConnectionNumber (dpy)); 369 370 /* Set ratpoison specific Atoms. */ 371 rp_command = XInternAtom (dpy, "RP_COMMAND", False); 372 rp_command_request = XInternAtom (dpy, "RP_COMMAND_REQUEST", False); 373 rp_command_result = XInternAtom (dpy, "RP_COMMAND_RESULT", False); 374 rp_selection = XInternAtom (dpy, "RP_SELECTION", False); 375 376 /* TEXT atoms */ 377 xa_string = XA_STRING; 378 xa_compound_text = XInternAtom(dpy, "COMPOUND_TEXT", False); 379 xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False); 380 381 if (cmd_count > 0) 382 { 383 int j, exit_status = EXIT_SUCCESS; 384 385 for (j = 0; j < cmd_count; j++) 386 { 387 if (!send_command (interactive, (unsigned char *)cmd[j])) 388 exit_status = EXIT_FAILURE; 389 free (cmd[j]); 390 } 391 392 free (cmd); 393 XCloseDisplay (dpy); 394 return exit_status; 395 } 396 397 /* Set our Atoms */ 398 wm_name = XInternAtom(dpy, "WM_NAME", False); 399 wm_state = XInternAtom(dpy, "WM_STATE", False); 400 wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); 401 wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 402 wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 403 wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); 404 wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); 405 406 /* netwm atoms */ 407 _net_wm_pid = XInternAtom(dpy, "_NET_WM_PID", False); 408 PRINT_DEBUG (("_NET_WM_PID = %ld\n", _net_wm_pid)); 409 _net_supported = XInternAtom(dpy, "_NET_SUPPORTED", False); 410 PRINT_DEBUG (("_NET_SUPPORTED = %ld\n", _net_supported)); 411 _net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 412 _net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 413 _net_wm_window_type_dialog = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); 414 _net_wm_window_type_tooltip = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); 415 _net_wm_window_type_dock = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); 416 _net_wm_window_type_desktop = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); 417 _net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False); 418 _net_workarea = XInternAtom(dpy, "_NET_WORKAREA", False); 419 420 /* Setup signal handlers. */ 421 XSetErrorHandler(handler); 422 set_sig_handler (SIGALRM, alrm_handler); 423 set_sig_handler (SIGTERM, sighandler); 424 set_sig_handler (SIGINT, sighandler); 425 set_sig_handler (SIGHUP, hup_handler); 426 set_sig_handler (SIGCHLD, chld_handler); 427 428 /* Add RATPOISON to the environment */ 429 putenv (xsprintf ("RATPOISON=%s", argv[0])); 430 431 /* Setup ratpoison's internal structures */ 432 init_defaults (); 433 init_xkb (); 434 init_groups (); 435 init_window_stuff (); 436 init_xrandr (); 437 init_screens (); 438 439 init_frame_lists (); 440 update_modifier_map (); 441 init_user_commands(); 442 initialize_default_keybindings (); 443 history_load (); 444 445 scanwins (); 446 447 if (read_startup_files (alt_rcfile) == -1) 448 return EXIT_FAILURE; 449 450 /* Indicate to the user that ratpoison has booted. */ 451 if (defaults.startup_message) 452 show_welcome_message(); 453 454 /* If no window has focus, give the key_window focus. */ 455 if (current_window() == NULL) 456 set_window_focus (rp_current_screen->key_window); 457 458 listen_for_events (); 459 460 return EXIT_SUCCESS; 461} 462 463void 464set_extents_of_fontset (XFontSet font) 465{ 466 XFontSetExtents *extent; 467 extent = XExtentsOfFontSet(font); 468 rp_font_ascent = extent->max_logical_extent.height * 9 / 10; 469 rp_font_descent = extent->max_logical_extent.height / 5; 470 rp_font_width = extent->max_logical_extent.width; 471} 472 473XFontSet load_query_font_set (Display *disp, const char *fontset_name) 474{ 475 XFontSet fontset; 476 int missing_charset_count; 477 char **missing_charset_list; 478 char *def_string; 479 480 fontset = XCreateFontSet(disp, fontset_name, 481 &missing_charset_list, &missing_charset_count, 482 &def_string); 483 if (missing_charset_count) { 484 PRINT_DEBUG (("Missing charsets in FontSet(%s) creation.\n", fontset_name)); 485 XFreeStringList(missing_charset_list); 486 } 487 return fontset; 488}