calmwm.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * calmwm - the calm window manager
  3. *
  4. * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. *
  18. * $OpenBSD: calmwm.c,v 1.93 2015/01/19 14:54:16 okan Exp $
  19. */
  20. #include <sys/types.h>
  21. #include <sys/queue.h>
  22. #include <sys/wait.h>
  23. #include <err.h>
  24. #include <errno.h>
  25. #include <getopt.h>
  26. #include <limits.h>
  27. #include <locale.h>
  28. #include <pwd.h>
  29. #include <signal.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <unistd.h>
  34. #include "calmwm.h"
  35. Display *X_Dpy;
  36. Time Last_Event_Time = CurrentTime;
  37. Atom cwmh[CWMH_NITEMS];
  38. Atom ewmh[EWMH_NITEMS];
  39. struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
  40. int HasRandr, Randr_ev;
  41. struct conf Conf;
  42. const char *homedir;
  43. volatile sig_atomic_t cwm_status;
  44. static void sighdlr(int);
  45. static int x_errorhandler(Display *, XErrorEvent *);
  46. static void x_init(const char *);
  47. static void x_restart(char **);
  48. static void x_teardown(void);
  49. static int x_wmerrorhandler(Display *, XErrorEvent *);
  50. int
  51. main(int argc, char **argv)
  52. {
  53. const char *conf_file = NULL;
  54. char *conf_path, *display_name = NULL;
  55. char **cwm_argv;
  56. int ch;
  57. struct passwd *pw;
  58. if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  59. warnx("no locale support");
  60. mbtowc(NULL, NULL, MB_CUR_MAX);
  61. cwm_argv = argv;
  62. while ((ch = getopt(argc, argv, "c:d:")) != -1) {
  63. switch (ch) {
  64. case 'c':
  65. conf_file = optarg;
  66. break;
  67. case 'd':
  68. display_name = optarg;
  69. break;
  70. default:
  71. usage();
  72. }
  73. }
  74. argc -= optind;
  75. argv += optind;
  76. if (signal(SIGCHLD, sighdlr) == SIG_ERR)
  77. err(1, "signal");
  78. if ((homedir = getenv("HOME")) == NULL || *homedir == '\0') {
  79. pw = getpwuid(getuid());
  80. if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
  81. homedir = pw->pw_dir;
  82. else
  83. homedir = "/";
  84. }
  85. if (conf_file == NULL)
  86. xasprintf(&conf_path, "%s/%s", homedir, CONFFILE);
  87. else
  88. conf_path = xstrdup(conf_file);
  89. if (access(conf_path, R_OK) != 0) {
  90. if (conf_file != NULL)
  91. warn("%s", conf_file);
  92. free(conf_path);
  93. conf_path = NULL;
  94. }
  95. conf_init(&Conf);
  96. if (conf_path && (parse_config(conf_path, &Conf) == -1))
  97. warnx("config file %s has errors", conf_path);
  98. free(conf_path);
  99. x_init(display_name);
  100. cwm_status = CWM_RUNNING;
  101. while (cwm_status == CWM_RUNNING)
  102. xev_process();
  103. x_teardown();
  104. if (cwm_status == CWM_RESTART)
  105. x_restart(cwm_argv);
  106. return(0);
  107. }
  108. static void
  109. x_init(const char *dpyname)
  110. {
  111. int i;
  112. if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
  113. errx(1, "unable to open display \"%s\"", XDisplayName(dpyname));
  114. XSetErrorHandler(x_wmerrorhandler);
  115. XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
  116. XSync(X_Dpy, False);
  117. XSetErrorHandler(x_errorhandler);
  118. HasRandr = XRRQueryExtension(X_Dpy, &Randr_ev, &i);
  119. conf_atoms();
  120. conf_cursor(&Conf);
  121. for (i = 0; i < ScreenCount(X_Dpy); i++)
  122. screen_init(i);
  123. }
  124. static void
  125. x_restart(char **args)
  126. {
  127. (void)setsid();
  128. (void)execvp(args[0], args);
  129. }
  130. static void
  131. x_teardown(void)
  132. {
  133. struct screen_ctx *sc;
  134. unsigned int i;
  135. conf_clear(&Conf);
  136. TAILQ_FOREACH(sc, &Screenq, entry) {
  137. for (i = 0; i < CWM_COLOR_NITEMS; i++)
  138. XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
  139. DefaultColormap(X_Dpy, sc->which),
  140. &sc->xftcolor[i]);
  141. XftDrawDestroy(sc->xftdraw);
  142. XftFontClose(X_Dpy, sc->xftfont);
  143. XUnmapWindow(X_Dpy, sc->menuwin);
  144. XDestroyWindow(X_Dpy, sc->menuwin);
  145. XUngrabKey(X_Dpy, AnyKey, AnyModifier, sc->rootwin);
  146. }
  147. XUngrabPointer(X_Dpy, CurrentTime);
  148. XUngrabKeyboard(X_Dpy, CurrentTime);
  149. for (i = 0; i < CF_NITEMS; i++)
  150. XFreeCursor(X_Dpy, Conf.cursor[i]);
  151. XSync(X_Dpy, False);
  152. XSetInputFocus(X_Dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  153. XCloseDisplay(X_Dpy);
  154. }
  155. static int
  156. x_wmerrorhandler(Display *dpy, XErrorEvent *e)
  157. {
  158. errx(1, "root window unavailable - perhaps another wm is running?");
  159. return(0);
  160. }
  161. static int
  162. x_errorhandler(Display *dpy, XErrorEvent *e)
  163. {
  164. #ifdef DEBUG
  165. char msg[80], number[80], req[80];
  166. XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
  167. (void)snprintf(number, sizeof(number), "%d", e->request_code);
  168. XGetErrorDatabaseText(X_Dpy, "XRequest", number,
  169. "<unknown>", req, sizeof(req));
  170. warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg);
  171. #endif
  172. return(0);
  173. }
  174. static void
  175. sighdlr(int sig)
  176. {
  177. pid_t pid;
  178. int save_errno = errno, status;
  179. switch (sig) {
  180. case SIGCHLD:
  181. /* Collect dead children. */
  182. while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0 ||
  183. (pid < 0 && errno == EINTR))
  184. ;
  185. break;
  186. }
  187. errno = save_errno;
  188. }
  189. __dead void
  190. usage(void)
  191. {
  192. extern char *__progname;
  193. (void)fprintf(stderr, "usage: %s [-c file] [-d display]\n",
  194. __progname);
  195. exit(1);
  196. }