Xinqi Bao's Git
   1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> 
   2  * (C)opyright MMVI-MMVII Sander van Dijk <a dot h dot vandijk at gmail dot com> 
   3  * See LICENSE file for license details. 
  13 #include <sys/select.h> 
  15 #include <X11/Xutil.h> 
  16 #include <X11/keysym.h> 
  18 #define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) 
  20 typedef struct Item Item
; 
  22         Item 
*next
;             /* traverses all items */ 
  23         Item 
*left
, *right
;     /* traverses items matching current search pattern */ 
  29 static char text
[4096]; 
  30 static char *prompt 
= NULL
; 
  31 static int mx
, my
, mw
, mh
; 
  34 static unsigned int cmdw 
= 0; 
  35 static unsigned int promptw 
= 0; 
  36 static unsigned int numlockmask 
= 0; 
  37 static Bool running 
= True
; 
  38 static Item 
*allitems 
= NULL
;   /* first of all items */ 
  39 static Item 
*item 
= NULL
;       /* first of pattern matching items */ 
  40 static Item 
*sel 
= NULL
; 
  41 static Item 
*next 
= NULL
; 
  42 static Item 
*prev 
= NULL
; 
  43 static Item 
*curr 
= NULL
; 
  53         w 
= promptw 
+ cmdw 
+ 2 * SPACE
; 
  54         for(next 
= curr
; next
; next
=next
->right
) { 
  55                 tw 
= textw(next
->text
); 
  62         w 
= promptw 
+ cmdw 
+ 2 * SPACE
; 
  63         for(prev 
= curr
; prev 
&& prev
->left
; prev
=prev
->left
) { 
  64                 tw 
= textw(prev
->left
->text
); 
  81         drawtext(NULL
, dc
.norm
); 
  85                 drawtext(prompt
, dc
.sel
); 
  92         drawtext(text
[0] ? text 
: NULL
, dc
.norm
); 
  96                 drawtext((curr 
&& curr
->left
) ? "<" : NULL
, dc
.norm
); 
  98                 /* determine maximum items */ 
  99                 for(i 
= curr
; i 
!= next
; i
=i
->right
) { 
 100                         dc
.w 
= textw(i
->text
); 
 103                         drawtext(i
->text
, (sel 
== i
) ? dc
.sel 
: dc
.norm
); 
 108                 drawtext(next 
? ">" : NULL
, dc
.norm
); 
 110         XCopyArea(dpy
, dc
.drawable
, win
, dc
.gc
, 0, 0, mw
, mh
, 0, 0); 
 115 match(char *pattern
) { 
 121         plen 
= strlen(pattern
); 
 124         for(i 
= allitems
; i
; i
=i
->next
) 
 125                 if(!plen 
|| !strncmp(pattern
, i
->text
, plen
)) { 
 135         for(i 
= allitems
; i
; i
=i
->next
) 
 136                 if(plen 
&& strncmp(pattern
, i
->text
, plen
) 
 137                                 && strstr(i
->text
, pattern
)) { 
 147         curr 
= prev 
= next 
= sel 
= item
; 
 152 kpress(XKeyEvent 
* e
) { 
 160         num 
= XLookupString(e
, buf
, sizeof buf
, &ksym
, 0); 
 161         if(IsFunctionKey(ksym
) || IsKeypadKey(ksym
) 
 162                         || IsMiscFunctionKey(ksym
) || IsPFKey(ksym
) 
 163                         || IsPrivateKeypadKey(ksym
)) 
 165         /* first check if a control mask is omitted */ 
 166         if(e
->state 
& ControlMask
) { 
 168                 default:        /* ignore other control sequences */ 
 193         if(CLEANMASK(e
->state
) & Mod1Mask
) { 
 218                 if(num 
&& !iscntrl((int) buf
[0])) { 
 221                                 strncat(text
, buf
, sizeof text
); 
 223                                 strncpy(text
, buf
, sizeof text
); 
 233                         } while(i 
&& nitem 
&& prev_nitem 
== nitem
); 
 244                 while(sel 
&& sel
->right
) 
 258                 if(!(sel 
&& sel
->left
)) 
 261                 if(sel
->right 
== curr
) { 
 279                 if((e
->state 
& ShiftMask
) && text
) 
 280                         fprintf(stdout
, "%s", text
); 
 282                         fprintf(stdout
, "%s", sel
->text
); 
 284                         fprintf(stdout
, "%s", text
); 
 289                 if(!(sel 
&& sel
->right
)) 
 300                 strncpy(text
, sel
->text
, sizeof text
); 
 309         static char *maxname 
= NULL
; 
 311         unsigned int len 
= 0, max 
= 0; 
 315         while(fgets(buf
, sizeof buf
, stdin
)) { 
 317                 if (buf
[len 
- 1] == '\n') 
 324                 new = emalloc(sizeof(Item
)); 
 325                 new->next 
= new->left 
= new->right 
= NULL
; 
 344 main(int argc
, char *argv
[]) { 
 348         char *normbg 
= NORMBGCOLOR
; 
 349         char *normfg 
= NORMFGCOLOR
; 
 350         char *selbg 
= SELBGCOLOR
; 
 351         char *selfg 
= SELFGCOLOR
; 
 354         struct timeval timeout
; 
 357         XModifierKeymap 
*modmap
; 
 358         XSetWindowAttributes wa
; 
 362         /* command line args */ 
 363         for(i 
= 1; i 
< argc
; i
++) 
 364                 if(!strncmp(argv
[i
], "-b", 3)) { 
 367                 else if(!strncmp(argv
[i
], "-fn", 4)) { 
 368                         if(++i 
< argc
) font 
= argv
[i
]; 
 370                 else if(!strncmp(argv
[i
], "-nb", 4)) { 
 371                         if(++i 
< argc
) normbg 
= argv
[i
]; 
 373                 else if(!strncmp(argv
[i
], "-nf", 4)) { 
 374                         if(++i 
< argc
) normfg 
= argv
[i
]; 
 376                 else if(!strncmp(argv
[i
], "-p", 3)) { 
 377                         if(++i 
< argc
) prompt 
= argv
[i
]; 
 379                 else if(!strncmp(argv
[i
], "-sb", 4)) { 
 380                         if(++i 
< argc
) selbg 
= argv
[i
]; 
 382                 else if(!strncmp(argv
[i
], "-sf", 4)) { 
 383                         if(++i 
< argc
) selfg 
= argv
[i
]; 
 385                 else if(!strncmp(argv
[i
], "-t", 3)) { 
 386                         if(++i 
< argc
) timeout
.tv_sec 
= atoi(argv
[i
]); 
 388                 else if(!strncmp(argv
[i
], "-v", 3)) { 
 389                         fputs("dmenu-"VERSION
", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout
); 
 393                         eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>] [-p <prompt>]\n" 
 394                                 "             [-sb <color>] [-sf <color>] [-t <seconds>] [-v]\n", stdout
); 
 395         setlocale(LC_CTYPE
, ""); 
 396         dpy 
= XOpenDisplay(0); 
 398                 eprint("dmenu: cannot open display\n"); 
 399         screen 
= DefaultScreen(dpy
); 
 400         root 
= RootWindow(dpy
, screen
); 
 402         /* Note, the select() construction allows to grab all keypresses as 
 403          * early as possible, to not loose them. But if there is no standard 
 404          * input supplied, we will make sure to exit after MAX_WAIT_STDIN 
 405          * seconds. This is convenience behavior for rapid typers. 
 407         while(XGrabKeyboard(dpy
, root
, True
, GrabModeAsync
, 
 408                          GrabModeAsync
, CurrentTime
) != GrabSuccess
) 
 411         FD_SET(STDIN_FILENO
, &rd
); 
 412         if(select(ConnectionNumber(dpy
) + 1, &rd
, NULL
, NULL
, &timeout
) < 1) 
 413                 goto UninitializedEnd
; 
 414         maxname 
= readstdin(); 
 415         /* init modifier map */ 
 416         modmap 
= XGetModifierMapping(dpy
); 
 417         for (i 
= 0; i 
< 8; i
++) { 
 418                 for (j 
= 0; j 
< modmap
->max_keypermod
; j
++) { 
 419                         if(modmap
->modifiermap
[i 
* modmap
->max_keypermod 
+ j
] == XKeysymToKeycode(dpy
, XK_Num_Lock
)) 
 420                                 numlockmask 
= (1 << i
); 
 423         XFreeModifiermap(modmap
); 
 425         dc
.norm
[ColBG
] = getcolor(normbg
); 
 426         dc
.norm
[ColFG
] = getcolor(normfg
); 
 427         dc
.sel
[ColBG
] = getcolor(selbg
); 
 428         dc
.sel
[ColFG
] = getcolor(selfg
); 
 431         wa
.override_redirect 
= 1; 
 432         wa
.background_pixmap 
= ParentRelative
; 
 433         wa
.event_mask 
= ExposureMask 
| ButtonPressMask 
| KeyPressMask
; 
 435         mw 
= DisplayWidth(dpy
, screen
); 
 436         mh 
= dc
.font
.height 
+ 2; 
 438                 my 
+= DisplayHeight(dpy
, screen
) - mh
; 
 439         win 
= XCreateWindow(dpy
, root
, mx
, my
, mw
, mh
, 0, 
 440                         DefaultDepth(dpy
, screen
), CopyFromParent
, 
 441                         DefaultVisual(dpy
, screen
), 
 442                         CWOverrideRedirect 
| CWBackPixmap 
| CWEventMask
, &wa
); 
 444         dc
.drawable 
= XCreatePixmap(dpy
, root
, mw
, mh
, DefaultDepth(dpy
, screen
)); 
 445         dc
.gc 
= XCreateGC(dpy
, root
, 0, 0); 
 446         XSetLineAttributes(dpy
, dc
.gc
, 1, LineSolid
, CapButt
, JoinMiter
); 
 448                 cmdw 
= textw(maxname
); 
 452                 promptw 
= textw(prompt
); 
 457         XMapRaised(dpy
, win
); 
 461         /* main event loop */ 
 462         while(running 
&& !XNextEvent(dpy
, &ev
)) 
 464                 default:        /* ignore all crap */ 
 470                         if(ev
.xexpose
.count 
== 0) 
 477                 itm 
= allitems
->next
; 
 478                 free(allitems
->text
); 
 483                 XFreeFontSet(dpy
, dc
.font
.set
); 
 485                 XFreeFont(dpy
, dc
.font
.xfont
); 
 486         XFreePixmap(dpy
, dc
.drawable
); 
 488         XDestroyWindow(dpy
, win
); 
 490         XUngrabKeyboard(dpy
, CurrentTime
);