@@ -65,6 +65,13 @@ static Clr *scheme[SchemeLast];
6565static int (* fstrncmp )(const char * , const char * , size_t ) = strncmp ;
6666static char * (* fstrstr )(const char * , const char * ) = strstr ;
6767
68+ static unsigned int
69+ textw_clamp (const char * str , unsigned int n )
70+ {
71+ unsigned int w = drw_fontset_getwidth_clamp (drw , str , n ) + lrpad ;
72+ return MIN (w , n );
73+ }
74+
6875static void
6976appenditem (struct item * item , struct item * * list , struct item * * last )
7077{
@@ -89,10 +96,10 @@ calcoffsets(void)
8996 n = mw - (promptw + inputw + TEXTW ("<" ) + TEXTW (">" ));
9097 /* calculate which items will begin the next page and previous page */
9198 for (i = 0 , next = curr ; next ; next = next -> right )
92- if ((i += (lines > 0 ) ? bh : MIN ( TEXTW ( next -> text ) , n )) > n )
99+ if ((i += (lines > 0 ) ? bh : textw_clamp ( next -> text , n )) > n )
93100 break ;
94101 for (i = 0 , prev = curr ; prev && prev -> left ; prev = prev -> left )
95- if ((i += (lines > 0 ) ? bh : MIN ( TEXTW ( prev -> left -> text ) , n )) > n )
102+ if ((i += (lines > 0 ) ? bh : textw_clamp ( prev -> left -> text , n )) > n )
96103 break ;
97104}
98105
@@ -104,19 +111,29 @@ cleanup(void)
104111 XUngrabKey (dpy , AnyKey , AnyModifier , root );
105112 for (i = 0 ; i < SchemeLast ; i ++ )
106113 free (scheme [i ]);
114+ for (i = 0 ; items && items [i ].text ; ++ i )
115+ free (items [i ].text );
116+ free (items );
107117 drw_free (drw );
108118 XSync (dpy , False );
109119 XCloseDisplay (dpy );
110120}
111121
112122static char *
113- cistrstr (const char * s , const char * sub )
123+ cistrstr (const char * h , const char * n )
114124{
115- size_t len ;
125+ size_t i ;
126+
127+ if (!n [0 ])
128+ return (char * )h ;
116129
117- for (len = strlen (sub ); * s ; s ++ )
118- if (!strncasecmp (s , sub , len ))
119- return (char * )s ;
130+ for (; * h ; ++ h ) {
131+ for (i = 0 ; n [i ] && tolower ((unsigned char )n [i ]) ==
132+ tolower ((unsigned char )h [i ]); ++ i )
133+ ;
134+ if (n [i ] == '\0' )
135+ return (char * )h ;
136+ }
120137 return NULL ;
121138}
122139
@@ -236,7 +253,7 @@ drawmenu(void)
236253 }
237254 x += w ;
238255 for (item = curr ; item != next ; item = item -> right )
239- x = drawitem (item , x , 0 , MIN ( TEXTW ( item -> text ) , mw - x - TEXTW (">" ) - TEXTW (numbers )));
256+ x = drawitem (item , x , 0 , textw_clamp ( item -> text , mw - x - TEXTW (">" ) - TEXTW (numbers )));
240257 if (next ) {
241258 w = TEXTW (">" );
242259 drw_setscheme (drw , scheme [SchemeNorm ]);
@@ -383,7 +400,7 @@ match(void)
383400 /* separate input text into tokens to be matched individually */
384401 for (s = strtok (buf , " " ); s ; tokv [tokc - 1 ] = s , s = strtok (NULL , " " ))
385402 if (++ tokc > tokn && !(tokv = realloc (tokv , ++ tokn * sizeof * tokv )))
386- die ("cannot realloc %u bytes:" , tokn * sizeof * tokv );
403+ die ("cannot realloc %zu bytes:" , tokn * sizeof * tokv );
387404 len = tokc ? strlen (tokv [0 ]) : 0 ;
388405
389406 matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL ;
@@ -472,19 +489,19 @@ movewordedge(int dir)
472489static void
473490keypress (XKeyEvent * ev )
474491{
475- char buf [32 ];
492+ char buf [64 ];
476493 int len ;
477- KeySym ksym ;
494+ KeySym ksym = NoSymbol ;
478495 Status status ;
479496
480497 len = XmbLookupString (xic , ev , buf , sizeof buf , & ksym , & status );
481498 switch (status ) {
482499 default : /* XLookupNone, XBufferOverflow */
483500 return ;
484- case XLookupChars :
501+ case XLookupChars : /* composed string from input method */
485502 goto insert ;
486503 case XLookupKeySym :
487- case XLookupBoth :
504+ case XLookupBoth : /* a KeySym and a string are returned: use keysym */
488505 break ;
489506 }
490507
@@ -525,9 +542,11 @@ keypress(XKeyEvent *ev)
525542 utf8 , utf8 , win , CurrentTime );
526543 return ;
527544 case XK_Left :
545+ case XK_KP_Left :
528546 movewordedge (-1 );
529547 goto draw ;
530548 case XK_Right :
549+ case XK_KP_Right :
531550 movewordedge (+1 );
532551 goto draw ;
533552 case XK_Return :
@@ -561,10 +580,11 @@ keypress(XKeyEvent *ev)
561580 switch (ksym ) {
562581 default :
563582insert :
564- if (!iscntrl (* buf ))
583+ if (!iscntrl (( unsigned char ) * buf ))
565584 insert (buf , len );
566585 break ;
567586 case XK_Delete :
587+ case XK_KP_Delete :
568588 if (text [cursor ] == '\0' )
569589 return ;
570590 cursor = nextrune (+1 );
@@ -575,6 +595,7 @@ keypress(XKeyEvent *ev)
575595 insert (NULL , nextrune (-1 ) - cursor );
576596 break ;
577597 case XK_End :
598+ case XK_KP_End :
578599 if (text [cursor ] != '\0' ) {
579600 cursor = strlen (text );
580601 break ;
@@ -594,6 +615,7 @@ keypress(XKeyEvent *ev)
594615 cleanup ();
595616 exit (1 );
596617 case XK_Home :
618+ case XK_KP_Home :
597619 if (sel == matches ) {
598620 cursor = 0 ;
599621 break ;
@@ -602,6 +624,7 @@ keypress(XKeyEvent *ev)
602624 calcoffsets ();
603625 break ;
604626 case XK_Left :
627+ case XK_KP_Left :
605628 if (cursor > 0 && (!sel || !sel -> left || lines > 0 )) {
606629 cursor = nextrune (-1 );
607630 break ;
@@ -610,18 +633,21 @@ keypress(XKeyEvent *ev)
610633 return ;
611634 /* fallthrough */
612635 case XK_Up :
636+ case XK_KP_Up :
613637 if (sel && sel -> left && (sel = sel -> left )-> right == curr ) {
614638 curr = prev ;
615639 calcoffsets ();
616640 }
617641 break ;
618642 case XK_Next :
643+ case XK_KP_Next :
619644 if (!next )
620645 return ;
621646 sel = curr = next ;
622647 calcoffsets ();
623648 break ;
624649 case XK_Prior :
650+ case XK_KP_Prior :
625651 if (!prev )
626652 return ;
627653 sel = curr = prev ;
@@ -638,6 +664,7 @@ keypress(XKeyEvent *ev)
638664 sel -> out = 1 ;
639665 break ;
640666 case XK_Right :
667+ case XK_KP_Right :
641668 if (text [cursor ] != '\0' ) {
642669 cursor = nextrune (+1 );
643670 break ;
@@ -646,6 +673,7 @@ keypress(XKeyEvent *ev)
646673 return ;
647674 /* fallthrough */
648675 case XK_Down :
676+ case XK_KP_Down :
649677 if (sel && sel -> right && (sel = sel -> right ) == next ) {
650678 curr = next ;
651679 calcoffsets ();
@@ -654,9 +682,9 @@ keypress(XKeyEvent *ev)
654682 case XK_Tab :
655683 if (!sel )
656684 return ;
657- strncpy ( text , sel -> text , sizeof text - 1 );
658- text [ sizeof text - 1 ] = '\0' ;
659- cursor = strlen ( text ) ;
685+ cursor = strnlen ( sel -> text , sizeof text - 1 );
686+ memcpy ( text , sel -> text , cursor ) ;
687+ text [ cursor ] = '\0' ;
660688 match ();
661689 break ;
662690 }
@@ -686,34 +714,32 @@ paste(void)
686714static void
687715readstdin (void )
688716{
689- char buf [ sizeof text ], * p ;
690- size_t i , imax = 0 , size = 0 ;
691- unsigned int tmpmax = 0 ;
717+ char * line = NULL ;
718+ size_t i , itemsiz = 0 , linesiz = 0 ;
719+ ssize_t len ;
692720
693721 if (passwd ){
694722 inputw = lines = 0 ;
695723 return ;
696724 }
697725
698726 /* read each line from stdin and add it to the item list */
699- for (i = 0 ; fgets (buf , sizeof buf , stdin ); i ++ ) {
700- if (i + 1 >= size / sizeof * items )
701- if (!(items = realloc (items , (size += BUFSIZ ))))
702- die ("cannot realloc %u bytes:" , size );
703- if ((p = strchr (buf , '\n' )))
704- * p = '\0' ;
705- if (!(items [i ].text = strdup (buf )))
706- die ("cannot strdup %u bytes:" , strlen (buf ) + 1 );
707- items [i ].out = 0 ;
708- drw_font_getexts (drw -> fonts , buf , strlen (buf ), & tmpmax , NULL );
709- if (tmpmax > inputw ) {
710- inputw = tmpmax ;
711- imax = i ;
727+ for (i = 0 ; (len = getline (& line , & linesiz , stdin )) != -1 ; i ++ ) {
728+ if (i + 1 >= itemsiz ) {
729+ itemsiz += 256 ;
730+ if (!(items = realloc (items , itemsiz * sizeof (* items ))))
731+ die ("cannot realloc %zu bytes:" , itemsiz * sizeof (* items ));
712732 }
733+ if (line [len - 1 ] == '\n' )
734+ line [len - 1 ] = '\0' ;
735+ if (!(items [i ].text = strdup (line )))
736+ die ("strdup:" );
737+
738+ items [i ].out = 0 ;
713739 }
740+ free (line );
714741 if (items )
715742 items [i ].text = NULL ;
716- inputw = items ? TEXTW (items [imax ].text ) : 0 ;
717743 lines = MIN (lines , i );
718744}
719745
@@ -804,7 +830,7 @@ setup(void)
804830 /* no focused window is on screen, so use pointer location instead */
805831 if (mon < 0 && !area && XQueryPointer (dpy , root , & dw , & dw , & x , & y , & di , & di , & du ))
806832 for (i = 0 ; i < n ; i ++ )
807- if (INTERSECT (x , y , 1 , 1 , info [i ]))
833+ if (INTERSECT (x , y , 1 , 1 , info [i ]) != 0 )
808834 break ;
809835
810836 x = info [i ].x_org ;
@@ -822,14 +848,14 @@ setup(void)
822848 mw = wa .width ;
823849 }
824850 promptw = (prompt && * prompt ) ? TEXTW (prompt ) - lrpad / 4 : 0 ;
825- inputw = MIN ( inputw , mw / 3 );
851+ inputw = mw / 3 ; /* input width: ~33% of monitor width */
826852 match ();
827853
828854 /* create menu window */
829855 swa .override_redirect = True ;
830856 swa .background_pixel = scheme [SchemeNorm ][ColBg ].pixel ;
831857 swa .event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask ;
832- win = XCreateWindow (dpy , parentwin , x , y , mw , mh , 0 ,
858+ win = XCreateWindow (dpy , root , x , y , mw , mh , 0 ,
833859 CopyFromParent , CopyFromParent , CopyFromParent ,
834860 CWOverrideRedirect | CWBackPixel | CWEventMask , & swa );
835861 XSetClassHint (dpy , win , & ch );
@@ -844,6 +870,7 @@ setup(void)
844870
845871 XMapRaised (dpy , win );
846872 if (embed ) {
873+ XReparentWindow (dpy , win , parentwin , x , y );
847874 XSelectInput (dpy , parentwin , FocusChangeMask | SubstructureNotifyMask );
848875 if (XQueryTree (dpy , parentwin , & dw , & w , & dws , & du ) && dws ) {
849876 for (i = 0 ; i < du && dws [i ] != win ; ++ i )
@@ -859,10 +886,9 @@ setup(void)
859886static void
860887usage (void )
861888{
862- fputs ("usage: dmenu [-bfiv] [-n|P] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
863- " [-nb color] [-nf color] [-sb color] [-sf color]\n"
864- " [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" , stderr );
865- exit (1 );
889+ die ("usage: dmenu [-bfiv] [-n|P] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
890+ " [-nb color] [-nf color] [-sb color] [-sf color]\n"
891+ " [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" );
866892}
867893
868894int
0 commit comments