3 * wmAppKill v0.2 - S.Rozange
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING); if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA
30 #include <X11/Xutil.h>
31 #include <X11/extensions/shape.h>
33 #include <sys/types.h>
35 #include <sys/resource.h>
39 #include <glibtop/proclist.h>
40 #include <glibtop/procstate.h>
46 #include "wmAppKill.xpm"
47 #include "wmAppKill.h"
49 Display
*dpy
; /* xlib global vars */
57 _desc
*pList
= NULL
; /* double linked list */
58 _desc
*posProc
= NULL
; /* lower proc showed on the dock */
59 pid_t tabNoProc
[NB_LINE
]; /* array containing each line's pid */
60 pid_t lastProcPid
; /* oldest proc before refreshment */
61 char *procBaseName
= PROC_DEF
; /* procBase is NULL if we want all the proc to be listed */
62 int procBasePos
= 0; /* procbase's pos in linked list */
63 pid_t procBasePid
= 1; /* procbase's pid */
64 unsigned int gNbProc
= 0; /* proc number starting from procBase */
65 unsigned int gNbProcTotal
= 0; /* total proc number */
66 struct timeval timev
; /* to detect double-click */
68 void ZoneCreate(int x
, int y
, int width
, int height
, char no
)
73 fZone
= (_zone
*)malloc(sizeof(_zone
));
76 for (last
= fZone
; last
-> next
; last
= last
-> next
);
77 last
-> next
= (_zone
*)malloc(sizeof(_zone
));
83 last
-> width
= width
;
84 last
-> height
= height
;
93 Window root_ret
, child_ret
;
94 _zone
*curseur
= fZone
;
96 XQueryPointer(dpy
, iconWin
, &root_ret
, &child_ret
, &popo
, &popo
, &x
, &y
, &mask
); /* mouse position */
99 if ((x
>= curseur
-> x
) && (x
<= curseur
-> x
+ curseur
-> width
) && (y
>= curseur
-> y
) && (y
<= curseur
-> y
+ curseur
-> height
))
100 return curseur
-> no
;
103 while ((curseur
= curseur
-> next
));
108 void GarbageCollector(_desc
*garb
)
119 int CheckProc(pid_t pid
)
121 glibtop_proclist bof
;
124 if ((n
= glibtop_get_proclist (&bof
, GLIBTOP_KERN_PROC_PID
, (int64_t)pid
)) == NULL
) {
133 _desc
*GetProcList(void) /* create a double linked list */
135 glibtop_proclist buf
;
143 if ((n
= glibtop_get_proclist (&buf
, GLIBTOP_KERN_PROC_UID
, (int64_t)getuid())) == NULL
) {
144 fprintf(stderr
, "Problem using libgtop\n");
148 nbPr
= (int)buf
.number
;
150 glump
= (_desc
*)malloc(sizeof(_desc
));
154 for (i
= nbPr
; i
; i
--){
156 glibtop_proc_state buf
;
157 glump
-> previous
= lastOne
;
158 glump
-> next
= (_desc
*)malloc(sizeof(_desc
));
160 glibtop_get_proc_state(&buf
, glump
-> pid
= n
[i
- 1]);
161 strcpy(glump
-> name
, bof
= buf
.cmd
);
162 if (strlen(glump
-> name
) > MAX_CHAR
)
163 glump
-> name
[MAX_CHAR
] = 0;
166 glump
= glump
-> next
;
168 if (procBaseName
&& !strcmp(bof
, procBaseName
)) {
170 procBasePid
= n
[i
- 1];
175 lastOne
-> next
= NULL
;
176 lastProcPid
= n
[nbPr
- 1];
179 if (procBaseName
&& i
) gNbProc
= nbPr
- i
+ 1; /* procBase has been found */
180 else { /* procBaseName is null or hasn't been found */
192 int CheckProcToRemove(unsigned int *procList
, unsigned int procListSize
)
194 _desc
*curseur
= pList
, *temp
;
195 int nbProcRemoved
= 0, i
;
198 for (i
= procListSize
; i
; i
--)
199 if (curseur
-> pid
== procList
[i
- 1]) break;
202 curseur
= curseur
-> next
;
204 if (!i
) { /* we didn't find it in proclist, let's remove it */
211 return nbProcRemoved
;
214 int CheckProcToAdd(int pos
, unsigned int *procList
, unsigned int procListSize
)
218 glibtop_proc_state buf
;
220 for (i
= pos
; i
< procListSize
; i
++){
223 glump
= (_desc
*)malloc(sizeof(_desc
));
224 usleep(20000); /* libgtop seems to need a little bit of time */
225 if (CheckProc(procList
[i
])) continue; /* checking if the process isn't already dead */
227 glibtop_get_proc_state(&buf
, glump
-> pid
= procList
[i
]);
228 strcpy(glump
-> name
, buf
.cmd
);
229 if (strlen(glump
-> name
) > MAX_CHAR
)
230 glump
-> name
[MAX_CHAR
] = 0;
232 pList
-> previous
= glump
;
233 glump
-> next
= pList
;
234 glump
-> previous
= NULL
;
235 if (posProc
== pList
) posProc
= glump
;
240 lastProcPid
= glump
-> pid
;
246 int CheckProcChange(void)
248 glibtop_proclist buf
;
253 if ((n
= glibtop_get_proclist (&buf
, GLIBTOP_KERN_PROC_UID
, (int64_t)getuid())) == NULL
) return -1;
254 nbPr
= (int)buf
.number
;
256 if ((nbPr
== gNbProcTotal
) && (n
[nbPr
- 1] == lastProcPid
)) return 0; /* nothing changed */
258 if (procBaseName
&& (n
[procBasePos
] != procBasePid
)) /* some proc killed before the baseproc (=oldest proc) */
260 if (CheckProc(procBasePid
)) { /* baseproc doesn't exist anymore */
261 GarbageCollector(pList
);
262 pList
= GetProcList(); /* so we create a whole new list */
267 while (n
[--procBasePos
] != procBasePid
); /* here we find what's the new pos. of baseproc */
271 diffNbProc
= (nbPr
- procBasePos
) - gNbProc
; /* nb of changes after baseproc */
273 if (diffNbProc
== 0 && (n
[nbPr
- 1] == lastProcPid
)){ /* only changes before baseproc */
279 if (diffNbProc
> 0 && n
[nbPr
- diffNbProc
- 1] == lastProcPid
) /* only proc to add */
280 CheckProcToAdd(nbPr
- diffNbProc
, n
, nbPr
);
282 else { /* to remove [and to add] */
284 nb
= CheckProcToRemove(n
, nbPr
);
285 if (nb
!= -diffNbProc
)
286 CheckProcToAdd(nbPr
- diffNbProc
- 1, n
, nbPr
);
293 void RemoveProc(_desc
*cible
)
295 _desc
*temp1
, *temp2
;
300 temp1
= cible
-> previous
;
301 temp2
= cible
-> next
;
303 for (curseur
= cible
, i
= 0; curseur
&& i
!= NB_LINE
+ 1; curseur
= curseur
-> next
, ++i
);
305 if (!(gNbProc
- 1 < NB_LINE
) && (i
== 2 || i
== 3)) { /* the killed proc is near the start of the list */
306 for (--i
, curseur
= posProc
; i
&& curseur
-> previous
; curseur
= curseur
-> previous
, --i
);
309 else if ((cible
== posProc
) && (cible
-> previous
)) {
310 posProc
= cible
-> previous
;
312 else if ((cible
== posProc
) && (cible
-> next
)) {
313 posProc
= cible
-> next
;
316 if (temp1
) temp1
-> next
= temp2
;
319 temp2
-> previous
= NULL
;
321 lastProcPid
= temp2
-> pid
;
326 if (temp2
) temp2
-> previous
= temp1
;
328 temp1
-> next
= NULL
;
335 void ShowString (int x
, int y
, char *doudou
)
340 while ((c
= tolower(doudou
[i
++]))){
341 if (c
>= 'a' && c
<= 'z') {
342 XCopyArea(dpy
,XPM
, win
,gc
, 1 + (c
- 'a') * 6, 10, 5, 8, x
, y
) ;
343 XCopyArea(dpy
,XPM
, iconWin
,gc
, 1 + (c
- 'a') * 6, 10, 5, 8, x
, y
) ;
351 XClearWindow(dpy
, win
);
352 XClearWindow(dpy
, iconWin
);
354 XCopyArea(dpy
, XPM
,win
, gc
, 1 + (26) * 6, 10, 6, 8, 5, 51);
355 XCopyArea(dpy
, XPM
, iconWin
, gc
, 1 + (26) * 6, 10, 6, 8, 5, 51);
356 XCopyArea(dpy
, XPM
, win
, gc
, 1 + (27) * 6, 10, 6, 8, 53, 51);
357 XCopyArea(dpy
, XPM
, iconWin
, gc
, 1 + (27) * 6, 10, 6, 8, 53, 51);
359 XCopyArea(dpy
, XPM
, win
, gc
, 106, 0, 28, 8, 17, 50);
360 XCopyArea(dpy
, XPM
, iconWin
, gc
, 106, 0, 28, 8, 17, 50);
370 for (i
= NB_LINE
; i
; i
--){
371 XCopyArea(dpy
, XPM
, win
, gc
, 2, 22, 53, 9, X_PROC
+ 1, Y_PROC
+ ((i
- 1) * 10));
372 XCopyArea(dpy
, XPM
, iconWin
, gc
, 2, 22, 53, 9, X_PROC
+ 1, Y_PROC
+ ((i
- 1) * 10));
375 if (gNbProc
< NB_LINE
) {
378 for (y
= NB_LINE
; y
!= gNbProc
; y
--) tabNoProc
[y
- 1] = -1;
382 for (curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--)
384 ShowString(X_PROC
+ 1, Y_PROC
+ (i
- 1) * 10, curseur
-> name
);
385 tabNoProc
[i
- 1] = curseur
-> pid
;
389 void DoClick(XEvent ev
)
391 unsigned char doubleClick
= 0;
392 static unsigned char firstClick
= 0;
398 if (ev
.xbutton
.button
== CLICK_TWO
) {
402 /* Mouse wheel patch by Mathieu Cuny */
404 if (ev
.xbutton
.button
== WHEEL_UP
&& gNbProc
> NB_LINE
) {
405 for (i
= NB_LINE
, curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--);
406 if (curseur
) posProc
= posProc
-> next
;
410 if (ev
.xbutton
.button
== WHEEL_DOWN
&& posProc
-> previous
&& gNbProc
> NB_LINE
) {
411 posProc
= posProc
-> previous
;
415 /* Mouse wheel patch end */
417 if (ev
.xbutton
.button
== CLICK_ONE
) {
422 gettimeofday(&temp
, NULL
);
423 nms1
= temp
.tv_sec
- timev
.tv_sec
; /* nb sec since last click */
425 if ((!nms1
|| nms1
== 1)){
426 long long yop
= (nms1
* 1000000L) + (temp
.tv_usec
- timev
.tv_usec
); /* nb mlsec since last click */
427 if (firstClick
&& (yop
< DOUBLE_CLICK_DELAY
)){ /* we got double click */
430 } else firstClick
= 1;
431 } else firstClick
= 1;
435 if (zone
== UP
&& !doubleClick
&& gNbProc
> NB_LINE
)
437 for (i
= NB_LINE
, curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--);
438 if (curseur
) posProc
= posProc
-> next
;
442 else if (zone
== DOWN
&& posProc
-> previous
&& !doubleClick
&& gNbProc
> NB_LINE
)
444 posProc
= posProc
-> previous
;
448 else if (zone
== UP
&& doubleClick
&& gNbProc
> NB_LINE
)
451 for (curseur
= pList
; curseur
-> next
; curseur
= curseur
-> next
); /* curseur = end of list */
453 for (i
= NB_LINE
- 1; i
; curseur
= curseur
-> previous
, i
--);
458 else if (zone
== DOWN
&& doubleClick
&& gNbProc
> NB_LINE
)
464 else if (zone
> 0 && zone
<= NB_LINE
&& doubleClick
&& tabNoProc
[zone
- 1] != -1)
466 kill(tabNoProc
[zone
- 1], SIGKILL
); /* let's kill the mofo */
467 waitpid(tabNoProc
[zone
- 1], NULL
, 0);
470 if (doubleClick
) doubleClick
= 0;
477 unsigned long long compteur
= 0;
483 if (CheckProcChange()) DoExpose();
484 compteur
= UPDATE_NB
* DELAY
;
486 while(XPending(dpy
)){
489 case Expose
: DoExp(); break;
490 case ButtonPress
: DoClick(ev
); break;
498 void PrintUsage(void)
500 printf("usage: wmAppKill [-a] [-n <name>] [-h]\n");
501 printf("\t-a\t\tSelect all processes\n");
502 printf("\t-n <name>\tDo not select processes older than <name> (default: wmaker)\n");
503 printf("\t-h\t\tDisplay help screen\n");
506 void GetArg(int argc
, char *argv
[])
508 if (argc
== 1) return;
510 else if (argc
== 3 && !strcmp(argv
[1], "-n") && argv
[2][0] != '-')
511 procBaseName
= strdup(argv
[2]);
513 else if (argc
== 2 && !strcmp(argv
[1], "-a"))
516 else if (argc
== 2 && !strcmp(argv
[1], "-h"))
527 void CreateDock(int argc
, char *argv
[]) /* this part comes from http://www.linuxmag-france.org/ */
531 XSizeHints sizeHints
;
532 XClassHint classHint
;
534 unsigned long p_blanc
;
535 unsigned long p_noir
;
536 unsigned int borderWidth
= 2;
537 char *wname
= argv
[0] ;
539 dpy
= XOpenDisplay(NULL
) ;
543 fprintf(stderr
, "Can't open display\n") ;
547 root
= RootWindow(dpy
,screen
);
548 p_blanc
= WhitePixel(dpy
,screen
) ;
549 p_noir
= BlackPixel(dpy
,screen
) ;
550 gc
= XDefaultGC(dpy
,screen
) ;
551 XSetForeground(dpy
, gc
, p_noir
);
552 XSetBackground(dpy
, gc
,p_noir
);
556 sizeHints
.width
= 64 ;
557 sizeHints
.height
= 64 ;
559 win
= XCreateSimpleWindow(dpy
,root
,sizeHints
.x
,sizeHints
.y
, sizeHints
.width
, sizeHints
.height
, borderWidth
, p_noir
,p_noir
) ;
560 iconWin
= XCreateSimpleWindow(dpy
,root
,sizeHints
.x
,sizeHints
.y
,sizeHints
.width
, sizeHints
.height
, borderWidth
, p_noir
,p_noir
) ;
562 sizeHints
.flags
= USSize
| USPosition
;
563 XSetWMNormalHints(dpy
,win
,&sizeHints
) ;
564 wmHints
.initial_state
= WithdrawnState
;
565 wmHints
.icon_window
= iconWin
;
566 wmHints
.icon_x
= sizeHints
.x
;
567 wmHints
.icon_y
= sizeHints
.y
;
568 wmHints
.window_group
= win
;
569 wmHints
.flags
= StateHint
| IconWindowHint
| IconPositionHint
| WindowGroupHint
;
570 XSetWMHints(dpy
, win
, &wmHints
) ;
571 classHint
.res_name
= wname
;
572 classHint
.res_class
= wname
;
574 XSetClassHint(dpy
, win
, &classHint
) ;
575 XSetCommand(dpy
,win
, argv
, argc
) ;
577 pixmask
= XCreateBitmapFromData(dpy
,win
,fond_bits
, fond_width
, fond_height
) ;
578 XShapeCombineMask(dpy
,win
,ShapeBounding
,0,0,pixmask
,ShapeSet
) ;
579 XShapeCombineMask(dpy
,iconWin
,ShapeBounding
, 0, 0, pixmask
, ShapeSet
) ;
580 XpmCreatePixmapFromData(dpy
,root
,wmAppKill_xpm
, &XPM
, NULL
,NULL
) ;
582 XSelectInput(dpy
,win
, ExposureMask
| ButtonPressMask
) ;
583 XSelectInput(dpy
,iconWin
, ExposureMask
| ButtonPressMask
) ;
585 XMapWindow(dpy
,win
) ;
588 int main(int argc
, char *argv
[])
594 CreateDock(argc
, argv
);
595 gettimeofday(&timev
, NULL
);
597 pList
= GetProcList();
600 ZoneCreate(4, 50, 8, 8, UP
);
601 ZoneCreate(54, 50, 8, 8, DOWN
);
603 for (i
= NB_LINE
; i
; i
--)
604 ZoneCreate(X_PROC
+ 1, Y_PROC
+ (i
- 1) * 10 + 2, 48, 7, i
);