PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/cmd/rio/main.c

https://bitbucket.org/rsc/plan9port/
C | 542 lines | 469 code | 63 blank | 10 comment | 109 complexity | 3062d10f16aa0d73040d25613b9dc46e MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, Unlicense
  1. /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <errno.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <X11/X.h>
  8. #include <X11/Xos.h>
  9. #include <X11/Xlib.h>
  10. #include <X11/Xutil.h>
  11. #include <X11/Xatom.h>
  12. #ifdef SHAPE
  13. #include <X11/extensions/shape.h>
  14. #endif
  15. #include "dat.h"
  16. #include "fns.h"
  17. #include "patchlevel.h"
  18. char *version[] =
  19. {
  20. "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 0
  21. };
  22. Display *dpy;
  23. ScreenInfo *screens;
  24. int initting;
  25. XFontStruct *font;
  26. int nostalgia;
  27. char **myargv;
  28. char *termprog;
  29. char *shell;
  30. Bool shape;
  31. int _border = 4;
  32. int _corner = 25;
  33. int _inset = 1;
  34. int curtime;
  35. int debug;
  36. int signalled;
  37. int scrolling;
  38. int num_screens;
  39. int solidsweep = 0;
  40. int numvirtuals = 0;
  41. int ffm = 0;
  42. Atom exit_rio;
  43. Atom restart_rio;
  44. Atom wm_state;
  45. Atom wm_change_state;
  46. Atom wm_protocols;
  47. Atom wm_delete;
  48. Atom wm_take_focus;
  49. Atom wm_lose_focus;
  50. Atom wm_colormaps;
  51. Atom _rio_running;
  52. Atom _rio_hold_mode;
  53. Atom wm_state_fullscreen;
  54. Atom wm_state;
  55. char *fontlist[] = {
  56. "lucm.latin1.9",
  57. "blit",
  58. "*-lucidatypewriter-bold-*-14-*-75-*",
  59. "*-lucidatypewriter-medium-*-12-*-75-*",
  60. "9x15bold",
  61. "fixed",
  62. "*",
  63. 0
  64. };
  65. void
  66. usage(void)
  67. {
  68. fprintf(stderr, "usage: rio [-grey] [-font fname] [-s] [-term prog] [-version] [-virtuals num] [exit|restart]\n");
  69. exit(1);
  70. }
  71. int
  72. main(int argc, char *argv[])
  73. {
  74. int i, background, do_exit, do_restart;
  75. char *fname;
  76. int shape_event;
  77. #ifdef SHAPE
  78. int dummy;
  79. #endif
  80. shape_event = 0;
  81. myargv = argv; /* for restart */
  82. do_exit = do_restart = 0;
  83. background = 0;
  84. font = 0;
  85. fname = 0;
  86. for(i = 1; i < argc; i++)
  87. if(strcmp(argv[i], "-nostalgia") == 0)
  88. nostalgia++;
  89. else if(strcmp(argv[i], "-grey") == 0)
  90. background = 1;
  91. else if(strcmp(argv[i], "-debug") == 0)
  92. debug++;
  93. /*
  94. else if(strcmp(argv[i], "-ffm") == 0)
  95. ffm++;
  96. */
  97. else if(strcmp(argv[i], "-font") == 0 && i+1<argc){
  98. i++;
  99. fname = argv[i];
  100. }
  101. else if(strcmp(argv[i], "-term") == 0 && i+1<argc)
  102. termprog = argv[++i];
  103. else if(strcmp(argv[i], "-virtuals") == 0 && i+1<argc){
  104. numvirtuals = atoi(argv[++i]);
  105. if(numvirtuals < 0 || numvirtuals > 12){
  106. fprintf(stderr, "rio: wrong number of virtual displays, defaulting to 4\n");
  107. numvirtuals = 4;
  108. }
  109. } else if(strcmp(argv[i], "-version") == 0){
  110. fprintf(stderr, "%s", version[0]);
  111. if(PATCHLEVEL > 0)
  112. fprintf(stderr, "; patch level %d", PATCHLEVEL);
  113. fprintf(stderr, "\n");
  114. exit(0);
  115. }
  116. else if(strcmp(argv[i], "-s") == 0){
  117. scrolling = 1;
  118. }
  119. else if(argv[i][0] == '-')
  120. usage();
  121. else
  122. break;
  123. for(; i < argc; i++)
  124. if(strcmp(argv[i], "exit") == 0)
  125. do_exit++;
  126. else if(strcmp(argv[i], "restart") == 0)
  127. do_restart++;
  128. else
  129. usage();
  130. if(do_exit && do_restart)
  131. usage();
  132. shell = (char *)getenv("SHELL");
  133. if(shell == NULL)
  134. shell = DEFSHELL;
  135. dpy = XOpenDisplay("");
  136. if(dpy == 0)
  137. fatal("can't open display");
  138. initting = 1;
  139. XSetErrorHandler(handler);
  140. if(signal(SIGTERM, sighandler) == SIG_IGN)
  141. signal(SIGTERM, SIG_IGN);
  142. if(signal(SIGINT, sighandler) == SIG_IGN)
  143. signal(SIGINT, SIG_IGN);
  144. if(signal(SIGHUP, sighandler) == SIG_IGN)
  145. signal(SIGHUP, SIG_IGN);
  146. exit_rio = XInternAtom(dpy, "9WM_EXIT", False);
  147. restart_rio = XInternAtom(dpy, "9WM_RESTART", False);
  148. curtime = -1; /* don't care */
  149. if(do_exit){
  150. sendcmessage(DefaultRootWindow(dpy), exit_rio, 0L, 1, 1);
  151. XSync(dpy, False);
  152. exit(0);
  153. }
  154. if(do_restart){
  155. sendcmessage(DefaultRootWindow(dpy), restart_rio, 0L, 1, 1);
  156. XSync(dpy, False);
  157. exit(0);
  158. }
  159. if(0) XSynchronize(dpy, True);
  160. wm_state = XInternAtom(dpy, "WM_STATE", False);
  161. wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
  162. wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
  163. wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  164. wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
  165. wm_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False);
  166. wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
  167. _rio_running = XInternAtom(dpy, "_9WM_RUNNING", False);
  168. _rio_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
  169. wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
  170. wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
  171. if(fname != 0)
  172. if((font = XLoadQueryFont(dpy, fname)) == 0)
  173. fprintf(stderr, "rio: warning: can't load font %s\n", fname);
  174. if(font == 0){
  175. i = 0;
  176. for(;;){
  177. fname = fontlist[i++];
  178. if(fname == 0){
  179. fprintf(stderr, "rio: warning: can't find a font\n");
  180. break;
  181. }
  182. font = XLoadQueryFont(dpy, fname);
  183. if(font != 0)
  184. break;
  185. }
  186. }
  187. if(nostalgia){
  188. _border--;
  189. _inset--;
  190. }
  191. #ifdef SHAPE
  192. shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
  193. #endif
  194. num_screens = ScreenCount(dpy);
  195. screens = (ScreenInfo *)malloc(sizeof(ScreenInfo) * num_screens);
  196. for(i = 0; i < num_screens; i++)
  197. initscreen(&screens[i], i, background);
  198. initb2menu(numvirtuals);
  199. /* set selection so that 9term knows we're running */
  200. curtime = CurrentTime;
  201. XSetSelectionOwner(dpy, _rio_running, screens[0].menuwin, timestamp());
  202. XSync(dpy, False);
  203. initting = 0;
  204. nofocus();
  205. for(i = 0; i < num_screens; i++)
  206. scanwins(&screens[i]);
  207. keysetup();
  208. mainloop(shape_event);
  209. return 0;
  210. }
  211. void
  212. initscreen(ScreenInfo *s, int i, int background)
  213. {
  214. char *ds, *colon, *dot1;
  215. unsigned long mask;
  216. unsigned long gmask;
  217. XGCValues gv;
  218. XSetWindowAttributes attr;
  219. XVisualInfo xvi;
  220. XSetWindowAttributes attrs;
  221. s->num = i;
  222. s->root = RootWindow(dpy, i);
  223. s->def_cmap = DefaultColormap(dpy, i);
  224. s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i));
  225. s->depth = DefaultDepth(dpy, i);
  226. /*
  227. * Figure out underlying screen format.
  228. */
  229. if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi)
  230. || XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){
  231. s->vis = xvi.visual;
  232. s->depth = 16;
  233. }
  234. else
  235. if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi)
  236. || XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){
  237. s->vis = xvi.visual;
  238. s->depth = 15;
  239. }
  240. else
  241. if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi)
  242. || XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){
  243. s->vis = xvi.visual;
  244. s->depth = 24;
  245. }
  246. else
  247. if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi)
  248. || XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){
  249. s->vis = xvi.visual;
  250. s->depth = 8;
  251. }
  252. else{
  253. s->depth = DefaultDepth(dpy, i);
  254. if(s->depth != 8){
  255. fprintf(stderr, "can't understand depth %d screen", s->depth);
  256. exit(1);
  257. }
  258. s->vis = DefaultVisual(dpy, i);
  259. }
  260. if(DefaultDepth(dpy, i) != s->depth){
  261. s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone);
  262. }
  263. ds = DisplayString(dpy);
  264. colon = rindex(ds, ':');
  265. if(colon && num_screens > 1){
  266. strcpy(s->display, "DISPLAY=");
  267. strcat(s->display, ds);
  268. colon = s->display + 8 + (colon - ds); /* use version in buf */
  269. dot1 = index(colon, '.'); /* first period after colon */
  270. if(!dot1)
  271. dot1 = colon + strlen(colon); /* if not there, append */
  272. sprintf(dot1, ".%d", i);
  273. }
  274. else
  275. s->display[0] = '\0';
  276. s->black = BlackPixel(dpy, i);
  277. s->white = WhitePixel(dpy, i);
  278. s->activeholdborder = colorpixel(dpy, s, s->depth, 0x000099, s->white);
  279. s->inactiveholdborder = colorpixel(dpy, s, s->depth, 0x005DBB, s->black);
  280. s->activeborder = colorpixel(dpy, s, s->depth, 0x55AAAA, s->black);
  281. s->inactiveborder = colorpixel(dpy, s, s->depth, 0x9EEEEE, s->white);
  282. s->red = colorpixel(dpy, s, s->depth, 0xDD0000, s->white);
  283. s->width = WidthOfScreen(ScreenOfDisplay(dpy, i));
  284. s->height = HeightOfScreen(ScreenOfDisplay(dpy, i));
  285. s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i));
  286. s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(dpy, i));
  287. gv.foreground = s->black^s->white;
  288. gv.background = s->white;
  289. gv.function = GXxor;
  290. gv.line_width = 0;
  291. gv.subwindow_mode = IncludeInferiors;
  292. gmask = GCForeground | GCBackground | GCFunction | GCLineWidth
  293. | GCSubwindowMode;
  294. if(font != 0){
  295. gv.font = font->fid;
  296. gmask |= GCFont;
  297. }
  298. s->gc = XCreateGC(dpy, s->root, gmask, &gv);
  299. gv.function = GXcopy;
  300. s->gccopy = XCreateGC(dpy, s->root, gmask, &gv);
  301. gv.foreground = s->red;
  302. s->gcred = XCreateGC(dpy, s->root, gmask, &gv);
  303. gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
  304. s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv);
  305. initcurs(s);
  306. attr.cursor = s->arrow;
  307. attr.event_mask = SubstructureRedirectMask
  308. | SubstructureNotifyMask | ColormapChangeMask
  309. | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask
  310. | KeyPressMask | EnterWindowMask;
  311. mask = CWCursor|CWEventMask;
  312. XChangeWindowAttributes(dpy, s->root, mask, &attr);
  313. XSync(dpy, False);
  314. if(background){
  315. XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
  316. XClearWindow(dpy, s->root);
  317. } else
  318. system("xsetroot -solid grey30");
  319. attrs.border_pixel = colorpixel(dpy, s, s->depth, 0x88CC88, s->black);
  320. attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
  321. attrs.colormap = s->def_cmap;
  322. s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 2,
  323. s->depth,
  324. CopyFromParent,
  325. s->vis,
  326. CWBackPixel | CWBorderPixel | CWColormap,
  327. &attrs
  328. );
  329. gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
  330. s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv);
  331. gv.foreground = colorpixel(dpy, s, s->depth, 0x448844, s->black);
  332. s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
  333. gv.foreground = s->black;
  334. gv.background = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
  335. s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv);
  336. gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
  337. gv.background = colorpixel(dpy, s, s->depth, 0x448844, s->black);
  338. s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
  339. attrs.border_pixel = s->red;
  340. attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
  341. attrs.colormap = s->def_cmap;
  342. s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4,
  343. s->depth,
  344. CopyFromParent,
  345. s->vis,
  346. CWBackPixel | CWBorderPixel | CWColormap,
  347. &attrs
  348. );
  349. }
  350. ScreenInfo*
  351. getscreen(Window w)
  352. {
  353. int i;
  354. for(i = 0; i < num_screens; i++)
  355. if(screens[i].root == w)
  356. return &screens[i];
  357. return 0;
  358. }
  359. Time
  360. timestamp(void)
  361. {
  362. XEvent ev;
  363. if(curtime == CurrentTime){
  364. XChangeProperty(dpy, screens[0].root, _rio_running, _rio_running, 8,
  365. PropModeAppend, (unsigned char *)"", 0);
  366. XMaskEvent(dpy, PropertyChangeMask, &ev);
  367. curtime = ev.xproperty.time;
  368. }
  369. return curtime;
  370. }
  371. void
  372. sendcmessage(Window w, Atom a, long x, int isroot, int usemask)
  373. {
  374. XEvent ev;
  375. int status;
  376. long mask;
  377. memset(&ev, 0, sizeof(ev));
  378. ev.xclient.type = ClientMessage;
  379. ev.xclient.window = w;
  380. ev.xclient.message_type = a;
  381. ev.xclient.format = 32;
  382. ev.xclient.data.l[0] = x;
  383. ev.xclient.data.l[1] = timestamp();
  384. mask = 0;
  385. if(usemask){
  386. mask |= KeyPressMask; /* seems to be necessary */
  387. if(isroot)
  388. mask |= SubstructureRedirectMask; /* magic! */
  389. else
  390. mask |= ExposureMask; /* not really correct but so be it */
  391. }
  392. status = XSendEvent(dpy, w, False, mask, &ev);
  393. if(status == 0)
  394. fprintf(stderr, "rio: sendcmessage failed\n");
  395. }
  396. void
  397. sendconfig(Client *c)
  398. {
  399. XConfigureEvent ce;
  400. ce.type = ConfigureNotify;
  401. ce.event = c->window;
  402. ce.window = c->window;
  403. ce.x = c->x;
  404. ce.y = c->y;
  405. ce.width = c->dx;
  406. ce.height = c->dy;
  407. ce.border_width = c->border;
  408. ce.above = None;
  409. ce.override_redirect = 0;
  410. XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
  411. }
  412. void
  413. sighandler(void)
  414. {
  415. signalled = 1;
  416. }
  417. void
  418. getevent(XEvent *e)
  419. {
  420. int fd;
  421. fd_set rfds;
  422. struct timeval t;
  423. if(!signalled){
  424. if(QLength(dpy) > 0){
  425. XNextEvent(dpy, e);
  426. return;
  427. }
  428. fd = ConnectionNumber(dpy);
  429. FD_ZERO(&rfds);
  430. FD_SET(fd, &rfds);
  431. t.tv_sec = t.tv_usec = 0;
  432. if(select(fd+1, &rfds, NULL, NULL, &t) == 1){
  433. XNextEvent(dpy, e);
  434. return;
  435. }
  436. XFlush(dpy);
  437. FD_SET(fd, &rfds);
  438. if(select(fd+1, &rfds, NULL, NULL, NULL) == 1){
  439. XNextEvent(dpy, e);
  440. return;
  441. }
  442. if(errno != EINTR || !signalled){
  443. perror("rio: select failed");
  444. exit(1);
  445. }
  446. }
  447. fprintf(stderr, "rio: exiting on signal\n");
  448. cleanup();
  449. exit(1);
  450. }
  451. void
  452. cleanup(void)
  453. {
  454. Client *c, *cc[2], *next;
  455. XWindowChanges wc;
  456. int i;
  457. /* order of un-reparenting determines final stacking order... */
  458. cc[0] = cc[1] = 0;
  459. for(c = clients; c; c = next){
  460. next = c->next;
  461. i = normal(c);
  462. c->next = cc[i];
  463. cc[i] = c;
  464. }
  465. for(i = 0; i < 2; i++){
  466. for(c = cc[i]; c; c = c->next){
  467. if(!withdrawn(c)){
  468. XReparentWindow(dpy, c->window, c->screen->root,
  469. c->x, c->y);
  470. }
  471. wc.border_width = c->border;
  472. XConfigureWindow(dpy, c->window, CWBorderWidth, &wc);
  473. }
  474. }
  475. XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp());
  476. for(i = 0; i < num_screens; i++)
  477. cmapnofocus(&screens[i]);
  478. XCloseDisplay(dpy);
  479. }