/* * wmAppKill v0.2 - S.Rozange * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fond.xbm" #include "wmAppKill.xpm" #include "wmAppKill.h" Display *dpy; /* xlib global vars */ GC gc; Window win; Window iconWin; Pixmap XPM; int screen; _zone *fZone = NULL; _desc *pList = NULL; /* double linked list */ _desc *posProc = NULL; /* lower proc showed on the dock */ pid_t tabNoProc[NB_LINE]; /* array containing each line's pid */ pid_t lastProcPid; /* oldest proc before refreshment */ char *procBaseName = PROC_DEF; /* procBase is NULL if we want all the proc to be listed */ int procBasePos = 0; /* procbase's pos in linked list */ pid_t procBasePid = 1; /* procbase's pid */ unsigned int gNbProc = 0; /* proc number starting from procBase */ unsigned int gNbProcTotal = 0; /* total proc number */ struct timeval timev; /* to detect double-click */ void ZoneCreate(int x, int y, int width, int height, char no) { _zone *last; if (!fZone) { fZone = (_zone *)malloc(sizeof(_zone)); last = fZone; } else { for (last = fZone; last -> next; last = last -> next); last -> next = (_zone *)malloc(sizeof(_zone)); last = last -> next; } last -> x = x; last -> y = y; last -> width = width; last -> height = height; last -> no = no; last -> next = NULL; } char CheckZone(void) { int x, y,popo; unsigned int mask; Window root_ret, child_ret; _zone *curseur = fZone; XQueryPointer(dpy, iconWin, &root_ret, &child_ret, &popo, &popo, &x, &y, &mask); /* mouse position */ do { if ((x >= curseur -> x) && (x <= curseur -> x + curseur -> width) && (y >= curseur -> y) && (y <= curseur -> y + curseur -> height)) return curseur -> no; } while ((curseur = curseur -> next)); return 0; } void GarbageCollector(_desc *garb) { _desc *next; while (garb) { next = garb -> next; free(garb); garb = next; } } int CheckProc(pid_t pid) { glibtop_proclist bof; unsigned int *n; if ((n = glibtop_get_proclist (&bof, GLIBTOP_KERN_PROC_PID , (int64_t)pid)) == NULL) { g_free(n); return -1; } g_free(n); return 0; } _desc *GetProcList(void) /* create a double linked list */ { glibtop_proclist buf; unsigned int *n; unsigned int nbPr; int i; _desc *lastOne; _desc *glump; _desc *res; if ((n = glibtop_get_proclist (&buf, GLIBTOP_KERN_PROC_UID, (int64_t)getuid())) == NULL) { fprintf(stderr, "Problem using libgtop\n"); exit(1); }; nbPr = (int)buf.number; glump = (_desc *)malloc(sizeof(_desc)); res = glump; lastOne = NULL; for (i = nbPr; i; i--){ char *bof; glibtop_proc_state buf; glump -> previous = lastOne; glump -> next = (_desc *)malloc(sizeof(_desc)); glibtop_get_proc_state(&buf, glump -> pid = n[i - 1]); strcpy(glump -> name, bof = buf.cmd); if (strlen(glump -> name) > MAX_CHAR) glump -> name[MAX_CHAR] = 0; lastOne = glump; glump = glump -> next; if (procBaseName && !strcmp(bof, procBaseName)) { procBasePos = i - 1; procBasePid = n[i - 1]; break; } } lastOne -> next = NULL; lastProcPid = n[nbPr - 1]; g_free(n); if (procBaseName && i) gNbProc = nbPr - i + 1; /* procBase has been found */ else { /* procBaseName is null or hasn't been found */ procBaseName = NULL; procBasePos = 0; procBasePid = n[0]; gNbProc = nbPr; } gNbProcTotal = nbPr; return res; } int CheckProcToRemove(unsigned int *procList, unsigned int procListSize) { _desc *curseur = pList, *temp; int nbProcRemoved = 0, i; while (curseur) { for (i = procListSize; i; i--) if (curseur -> pid == procList[i - 1]) break; temp = curseur; curseur = curseur -> next; if (!i) { /* we didn't find it in proclist, let's remove it */ RemoveProc(temp); gNbProc--; nbProcRemoved++; } } return nbProcRemoved; } int CheckProcToAdd(int pos, unsigned int *procList, unsigned int procListSize) { _desc *glump; int i, compteur = 0; glibtop_proc_state buf; for (i = pos; i < procListSize ; i++){ compteur++; glump = (_desc *)malloc(sizeof(_desc)); usleep(20000); /* libgtop seems to need a little bit of time */ if (CheckProc(procList[i])) continue; /* checking if the process isn't already dead */ glibtop_get_proc_state(&buf, glump -> pid = procList[i]); strcpy(glump -> name, buf.cmd); if (strlen(glump -> name) > MAX_CHAR) glump -> name[MAX_CHAR] = 0; pList -> previous = glump; glump -> next = pList; glump -> previous = NULL; if (posProc == pList) posProc = glump; pList = glump; gNbProc++; gNbProcTotal++; lastProcPid = glump -> pid; } return compteur; } int CheckProcChange(void) { glibtop_proclist buf; unsigned int *n; unsigned int nbPr; int diffNbProc; if ((n = glibtop_get_proclist (&buf, GLIBTOP_KERN_PROC_UID, (int64_t)getuid())) == NULL) return -1; nbPr = (int)buf.number; if ((nbPr == gNbProcTotal) && (n[nbPr - 1] == lastProcPid)) return 0; /* nothing changed */ if (procBaseName && (n[procBasePos] != procBasePid)) /* some proc killed before the baseproc (=oldest proc) */ { if (CheckProc(procBasePid)) { /* baseproc doesn't exist anymore */ GarbageCollector(pList); pList = GetProcList(); /* so we create a whole new list */ posProc = pList; return 1; } else while (n[--procBasePos] != procBasePid); /* here we find what's the new pos. of baseproc */ } diffNbProc = (nbPr - procBasePos) - gNbProc; /* nb of changes after baseproc */ if (diffNbProc == 0 && (n[nbPr - 1] == lastProcPid)){ /* only changes before baseproc */ gNbProcTotal = nbPr; g_free(n); return 0; } if (diffNbProc > 0 && n[nbPr - diffNbProc - 1] == lastProcPid) /* only proc to add */ CheckProcToAdd(nbPr - diffNbProc, n, nbPr); else { /* to remove [and to add] */ int nb; nb = CheckProcToRemove(n, nbPr); if (nb != -diffNbProc) CheckProcToAdd(nbPr - diffNbProc - 1, n, nbPr); } g_free(n); return 1; } void RemoveProc(_desc *cible) { _desc *temp1, *temp2; _desc *curseur; int i; temp1 = cible -> previous; temp2 = cible -> next; for (curseur = cible, i = 0; curseur && i != NB_LINE + 1; curseur = curseur -> next, ++i); if (!(gNbProc - 1 < NB_LINE) && (i == 2 || i == 3)) { /* the killed proc is near the start of the list */ for (--i, curseur = posProc; i && curseur -> previous; curseur = curseur -> previous, --i); posProc = curseur; } else if ((cible == posProc) && (cible -> previous)) { posProc = cible -> previous; } else if ((cible == posProc) && (cible -> next)) { posProc = cible -> next; } if (temp1) temp1 -> next = temp2; else { pList = temp2; temp2 -> previous = NULL; gNbProcTotal--; lastProcPid = temp2 -> pid; free(cible); return; } if (temp2) temp2 -> previous = temp1; else temp1 -> next = NULL; free(cible); gNbProcTotal--; } void ShowString (int x, int y, char *doudou) { int i = 0; char c; while ((c = tolower(doudou[i++]))){ if (c >= 'a' && c <= 'z') { XCopyArea(dpy,XPM, win,gc, 1 + (c - 'a') * 6, 10, 5, 8, x, y) ; XCopyArea(dpy,XPM, iconWin,gc, 1 + (c - 'a') * 6, 10, 5, 8, x, y) ; x += 6; } } } void DoExp(){ XClearWindow(dpy, win); XClearWindow(dpy, iconWin); XCopyArea(dpy, XPM ,win, gc, 1 + (26) * 6, 10, 6, 8, 5, 51); XCopyArea(dpy, XPM, iconWin, gc, 1 + (26) * 6, 10, 6, 8, 5, 51); XCopyArea(dpy, XPM, win, gc, 1 + (27) * 6, 10, 6, 8, 53, 51); XCopyArea(dpy, XPM, iconWin, gc, 1 + (27) * 6, 10, 6, 8, 53, 51); XCopyArea(dpy, XPM, win, gc, 106, 0, 28, 8, 17, 50); XCopyArea(dpy, XPM, iconWin, gc, 106, 0, 28, 8, 17, 50); DoExpose(); } void DoExpose() { int i; _desc *curseur; for (i = NB_LINE; i; i--){ XCopyArea(dpy, XPM, win, gc, 2, 22, 53, 9, X_PROC + 1, Y_PROC + ((i - 1) * 10)); XCopyArea(dpy, XPM, iconWin, gc, 2, 22, 53, 9, X_PROC + 1, Y_PROC + ((i - 1) * 10)); } if (gNbProc < NB_LINE) { int y; i = gNbProc; for (y = NB_LINE; y != gNbProc; y--) tabNoProc[y - 1] = -1; } else i = NB_LINE; for (curseur = posProc; i; curseur = curseur -> next, i--) { ShowString(X_PROC + 1, Y_PROC + (i - 1) * 10, curseur -> name); tabNoProc[i - 1] = curseur -> pid; } } void DoClick(XEvent ev) { unsigned char doubleClick = 0; static unsigned char firstClick = 0; _desc *curseur; char zone, i; zone = CheckZone(); if (ev.xbutton.button == CLICK_TWO) { DoExpose() ; } /* Mouse wheel patch by Mathieu Cuny */ if (ev.xbutton.button == WHEEL_UP && gNbProc > NB_LINE) { for (i = NB_LINE, curseur = posProc; i; curseur = curseur -> next, i--); if (curseur) posProc = posProc -> next; DoExpose(); } if (ev.xbutton.button == WHEEL_DOWN && posProc -> previous && gNbProc > NB_LINE) { posProc = posProc -> previous; DoExpose(); } /* Mouse wheel patch end */ if (ev.xbutton.button == CLICK_ONE) { struct timeval temp; long long nms1; gettimeofday(&temp, NULL); nms1 = temp.tv_sec - timev.tv_sec; /* nb sec since last click */ if ((!nms1 || nms1 == 1)){ long long yop = (nms1 * 1000000L) + (temp.tv_usec - timev.tv_usec); /* nb mlsec since last click */ if (firstClick && (yop < DOUBLE_CLICK_DELAY)){ /* we got double click */ doubleClick = 1; firstClick = 0; } else firstClick = 1; } else firstClick = 1; timev = temp; if (zone == UP && !doubleClick && gNbProc > NB_LINE) { for (i = NB_LINE, curseur = posProc; i; curseur = curseur -> next, i--); if (curseur) posProc = posProc -> next; DoExpose(); } else if (zone == DOWN && posProc -> previous && !doubleClick && gNbProc > NB_LINE) { posProc = posProc -> previous; DoExpose(); } else if (zone == UP && doubleClick && gNbProc > NB_LINE) { for (curseur = pList; curseur -> next; curseur = curseur -> next); /* curseur = end of list */ for (i = NB_LINE - 1; i; curseur = curseur -> previous, i--); posProc = curseur; DoExpose(); } else if (zone == DOWN && doubleClick && gNbProc > NB_LINE) { posProc = pList; DoExpose(); } else if (zone > 0 && zone <= NB_LINE && doubleClick && tabNoProc[zone - 1] != -1) { kill(tabNoProc[zone - 1], SIGKILL); /* let's kill the mofo */ waitpid(tabNoProc[zone - 1], NULL, 0); } if (doubleClick) doubleClick = 0; } } void DoEvents() { unsigned long long compteur = 0; XEvent ev ; for (;;){ if (!compteur){ if (CheckProcChange()) DoExpose(); compteur = UPDATE_NB * DELAY; } while(XPending(dpy)){ XNextEvent(dpy,&ev); switch(ev.type) { case Expose : DoExp(); break; case ButtonPress : DoClick(ev); break; } } usleep(DELAY); compteur -= DELAY; } } void PrintUsage(void) { printf("usage: wmAppKill [-a] [-n ] [-h]\n"); printf("\t-a\t\tSelect all processes\n"); printf("\t-n \tDo not select processes older than (default: wmaker)\n"); printf("\t-h\t\tDisplay help screen\n"); } void GetArg(int argc, char *argv[]) { if (argc == 1) return; else if (argc == 3 && !strcmp(argv[1], "-n") && argv[2][0] != '-') procBaseName = strdup(argv[2]); else if (argc == 2 && !strcmp(argv[1], "-a")) procBaseName = NULL; else if (argc == 2 && !strcmp(argv[1], "-h")) { PrintUsage(); exit(1); } else { PrintUsage(); exit(1); } } void CreateDock(int argc, char *argv[]) /* this part comes from http://www.linuxmag-france.org/ */ { Window root; XWMHints wmHints; XSizeHints sizeHints; XClassHint classHint; Pixmap pixmask; unsigned long p_blanc; unsigned long p_noir; unsigned int borderWidth = 2; char *wname = argv[0] ; dpy = XOpenDisplay(NULL) ; if(dpy == NULL) { fprintf(stderr, "Can't open display\n") ; exit(1) ; } root = RootWindow(dpy,screen); p_blanc = WhitePixel(dpy,screen) ; p_noir = BlackPixel(dpy,screen) ; gc = XDefaultGC(dpy,screen) ; XSetForeground(dpy, gc, p_noir); XSetBackground(dpy, gc,p_noir); sizeHints.x = 0 ; sizeHints.y = 0 ; sizeHints.width = 64 ; sizeHints.height = 64 ; win = XCreateSimpleWindow(dpy,root,sizeHints.x,sizeHints.y , sizeHints.width, sizeHints.height, borderWidth, p_noir,p_noir) ; iconWin = XCreateSimpleWindow(dpy,root,sizeHints.x,sizeHints.y,sizeHints.width, sizeHints.height, borderWidth, p_noir,p_noir ) ; sizeHints.flags = USSize | USPosition ; XSetWMNormalHints(dpy,win,&sizeHints) ; wmHints.initial_state = WithdrawnState ; wmHints.icon_window = iconWin ; wmHints.icon_x = sizeHints.x ; wmHints.icon_y = sizeHints.y ; wmHints.window_group = win ; wmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint ; XSetWMHints(dpy, win, &wmHints) ; classHint.res_name = wname ; classHint.res_class = wname ; XSetClassHint(dpy, win, &classHint) ; XSetCommand(dpy,win, argv, argc) ; pixmask = XCreateBitmapFromData(dpy,win,fond_bits, fond_width, fond_height) ; XShapeCombineMask(dpy,win,ShapeBounding,0,0,pixmask,ShapeSet) ; XShapeCombineMask(dpy,iconWin,ShapeBounding, 0, 0, pixmask, ShapeSet) ; XpmCreatePixmapFromData(dpy,root,wmAppKill_xpm, &XPM, NULL,NULL) ; XSelectInput(dpy,win, ExposureMask | ButtonPressMask) ; XSelectInput(dpy,iconWin, ExposureMask | ButtonPressMask) ; XMapWindow(dpy,win) ; } int main(int argc, char *argv[]) { int i; GetArg(argc, argv); glibtop_init(); CreateDock(argc, argv); gettimeofday(&timev, NULL); pList = GetProcList(); posProc = pList; ZoneCreate(4, 50, 8, 8, UP); ZoneCreate(54, 50, 8, 8, DOWN); for (i = NB_LINE; i; i--) ZoneCreate(X_PROC + 1, Y_PROC + (i - 1) * 10 + 2, 48, 7, i); DoEvents(); return 0; }