wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

wmii9menu.c (5722B)


      1 /* Licence
      2  * =======
      3  * 
      4  *   9menu is free software, and is Copyright (c) 1994 by David Hogan and
      5  *   Arnold Robbins. Permission is granted to all sentient beings to use
      6  *   this software, to make copies of it, and to distribute those copies,
      7  *   provided that:
      8  * 
      9  *       (1) the copyright and licence notices are left intact
     10  *       (2) the recipients are aware that it is free software
     11  *       (3) any unapproved changes in functionality are either
     12  *             (i) only distributed as patches
     13  *         or (ii) distributed as a new program which is not called 9menu
     14  *                 and whose documentation gives credit where it is due
     15  *       (4) the authors are not held responsible for any defects
     16  *           or shortcomings in the software, or damages caused by it.
     17  * 
     18  *   There is no warranty for this software.  Have a nice day.
     19  * 
     20  * --
     21  * Arnold Robbins
     22  * arnold@skeeve.com
     23  *
     24  * 9menu.c
     25  *
     26  * This program puts up a window that is just a menu, and executes
     27  * commands that correspond to the items selected.
     28  *
     29  * Initial idea: Arnold Robbins
     30  * Version using libXg: Matty Farrow (some ideas borrowed)
     31  * This code by: David Hogan and Arnold Robbins
     32  */
     33 
     34 /* 
     35  * Heavily modified by Kris Maglione for use with wmii.
     36  */
     37 
     38 #define IXP_NO_P9_
     39 #define IXP_P9_STRUCTS
     40 #include <fmt.h>
     41 #include <ixp.h>
     42 #include <stdarg.h>
     43 #include <stdbool.h>
     44 #include <stdio.h>
     45 #include <string.h>
     46 
     47 #include <stuff/clientutil.h>
     48 #include <stuff/util.h>
     49 #include <stuff/x.h>
     50 
     51 char version[] = "wmii9menu-"VERSION" "COPYRIGHT", ©1994 David Hogan, Arnold Robbins";
     52 
     53 static Window*	menuwin;
     54 
     55 static CTuple	cnorm;
     56 static CTuple	csel;
     57 static Font*	font;
     58 
     59 static int	wborder;
     60 
     61 static char*	initial = "";
     62 static int	cur;
     63 
     64 static char**	labels;		/* list of labels and commands */
     65 static char**	commands;
     66 static int	numitems;
     67 
     68 void usage(void);
     69 void run_menu(void);
     70 void create_window(void);
     71 void size_window(int, int);
     72 void redraw(int, int);
     73 void warpmouse(int, int);
     74 
     75 void
     76 init_screens(void) {
     77 	Rectangle *rects;
     78 	Point p;
     79 	int i, n;
     80 
     81 	rects = xinerama_screens(&n);
     82 	p = querypointer(&scr.root);
     83 	for(i=0; i < n; i++) {
     84 		if(rect_haspoint_p(rects[i], p))
     85 			break;
     86 	}
     87 	if(i == n)
     88 		i = 0;
     89 	scr.rect = rects[i];
     90 }
     91 
     92 /* main --- crack arguments, set up X stuff, run the main menu loop */
     93 
     94 int
     95 main(int argc, char **argv)
     96 {
     97 	static char *address;
     98 	char *cp;
     99 	int i;
    100 
    101 	ARGBEGIN{
    102 	case 'v':
    103 		lprint(1, "%s\n", version);
    104 		return 0;
    105 	case 'a':
    106 		address = EARGF(usage());
    107 		break;
    108 	case 'i':
    109 		initial = EARGF(usage());
    110 		break;
    111 	default:
    112 		usage();
    113 	}ARGEND;
    114 
    115 	if(argc == 0)
    116 		usage();
    117 
    118 	initdisplay();
    119 	xext_init();
    120 	init_screens();
    121 	create_window();
    122 
    123 	numitems = argc;
    124 	labels = emalloc(numitems * sizeof *labels);
    125 	commands = emalloc(numitems * sizeof *labels);
    126 
    127 	for(i = 0; i < numitems; i++) {
    128 		labels[i] = argv[i];
    129 		commands[i] = argv[i];
    130 		if((cp = strchr(labels[i], ':')) != nil) {
    131 			*cp++ = '\0';
    132 			commands[i] = cp;
    133 		}
    134 		if(strcmp(labels[i], initial) == 0)
    135 			cur = i;
    136 	}
    137 
    138 	client_init(address);
    139 
    140 	wborder = strtol(readctl("/ctl", "border "), nil, 10);
    141 	client_readconfig(&cnorm, &csel, &font);
    142 
    143 	run_menu();
    144 
    145 	XCloseDisplay(display);
    146 	return 0;
    147 }
    148 
    149 void
    150 usage(void)
    151 {
    152 	lprint(2, "usage: %s [-a <address>] [-i <arg>] <menitem>[:<command>] ...\n", argv0);
    153 	lprint(2, "       %s -v\n", argv0);
    154 	exit(0);
    155 }
    156 
    157 enum {
    158 	MouseMask = ButtonPressMask
    159 		  | ButtonReleaseMask
    160 		  | ButtonMotionMask
    161 		  | PointerMotionMask,
    162 	MenuMask = MouseMask
    163 		 | StructureNotifyMask
    164 		 | ExposureMask
    165 };
    166 
    167 void
    168 run_menu(void)
    169 {
    170 	XEvent ev;
    171 	int i, old, wide, high;
    172 
    173 	high = labelh(font);
    174 	wide = 0;
    175 	for(i = 0; i < numitems; i++)
    176 		wide = max(wide, textwidth(font, labels[i]));
    177 	wide += font->height & ~1;
    178 
    179 	size_window(wide, high);
    180 	warpmouse(wide, high);
    181 
    182 	for(;;) {
    183 		XNextEvent(display, &ev);
    184 		switch (ev.type) {
    185 		default:
    186 			lprint(2, "%s: unknown ev.type %d\n", argv0, ev.type);
    187 			break;
    188 		case ButtonRelease:
    189 			i = ev.xbutton.y / high;
    190 			if(ev.xbutton.x < 0 || ev.xbutton.x > wide)
    191 				return;
    192 			else if(i < 0 || i >= numitems)
    193 				return;
    194 
    195 			lprint(1, "%s\n", commands[i]);
    196 			return;
    197 		case ButtonPress:
    198 		case MotionNotify:
    199 			old = cur;
    200 			cur = ev.xbutton.y / high;
    201 			if(ev.xbutton.x < 0 || ev.xbutton.x > wide)
    202 				cur = ~0;
    203 			if(cur == old)
    204 				break;
    205 			redraw(high, wide);
    206 			break;
    207 		case Expose:
    208 			redraw(high, wide);
    209 			break;
    210 		case MapNotify:
    211 		case ConfigureNotify:
    212 		case MappingNotify:
    213 			break;
    214 		}
    215 	}
    216 }
    217 
    218 void
    219 create_window(void)
    220 {
    221 	WinAttr wa = { 0 };
    222 
    223 	wa.override_redirect = true;
    224 	menuwin = createwindow(&scr.root, Rect(-1, -1, 0, 0),
    225 			       scr.depth, InputOutput,
    226 			       &wa, CWOverrideRedirect);
    227 	selectinput(menuwin, MenuMask);
    228 	mapwin(menuwin);
    229 	if(!grabpointer(menuwin, nil, 0, MouseMask))
    230 		fatal("Failed to grab the mouse\n");
    231 }
    232 
    233 void
    234 size_window(int wide, int high)
    235 {
    236 	Rectangle r;
    237 	Point p;
    238 	int h;
    239 
    240 	h = high * numitems;
    241 	r = Rect(0, 0, wide, h);
    242 
    243 	p = querypointer(&scr.root);
    244 	p.x -= wide / 2;
    245 	p.x = max(p.x, scr.rect.min.x);
    246 	p.x = min(p.x, scr.rect.max.x - wide);
    247 
    248 	p.y -= cur * high + high / 2;
    249 	p.y = max(p.y, scr.rect.min.y);
    250 	p.y = min(p.y, scr.rect.max.y - h);
    251 
    252 	reshapewin(menuwin, rectaddpt(r, p));
    253 	setborder(menuwin, 1, &cnorm.border);
    254 }
    255 
    256 void
    257 redraw(int high, int wide)
    258 {
    259 	Rectangle r;
    260 	int i;
    261 
    262 	r = Rect(0, 0, wide, high);
    263 	for(i = 0; i < numitems; i++) {
    264 		r = rectsetorigin(r, Pt(0, i * high));
    265 		fillstring(menuwin, font, r, Center, labels[i], (cur == i ? &csel : &cnorm), 0);
    266 	}
    267 }
    268 
    269 void
    270 warpmouse(int wide, int high)
    271 {
    272 	Point p;
    273 	int offset;
    274 
    275 	/* move tip of pointer into middle of menu item */
    276 	offset = labelh(font) / 2;
    277 	offset += 6;	/* fudge factor */
    278 
    279 	p = Pt(wide / 2, cur*high - high/2 + offset);
    280 	p = addpt(p, menuwin->r.min);
    281 
    282 	warppointer(p);
    283 }
    284