jcs ratpoison hax
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}