Xinqi Bao's Git
2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3 * (C)opyright MMVI Sander van Dijk <a dot h dot vandijk at gmail dot com>
4 * See LICENSE file for license details.
16 #include <X11/cursorfont.h>
17 #include <X11/Xutil.h>
18 #include <X11/keysym.h>
23 typedef struct Item Item
;
26 Item
*next
; /* traverses all items */
27 Item
*left
, *right
; /* traverses items matching current search pattern */
31 static char *title
= nil
;
32 static Bool done
= False
;
34 static char text
[4096];
35 static BlitzColor selcolor
;
36 static BlitzColor normcolor
;
38 static XRectangle mrect
;
39 static Item
*allitem
= nil
; /* first of all items */
40 static Item
*item
= nil
; /* first of pattern matching items */
41 static Item
*sel
= nil
;
42 static Item
*nextoff
= nil
;
43 static Item
*prevoff
= nil
;
44 static Item
*curroff
= nil
;
46 static unsigned int cmdw
= 0;
47 static unsigned int twidth
= 0;
48 static unsigned int cwidth
= 0;
49 static Blitz blz
= {0};
50 static BlitzBrush brush
= {0};
51 static const int seek
= 30; /* 30px */
53 static void draw_menu(void);
54 static void handle_kpress(XKeyEvent
* e
);
56 static char version
[] = "wmiimenu - " VERSION
", (C)opyright MMIV-MMVI Anselm R. Garbe\n";
61 fprintf(stderr
, "%s", "usage: wmiimenu [-v] [-t <title>]\n");
68 unsigned int tw
, w
= cmdw
+ 2 * seek
;
73 for(nextoff
= curroff
; nextoff
; nextoff
=nextoff
->right
) {
74 tw
= blitz_textwidth(brush
.font
, nextoff
->text
);
75 if(tw
> mrect
.width
/ 3)
77 w
+= tw
+ mrect
.height
;
83 for(prevoff
= curroff
; prevoff
&& prevoff
->left
; prevoff
=prevoff
->left
) {
84 tw
= blitz_textwidth(brush
.font
, prevoff
->left
->text
);
85 if(tw
> mrect
.width
/ 3)
87 w
+= tw
+ mrect
.height
;
94 update_items(char *pattern
)
96 unsigned int plen
= strlen(pattern
);
102 if(!title
|| *pattern
)
110 for(i
= allitem
; i
; i
=i
->next
)
111 if(!plen
|| !strncmp(pattern
, i
->text
, plen
)) {
121 for(i
= allitem
; i
; i
=i
->next
)
122 if(plen
&& strncmp(pattern
, i
->text
, plen
)
123 && strstr(i
->text
, pattern
)) {
134 curroff
= prevoff
= nextoff
= sel
= item
;
139 /* creates brush structs for brush mode drawing */
143 unsigned int offx
= 0;
152 brush
.color
= normcolor
;
153 brush
.border
= False
;
154 blitz_draw_tile(&brush
);
157 if(!title
|| text
[0]) {
158 brush
.color
= normcolor
;
161 brush
.rect
.width
= cmdw
;
162 blitz_draw_label(&brush
, text
);
166 brush
.color
= selcolor
;
167 brush
.rect
.width
= cmdw
;
168 blitz_draw_label(&brush
, title
);
170 offx
+= brush
.rect
.width
;
172 brush
.align
= CENTER
;
174 brush
.color
= normcolor
;
176 brush
.rect
.width
= seek
;
177 offx
+= brush
.rect
.width
;
178 blitz_draw_label(&brush
, (curroff
&& curroff
->left
) ? "<" : nil
);
180 /* determine maximum items */
181 for(i
= curroff
; i
!= nextoff
; i
=i
->right
) {
182 brush
.color
= normcolor
;
183 brush
.border
= False
;
185 brush
.rect
.width
= blitz_textwidth(brush
.font
, i
->text
);
186 if(brush
.rect
.width
> mrect
.width
/ 3)
187 brush
.rect
.width
= mrect
.width
/ 3;
188 brush
.rect
.width
+= mrect
.height
;
190 brush
.color
= selcolor
;
193 blitz_draw_label(&brush
, i
->text
);
194 offx
+= brush
.rect
.width
;
197 brush
.color
= normcolor
;
198 brush
.border
= False
;
199 brush
.rect
.x
= mrect
.width
- seek
;
200 brush
.rect
.width
= seek
;
201 blitz_draw_label(&brush
, nextoff
? ">" : nil
);
203 XCopyArea(blz
.dpy
, brush
.drawable
, win
, brush
.gc
, 0, 0, mrect
.width
,
205 XSync(blz
.dpy
, False
);
209 handle_kpress(XKeyEvent
* e
)
214 unsigned int i
, len
= strlen(text
);
217 num
= XLookupString(e
, buf
, sizeof(buf
), &ksym
, 0);
219 if(IsFunctionKey(ksym
) || IsKeypadKey(ksym
)
220 || IsMiscFunctionKey(ksym
) || IsPFKey(ksym
)
221 || IsPrivateKeypadKey(ksym
))
224 /* first check if a control mask is omitted */
225 if(e
->state
& ControlMask
) {
257 default: /* ignore other control sequences */
264 if(!(sel
&& sel
->left
))
267 if(sel
->right
== curroff
) {
275 cext_strlcpy(text
, sel
->text
, sizeof(text
));
279 if(!(sel
&& sel
->right
))
288 if(e
->state
& ShiftMask
) {
290 fprintf(stdout
, "%s", text
);
293 fprintf(stdout
, "%s", sel
->text
);
295 fprintf(stdout
, "%s", text
);
309 } while(i
&& nitem
&& prev_nitem
== nitem
);
314 if((num
== 1) && !iscntrl((int) buf
[0])) {
317 cext_strlcat(text
, buf
, sizeof(text
));
319 cext_strlcpy(text
, buf
, sizeof(text
));
329 static char *maxname
= nil
;
331 unsigned int len
= 0, max
= 0;
335 while(fgets(buf
, sizeof(buf
), stdin
)) {
337 if (buf
[len
- 1] == '\n')
339 p
= cext_estrdup(buf
);
345 new = cext_emalloc(sizeof(Item
));
346 new->next
= new->left
= new->right
= nil
;
359 main(int argc
, char *argv
[])
362 XSetWindowAttributes wa
;
364 BlitzFont font
= {0};
369 /* command line args */
370 for(i
= 1; i
< argc
; i
++) {
371 if (argv
[i
][0] == '-')
372 switch (argv
[i
][1]) {
374 fprintf(stdout
, "%s", version
);
391 blz
.dpy
= XOpenDisplay(0);
393 fprintf(stderr
, "%s", "wmiimenu: cannot open dpy\n");
396 blz
.screen
= DefaultScreen(blz
.dpy
);
397 blz
.root
= RootWindow(blz
.dpy
, blz
.screen
);
399 maxname
= read_allitems();
401 /* grab as early as possible, but after reading all items!!! */
403 (blz
.dpy
, blz
.root
, True
, GrabModeAsync
,
404 GrabModeAsync
, CurrentTime
) != GrabSuccess
)
407 font
.fontstr
= getenv("WMII_FONT");
409 font
.fontstr
= cext_estrdup(BLITZ_FONT
);
410 blitz_loadfont(&blz
, &font
);
412 if((p
= getenv("WMII_NORMCOLORS")))
413 cext_strlcpy(normcolor
.colstr
, p
, sizeof(normcolor
.colstr
));
414 if(strlen(normcolor
.colstr
) != 23)
415 cext_strlcpy(normcolor
.colstr
, BLITZ_NORMCOLORS
, sizeof(normcolor
.colstr
));
416 blitz_loadcolor(&blz
, &normcolor
);
418 if((p
= getenv("WMII_SELCOLORS")))
419 cext_strlcpy(selcolor
.colstr
, p
, sizeof(selcolor
.colstr
));
420 if(strlen(selcolor
.colstr
) != 23)
421 cext_strlcpy(selcolor
.colstr
, BLITZ_SELCOLORS
, sizeof(selcolor
.colstr
));
422 blitz_loadcolor(&blz
, &selcolor
);
424 wa
.override_redirect
= 1;
425 wa
.background_pixmap
= ParentRelative
;
426 wa
.event_mask
= ExposureMask
| ButtonPressMask
| KeyPressMask
427 | SubstructureRedirectMask
| SubstructureNotifyMask
;
429 mrect
.width
= DisplayWidth(blz
.dpy
, blz
.screen
);
430 mrect
.height
= font
.ascent
+ font
.descent
+ 4;
431 mrect
.y
= DisplayHeight(blz
.dpy
, blz
.screen
) - mrect
.height
;
434 win
= XCreateWindow(blz
.dpy
, blz
.root
, mrect
.x
, mrect
.y
,
435 mrect
.width
, mrect
.height
, 0, DefaultDepth(blz
.dpy
, blz
.screen
),
436 CopyFromParent
, DefaultVisual(blz
.dpy
, blz
.screen
),
437 CWOverrideRedirect
| CWBackPixmap
| CWEventMask
, &wa
);
438 XDefineCursor(blz
.dpy
, win
, XCreateFontCursor(blz
.dpy
, XC_xterm
));
439 XSync(blz
.dpy
, False
);
442 gc
= XCreateGC(blz
.dpy
, win
, 0, 0);
443 pmap
= XCreatePixmap(blz
.dpy
, win
, mrect
.width
, mrect
.height
,
444 DefaultDepth(blz
.dpy
, blz
.screen
));
446 XSync(blz
.dpy
, False
);
449 brush
.color
= normcolor
;
450 brush
.drawable
= pmap
;
455 cwidth
= blitz_textwidth(brush
.font
, maxname
) + mrect
.height
;
456 if(cwidth
> mrect
.width
/ 3)
457 cwidth
= mrect
.width
/ 3;
460 twidth
= blitz_textwidth(brush
.font
, title
) + mrect
.height
;
461 if(twidth
> mrect
.width
/ 3)
462 twidth
= mrect
.width
/ 3;
465 cmdw
= title
? twidth
: cwidth
;
469 XMapRaised(blz
.dpy
, win
);
471 XSync(blz
.dpy
, False
);
473 /* main event loop */
474 while(!XNextEvent(blz
.dpy
, &ev
)) {
477 handle_kpress(&ev
.xkey
);
480 if(ev
.xexpose
.count
== 0) {
491 XUngrabKeyboard(blz
.dpy
, CurrentTime
);
492 XFreePixmap(blz
.dpy
, pmap
);
493 XFreeGC(blz
.dpy
, gc
);
494 XDestroyWindow(blz
.dpy
, win
);
495 XCloseDisplay(blz
.dpy
);