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