22
22
/* macros */
23
23
#define INTERSECT (x ,y ,w ,h ,r ) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
24
24
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
25
- #define LENGTH (X ) (sizeof X / sizeof X[0])
26
25
#define TEXTW (X ) (drw_fontset_getwidth(drw, (X)) + lrpad)
27
26
28
27
/* enums */
@@ -58,6 +57,13 @@ static Clr *scheme[SchemeLast];
58
57
static int (* fstrncmp )(const char * , const char * , size_t ) = strncmp ;
59
58
static char * (* fstrstr )(const char * , const char * ) = strstr ;
60
59
60
+ static unsigned int
61
+ textw_clamp (const char * str , unsigned int n )
62
+ {
63
+ unsigned int w = drw_fontset_getwidth_clamp (drw , str , n ) + lrpad ;
64
+ return MIN (w , n );
65
+ }
66
+
61
67
static void
62
68
appenditem (struct item * item , struct item * * list , struct item * * last )
63
69
{
@@ -82,10 +88,10 @@ calcoffsets(void)
82
88
n = mw - (promptw + inputw + TEXTW ("<" ) + TEXTW (">" ));
83
89
/* calculate which items will begin the next page and previous page */
84
90
for (i = 0 , next = curr ; next ; next = next -> right )
85
- if ((i += (lines > 0 ) ? bh : MIN ( TEXTW ( next -> text ) , n )) > n )
91
+ if ((i += (lines > 0 ) ? bh : textw_clamp ( next -> text , n )) > n )
86
92
break ;
87
93
for (i = 0 , prev = curr ; prev && prev -> left ; prev = prev -> left )
88
- if ((i += (lines > 0 ) ? bh : MIN ( TEXTW ( prev -> left -> text ) , n )) > n )
94
+ if ((i += (lines > 0 ) ? bh : textw_clamp ( prev -> left -> text , n )) > n )
89
95
break ;
90
96
}
91
97
@@ -97,19 +103,29 @@ cleanup(void)
97
103
XUngrabKey (dpy , AnyKey , AnyModifier , root );
98
104
for (i = 0 ; i < SchemeLast ; i ++ )
99
105
free (scheme [i ]);
106
+ for (i = 0 ; items && items [i ].text ; ++ i )
107
+ free (items [i ].text );
108
+ free (items );
100
109
drw_free (drw );
101
110
XSync (dpy , False );
102
111
XCloseDisplay (dpy );
103
112
}
104
113
105
114
static char *
106
- cistrstr (const char * s , const char * sub )
115
+ cistrstr (const char * h , const char * n )
107
116
{
108
- size_t len ;
117
+ size_t i ;
118
+
119
+ if (!n [0 ])
120
+ return (char * )h ;
109
121
110
- for (len = strlen (sub ); * s ; s ++ )
111
- if (!strncasecmp (s , sub , len ))
112
- return (char * )s ;
122
+ for (; * h ; ++ h ) {
123
+ for (i = 0 ; n [i ] && tolower ((unsigned char )n [i ]) ==
124
+ tolower ((unsigned char )h [i ]); ++ i )
125
+ ;
126
+ if (n [i ] == '\0' )
127
+ return (char * )h ;
128
+ }
113
129
return NULL ;
114
130
}
115
131
@@ -165,7 +181,7 @@ drawmenu(void)
165
181
}
166
182
x += w ;
167
183
for (item = curr ; item != next ; item = item -> right )
168
- x = drawitem (item , x , 0 , MIN ( TEXTW ( item -> text ) , mw - x - TEXTW (">" )));
184
+ x = drawitem (item , x , 0 , textw_clamp ( item -> text , mw - x - TEXTW (">" )));
169
185
if (next ) {
170
186
w = TEXTW (">" );
171
187
drw_setscheme (drw , scheme [SchemeNorm ]);
@@ -225,7 +241,7 @@ match(void)
225
241
/* separate input text into tokens to be matched individually */
226
242
for (s = strtok (buf , " " ); s ; tokv [tokc - 1 ] = s , s = strtok (NULL , " " ))
227
243
if (++ tokc > tokn && !(tokv = realloc (tokv , ++ tokn * sizeof * tokv )))
228
- die ("cannot realloc %u bytes:" , tokn * sizeof * tokv );
244
+ die ("cannot realloc %zu bytes:" , tokn * sizeof * tokv );
229
245
len = tokc ? strlen (tokv [0 ]) : 0 ;
230
246
231
247
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL ;
@@ -307,19 +323,19 @@ movewordedge(int dir)
307
323
static void
308
324
keypress (XKeyEvent * ev )
309
325
{
310
- char buf [32 ];
326
+ char buf [64 ];
311
327
int len ;
312
- KeySym ksym ;
328
+ KeySym ksym = NoSymbol ;
313
329
Status status ;
314
330
315
331
len = XmbLookupString (xic , ev , buf , sizeof buf , & ksym , & status );
316
332
switch (status ) {
317
333
default : /* XLookupNone, XBufferOverflow */
318
334
return ;
319
- case XLookupChars :
335
+ case XLookupChars : /* composed string from input method */
320
336
goto insert ;
321
337
case XLookupKeySym :
322
- case XLookupBoth :
338
+ case XLookupBoth : /* a KeySym and a string are returned: use keysym */
323
339
break ;
324
340
}
325
341
@@ -360,9 +376,11 @@ keypress(XKeyEvent *ev)
360
376
utf8 , utf8 , win , CurrentTime );
361
377
return ;
362
378
case XK_Left :
379
+ case XK_KP_Left :
363
380
movewordedge (-1 );
364
381
goto draw ;
365
382
case XK_Right :
383
+ case XK_KP_Right :
366
384
movewordedge (+1 );
367
385
goto draw ;
368
386
case XK_Return :
@@ -396,10 +414,11 @@ keypress(XKeyEvent *ev)
396
414
switch (ksym ) {
397
415
default :
398
416
insert :
399
- if (!iscntrl (* buf ))
417
+ if (!iscntrl (( unsigned char ) * buf ))
400
418
insert (buf , len );
401
419
break ;
402
420
case XK_Delete :
421
+ case XK_KP_Delete :
403
422
if (text [cursor ] == '\0' )
404
423
return ;
405
424
cursor = nextrune (+1 );
@@ -410,6 +429,7 @@ keypress(XKeyEvent *ev)
410
429
insert (NULL , nextrune (-1 ) - cursor );
411
430
break ;
412
431
case XK_End :
432
+ case XK_KP_End :
413
433
if (text [cursor ] != '\0' ) {
414
434
cursor = strlen (text );
415
435
break ;
@@ -429,6 +449,7 @@ keypress(XKeyEvent *ev)
429
449
cleanup ();
430
450
exit (1 );
431
451
case XK_Home :
452
+ case XK_KP_Home :
432
453
if (sel == matches ) {
433
454
cursor = 0 ;
434
455
break ;
@@ -437,6 +458,7 @@ keypress(XKeyEvent *ev)
437
458
calcoffsets ();
438
459
break ;
439
460
case XK_Left :
461
+ case XK_KP_Left :
440
462
if (cursor > 0 && (!sel || !sel -> left || lines > 0 )) {
441
463
cursor = nextrune (-1 );
442
464
break ;
@@ -445,18 +467,21 @@ keypress(XKeyEvent *ev)
445
467
return ;
446
468
/* fallthrough */
447
469
case XK_Up :
470
+ case XK_KP_Up :
448
471
if (sel && sel -> left && (sel = sel -> left )-> right == curr ) {
449
472
curr = prev ;
450
473
calcoffsets ();
451
474
}
452
475
break ;
453
476
case XK_Next :
477
+ case XK_KP_Next :
454
478
if (!next )
455
479
return ;
456
480
sel = curr = next ;
457
481
calcoffsets ();
458
482
break ;
459
483
case XK_Prior :
484
+ case XK_KP_Prior :
460
485
if (!prev )
461
486
return ;
462
487
sel = curr = prev ;
@@ -473,6 +498,7 @@ keypress(XKeyEvent *ev)
473
498
sel -> out = 1 ;
474
499
break ;
475
500
case XK_Right :
501
+ case XK_KP_Right :
476
502
if (text [cursor ] != '\0' ) {
477
503
cursor = nextrune (+1 );
478
504
break ;
@@ -481,6 +507,7 @@ keypress(XKeyEvent *ev)
481
507
return ;
482
508
/* fallthrough */
483
509
case XK_Down :
510
+ case XK_KP_Down :
484
511
if (sel && sel -> right && (sel = sel -> right ) == next ) {
485
512
curr = next ;
486
513
calcoffsets ();
@@ -489,9 +516,9 @@ keypress(XKeyEvent *ev)
489
516
case XK_Tab :
490
517
if (!sel )
491
518
return ;
492
- strncpy ( text , sel -> text , sizeof text - 1 );
493
- text [ sizeof text - 1 ] = '\0' ;
494
- cursor = strlen ( text ) ;
519
+ cursor = strnlen ( sel -> text , sizeof text - 1 );
520
+ memcpy ( text , sel -> text , cursor ) ;
521
+ text [ cursor ] = '\0' ;
495
522
match ();
496
523
break ;
497
524
}
@@ -521,29 +548,27 @@ paste(void)
521
548
static void
522
549
readstdin (void )
523
550
{
524
- char buf [ sizeof text ], * p ;
525
- size_t i , imax = 0 , size = 0 ;
526
- unsigned int tmpmax = 0 ;
551
+ char * line = NULL ;
552
+ size_t i , itemsiz = 0 , linesiz = 0 ;
553
+ ssize_t len ;
527
554
528
555
/* read each line from stdin and add it to the item list */
529
- for (i = 0 ; fgets (buf , sizeof buf , stdin ); i ++ ) {
530
- if (i + 1 >= size / sizeof * items )
531
- if (!(items = realloc (items , (size += BUFSIZ ))))
532
- die ("cannot realloc %u bytes:" , size );
533
- if ((p = strchr (buf , '\n' )))
534
- * p = '\0' ;
535
- if (!(items [i ].text = strdup (buf )))
536
- die ("cannot strdup %u bytes:" , strlen (buf ) + 1 );
537
- items [i ].out = 0 ;
538
- drw_font_getexts (drw -> fonts , buf , strlen (buf ), & tmpmax , NULL );
539
- if (tmpmax > inputw ) {
540
- inputw = tmpmax ;
541
- imax = i ;
556
+ for (i = 0 ; (len = getline (& line , & linesiz , stdin )) != -1 ; i ++ ) {
557
+ if (i + 1 >= itemsiz ) {
558
+ itemsiz += 256 ;
559
+ if (!(items = realloc (items , itemsiz * sizeof (* items ))))
560
+ die ("cannot realloc %zu bytes:" , itemsiz * sizeof (* items ));
542
561
}
562
+ if (line [len - 1 ] == '\n' )
563
+ line [len - 1 ] = '\0' ;
564
+ if (!(items [i ].text = strdup (line )))
565
+ die ("strdup:" );
566
+
567
+ items [i ].out = 0 ;
543
568
}
569
+ free (line );
544
570
if (items )
545
571
items [i ].text = NULL ;
546
- inputw = items ? TEXTW (items [imax ].text ) : 0 ;
547
572
lines = MIN (lines , i );
548
573
}
549
574
@@ -634,7 +659,7 @@ setup(void)
634
659
/* no focused window is on screen, so use pointer location instead */
635
660
if (mon < 0 && !area && XQueryPointer (dpy , root , & dw , & dw , & x , & y , & di , & di , & du ))
636
661
for (i = 0 ; i < n ; i ++ )
637
- if (INTERSECT (x , y , 1 , 1 , info [i ]))
662
+ if (INTERSECT (x , y , 1 , 1 , info [i ]) != 0 )
638
663
break ;
639
664
640
665
x = info [i ].x_org ;
@@ -652,14 +677,14 @@ setup(void)
652
677
mw = wa .width ;
653
678
}
654
679
promptw = (prompt && * prompt ) ? TEXTW (prompt ) - lrpad / 4 : 0 ;
655
- inputw = MIN ( inputw , mw / 3 );
680
+ inputw = mw / 3 ; /* input width: ~33% of monitor width */
656
681
match ();
657
682
658
683
/* create menu window */
659
684
swa .override_redirect = True ;
660
685
swa .background_pixel = scheme [SchemeNorm ][ColBg ].pixel ;
661
686
swa .event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask ;
662
- win = XCreateWindow (dpy , parentwin , x , y , mw , mh , 0 ,
687
+ win = XCreateWindow (dpy , root , x , y , mw , mh , 0 ,
663
688
CopyFromParent , CopyFromParent , CopyFromParent ,
664
689
CWOverrideRedirect | CWBackPixel | CWEventMask , & swa );
665
690
XSetClassHint (dpy , win , & ch );
@@ -674,6 +699,7 @@ setup(void)
674
699
675
700
XMapRaised (dpy , win );
676
701
if (embed ) {
702
+ XReparentWindow (dpy , win , parentwin , x , y );
677
703
XSelectInput (dpy , parentwin , FocusChangeMask | SubstructureNotifyMask );
678
704
if (XQueryTree (dpy , parentwin , & dw , & w , & dws , & du ) && dws ) {
679
705
for (i = 0 ; i < du && dws [i ] != win ; ++ i )
@@ -689,9 +715,8 @@ setup(void)
689
715
static void
690
716
usage (void )
691
717
{
692
- fputs ("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
693
- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" , stderr );
694
- exit (1 );
718
+ die ("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
719
+ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]" );
695
720
}
696
721
697
722
int
0 commit comments