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>
41 #include <glibtop/xmalloc.h>
47 #include "wmAppKill.xpm"
48 #include "wmAppKill.h"
50 Display
*dpy
; /* xlib global vars */
58 _desc
*pList
= NULL
; /* double linked list */
59 _desc
*posProc
= NULL
; /* lower proc showed on the dock */
60 pid_t tabNoProc
[NB_LINE
]; /* array containing each line's pid */
61 pid_t lastProcPid
; /* oldest proc before refreshment */
62 char *procBaseName
= PROC_DEF
; /* procBase is NULL if we want all the proc to be listed */
63 int procBasePos
= 0; /* procbase's pos in linked list */
64 pid_t procBasePid
= 1; /* procbase's pid */
65 unsigned int gNbProc
= 0; /* proc number starting from procBase */
66 unsigned int gNbProcTotal
= 0; /* total proc number */
67 struct timeval timev
; /* to detect double-click */
69 void ZoneCreate(int x
, int y
, int width
, int height
, char no
)
74 fZone
= (_zone
*)malloc(sizeof(_zone
));
77 for (last
= fZone
; last
-> next
; last
= last
-> next
);
78 last
-> next
= (_zone
*)malloc(sizeof(_zone
));
84 last
-> width
= width
;
85 last
-> height
= height
;
94 Window root_ret
, child_ret
;
95 _zone
*curseur
= fZone
;
97 XQueryPointer(dpy
, iconWin
, &root_ret
, &child_ret
, &popo
, &popo
, &x
, &y
, &mask
); /* mouse position */
100 if ((x
>= curseur
-> x
) && (x
<= curseur
-> x
+ curseur
-> width
) && (y
>= curseur
-> y
) && (y
<= curseur
-> y
+ curseur
-> height
))
101 return curseur
-> no
;
104 while ((curseur
= curseur
-> next
));
109 void GarbageCollector(_desc
*garb
)
120 int CheckProc(pid_t pid
)
122 glibtop_proclist bof
;
125 if ((n
= glibtop_get_proclist (&bof
, GLIBTOP_KERN_PROC_PID
, (int64_t)pid
)) == NULL
) {
134 _desc
*GetProcList(void) /* create a double linked list */
136 glibtop_proclist buf
;
144 if ((n
= glibtop_get_proclist (&buf
, GLIBTOP_KERN_PROC_UID
, (int64_t)getuid())) == NULL
) {
145 fprintf(stderr
, "Problem using libgtop\n");
149 nbPr
= (int)buf
.number
;
151 glump
= (_desc
*)malloc(sizeof(_desc
));
155 for (i
= nbPr
; i
; i
--){
157 glibtop_proc_state buf
;
158 glump
-> previous
= lastOne
;
159 glump
-> next
= (_desc
*)malloc(sizeof(_desc
));
161 glibtop_get_proc_state(&buf
, glump
-> pid
= n
[i
- 1]);
162 strcpy(glump
-> name
, bof
= buf
.cmd
);
163 if (strlen(glump
-> name
) > MAX_CHAR
)
164 glump
-> name
[MAX_CHAR
] = 0;
167 glump
= glump
-> next
;
169 if (procBaseName
&& !strcmp(bof
, procBaseName
)) {
171 procBasePid
= n
[i
- 1];
176 lastOne
-> next
= NULL
;
177 lastProcPid
= n
[nbPr
- 1];
180 if (procBaseName
&& i
) gNbProc
= nbPr
- i
+ 1; /* procBase has been found */
181 else { /* procBaseName is null or hasn't been found */
193 int CheckProcToRemove(unsigned int *procList
, unsigned int procListSize
)
195 _desc
*curseur
= pList
, *temp
;
196 int nbProcRemoved
= 0, i
;
199 for (i
= procListSize
; i
; i
--)
200 if (curseur
-> pid
== procList
[i
- 1]) break;
203 curseur
= curseur
-> next
;
205 if (!i
) { /* we didn't find it in proclist, let's remove it */
212 return nbProcRemoved
;
215 int CheckProcToAdd(int pos
, unsigned int *procList
, unsigned int procListSize
)
219 glibtop_proc_state buf
;
221 for (i
= pos
; i
< procListSize
; i
++){
224 glump
= (_desc
*)malloc(sizeof(_desc
));
225 usleep(20000); /* libgtop seems to need a little bit of time */
226 if (CheckProc(procList
[i
])) continue; /* checking if the process isn't already dead */
228 glibtop_get_proc_state(&buf
, glump
-> pid
= procList
[i
]);
229 strcpy(glump
-> name
, buf
.cmd
);
230 if (strlen(glump
-> name
) > MAX_CHAR
)
231 glump
-> name
[MAX_CHAR
] = 0;
233 pList
-> previous
= glump
;
234 glump
-> next
= pList
;
235 glump
-> previous
= NULL
;
236 if (posProc
== pList
) posProc
= glump
;
241 lastProcPid
= glump
-> pid
;
247 int CheckProcChange(void)
249 glibtop_proclist buf
;
254 if ((n
= glibtop_get_proclist (&buf
, GLIBTOP_KERN_PROC_UID
, (int64_t)getuid())) == NULL
) return -1;
255 nbPr
= (int)buf
.number
;
257 if ((nbPr
== gNbProcTotal
) && (n
[nbPr
- 1] == lastProcPid
)) return 0; /* nothing changed */
259 if (procBaseName
&& (n
[procBasePos
] != procBasePid
)) /* some proc killed before the baseproc (=oldest proc) */
261 if (CheckProc(procBasePid
)) { /* baseproc doesn't exist anymore */
262 GarbageCollector(pList
);
263 pList
= GetProcList(); /* so we create a whole new list */
268 while (n
[--procBasePos
] != procBasePid
); /* here we find what's the new pos. of baseproc */
272 diffNbProc
= (nbPr
- procBasePos
) - gNbProc
; /* nb of changes after baseproc */
274 if (diffNbProc
== 0 && (n
[nbPr
- 1] == lastProcPid
)){ /* only changes before baseproc */
280 if (diffNbProc
> 0 && n
[nbPr
- diffNbProc
- 1] == lastProcPid
) /* only proc to add */
281 CheckProcToAdd(nbPr
- diffNbProc
, n
, nbPr
);
283 else { /* to remove [and to add] */
285 nb
= CheckProcToRemove(n
, nbPr
);
286 if (nb
!= -diffNbProc
)
287 CheckProcToAdd(nbPr
- diffNbProc
- 1, n
, nbPr
);
294 void RemoveProc(_desc
*cible
)
296 _desc
*temp1
, *temp2
;
301 temp1
= cible
-> previous
;
302 temp2
= cible
-> next
;
304 for (curseur
= cible
, i
= 0; curseur
&& i
!= NB_LINE
+ 1; curseur
= curseur
-> next
, ++i
);
306 if (!(gNbProc
- 1 < NB_LINE
) && (i
== 2 || i
== 3)) { /* the killed proc is near the start of the list */
307 for (--i
, curseur
= posProc
; i
&& curseur
-> previous
; curseur
= curseur
-> previous
, --i
);
310 else if ((cible
== posProc
) && (cible
-> previous
)) {
311 posProc
= cible
-> previous
;
313 else if ((cible
== posProc
) && (cible
-> next
)) {
314 posProc
= cible
-> next
;
317 if (temp1
) temp1
-> next
= temp2
;
320 temp2
-> previous
= NULL
;
322 lastProcPid
= temp2
-> pid
;
327 if (temp2
) temp2
-> previous
= temp1
;
329 temp1
-> next
= NULL
;
336 void ShowString (int x
, int y
, char *doudou
)
341 while ((c
= tolower(doudou
[i
++]))){
342 if (c
>= 'a' && c
<= 'z') {
343 XCopyArea(dpy
,XPM
, win
,gc
, 1 + (c
- 'a') * 6, 10, 5, 8, x
, y
) ;
344 XCopyArea(dpy
,XPM
, iconWin
,gc
, 1 + (c
- 'a') * 6, 10, 5, 8, x
, y
) ;
352 XClearWindow(dpy
, win
);
353 XClearWindow(dpy
, iconWin
);
355 XCopyArea(dpy
, XPM
,win
, gc
, 1 + (26) * 6, 10, 6, 8, 5, 51);
356 XCopyArea(dpy
, XPM
, iconWin
, gc
, 1 + (26) * 6, 10, 6, 8, 5, 51);
357 XCopyArea(dpy
, XPM
, win
, gc
, 1 + (27) * 6, 10, 6, 8, 53, 51);
358 XCopyArea(dpy
, XPM
, iconWin
, gc
, 1 + (27) * 6, 10, 6, 8, 53, 51);
360 XCopyArea(dpy
, XPM
, win
, gc
, 106, 0, 28, 8, 17, 50);
361 XCopyArea(dpy
, XPM
, iconWin
, gc
, 106, 0, 28, 8, 17, 50);
371 for (i
= NB_LINE
; i
; i
--){
372 XCopyArea(dpy
, XPM
, win
, gc
, 2, 22, 53, 9, X_PROC
+ 1, Y_PROC
+ ((i
- 1) * 10));
373 XCopyArea(dpy
, XPM
, iconWin
, gc
, 2, 22, 53, 9, X_PROC
+ 1, Y_PROC
+ ((i
- 1) * 10));
376 if (gNbProc
< NB_LINE
) {
379 for (y
= NB_LINE
; y
!= gNbProc
; y
--) tabNoProc
[y
- 1] = -1;
383 for (curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--)
385 ShowString(X_PROC
+ 1, Y_PROC
+ (i
- 1) * 10, curseur
-> name
);
386 tabNoProc
[i
- 1] = curseur
-> pid
;
390 void DoClick(XEvent ev
)
392 unsigned char doubleClick
= 0;
393 static unsigned char firstClick
= 0;
399 if (ev
.xbutton
.button
== CLICK_TWO
) {
403 /* Mouse wheel patch by Mathieu Cuny */
405 if (ev
.xbutton
.button
== WHEEL_UP
&& gNbProc
> NB_LINE
) {
406 for (i
= NB_LINE
, curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--);
407 if (curseur
) posProc
= posProc
-> next
;
411 if (ev
.xbutton
.button
== WHEEL_DOWN
&& posProc
-> previous
&& gNbProc
> NB_LINE
) {
412 posProc
= posProc
-> previous
;
416 /* Mouse wheel patch end */
418 if (ev
.xbutton
.button
== CLICK_ONE
) {
423 gettimeofday(&temp
, NULL
);
424 nms1
= temp
.tv_sec
- timev
.tv_sec
; /* nb sec since last click */
426 if ((!nms1
|| nms1
== 1)){
427 long long yop
= (nms1
* 1000000L) + (temp
.tv_usec
- timev
.tv_usec
); /* nb mlsec since last click */
428 if (firstClick
&& (yop
< DOUBLE_CLICK_DELAY
)){ /* we got double click */
431 } else firstClick
= 1;
432 } else firstClick
= 1;
436 if (zone
== UP
&& !doubleClick
&& gNbProc
> NB_LINE
)
438 for (i
= NB_LINE
, curseur
= posProc
; i
; curseur
= curseur
-> next
, i
--);
439 if (curseur
) posProc
= posProc
-> next
;
443 else if (zone
== DOWN
&& posProc
-> previous
&& !doubleClick
&& gNbProc
> NB_LINE
)
445 posProc
= posProc
-> previous
;
449 else if (zone
== UP
&& doubleClick
&& gNbProc
> NB_LINE
)
452 for (curseur
= pList
; curseur
-> next
; curseur
= curseur
-> next
); /* curseur = end of list */
454 for (i
= NB_LINE
- 1; i
; curseur
= curseur
-> previous
, i
--);
459 else if (zone
== DOWN
&& doubleClick
&& gNbProc
> NB_LINE
)
465 else if (zone
> 0 && zone
<= NB_LINE
&& doubleClick
&& tabNoProc
[zone
- 1] != -1)
467 kill(tabNoProc
[zone
- 1], SIGKILL
); /* let's kill the mofo */
468 waitpid(tabNoProc
[zone
- 1], NULL
, 0);
471 if (doubleClick
) doubleClick
= 0;
478 unsigned long long compteur
= 0;
484 if (CheckProcChange()) DoExpose();
485 compteur
= UPDATE_NB
* DELAY
;
487 while(XPending(dpy
)){
490 case Expose
: DoExp(); break;
491 case ButtonPress
: DoClick(ev
); break;
499 void PrintUsage(void)
501 printf("usage: wmAppKill [-a] [-n <name>] [-h]\n");
502 printf("\t-a\t\tSelect all processes\n");
503 printf("\t-n <name>\tDo not select processes older than <name> (default: wmaker)\n");
504 printf("\t-h\t\tDisplay help screen\n");
507 void GetArg(int argc
, char *argv
[])
509 if (argc
== 1) return;
511 else if (argc
== 3 && !strcmp(argv
[1], "-n") && argv
[2][0] != '-')
512 procBaseName
= strdup(argv
[2]);
514 else if (argc
== 2 && !strcmp(argv
[1], "-a"))
517 else if (argc
== 2 && !strcmp(argv
[1], "-h"))
528 void CreateDock(int argc
, char *argv
[]) /* this part comes from http://www.linuxmag-france.org/ */
532 XSizeHints sizeHints
;
533 XClassHint classHint
;
535 unsigned long p_blanc
;
536 unsigned long p_noir
;
537 unsigned int borderWidth
= 2;
538 char *wname
= argv
[0] ;
540 dpy
= XOpenDisplay(NULL
) ;
544 fprintf(stderr
, "Can't open display\n") ;
548 root
= RootWindow(dpy
,screen
);
549 p_blanc
= WhitePixel(dpy
,screen
) ;
550 p_noir
= BlackPixel(dpy
,screen
) ;
551 gc
= XDefaultGC(dpy
,screen
) ;
552 XSetForeground(dpy
, gc
, p_noir
);
553 XSetBackground(dpy
, gc
,p_noir
);
557 sizeHints
.width
= 64 ;
558 sizeHints
.height
= 64 ;
560 win
= XCreateSimpleWindow(dpy
,root
,sizeHints
.x
,sizeHints
.y
, sizeHints
.width
, sizeHints
.height
, borderWidth
, p_noir
,p_noir
) ;
561 iconWin
= XCreateSimpleWindow(dpy
,root
,sizeHints
.x
,sizeHints
.y
,sizeHints
.width
, sizeHints
.height
, borderWidth
, p_noir
,p_noir
) ;
563 sizeHints
.flags
= USSize
| USPosition
;
564 XSetWMNormalHints(dpy
,win
,&sizeHints
) ;
565 wmHints
.initial_state
= WithdrawnState
;
566 wmHints
.icon_window
= iconWin
;
567 wmHints
.icon_x
= sizeHints
.x
;
568 wmHints
.icon_y
= sizeHints
.y
;
569 wmHints
.window_group
= win
;
570 wmHints
.flags
= StateHint
| IconWindowHint
| IconPositionHint
| WindowGroupHint
;
571 XSetWMHints(dpy
, win
, &wmHints
) ;
572 classHint
.res_name
= wname
;
573 classHint
.res_class
= wname
;
575 XSetClassHint(dpy
, win
, &classHint
) ;
576 XSetCommand(dpy
,win
, argv
, argc
) ;
578 pixmask
= XCreateBitmapFromData(dpy
,win
,fond_bits
, fond_width
, fond_height
) ;
579 XShapeCombineMask(dpy
,win
,ShapeBounding
,0,0,pixmask
,ShapeSet
) ;
580 XShapeCombineMask(dpy
,iconWin
,ShapeBounding
, 0, 0, pixmask
, ShapeSet
) ;
581 XpmCreatePixmapFromData(dpy
,root
,wmAppKill_xpm
, &XPM
, NULL
,NULL
) ;
583 XSelectInput(dpy
,win
, ExposureMask
| ButtonPressMask
) ;
584 XSelectInput(dpy
,iconWin
, ExposureMask
| ButtonPressMask
) ;
586 XMapWindow(dpy
,win
) ;
589 int main(int argc
, char *argv
[])
595 CreateDock(argc
, argv
);
596 gettimeofday(&timev
, NULL
);
598 pList
= GetProcList();
601 ZoneCreate(4, 50, 8, 8, UP
);
602 ZoneCreate(54, 50, 8, 8, DOWN
);
604 for (i
= NB_LINE
; i
; i
--)
605 ZoneCreate(X_PROC
+ 1, Y_PROC
+ (i
- 1) * 10 + 2, 48, 7, i
);