/* Also includes Xlib, Xresources, XPM, stdlib and stdio */ #include #include #include #include #include #include /* Include the pixmap to use */ #include "archlinux.xpm" #include "archlinux_bw.xpm" #include "loading.xpm" #define TRUE 1 #define FALSE 0 #define MAX 256 #define MAXPATHLEN 4096 #define CHK_INTERVAL 600 #define WMARCHUP_VER "1.2" #define VERSION "wmArchUp version " WMARCHUP_VER /* * Prototypes for local functions */ void destroy(void); void check_for_updates(); void buttonrelease(int button, int state, int x, int y); void update(); char *get_update_script(); /* * Global variables */ Pixmap arch, arch_mask, arch_bw, arch_bw_mask, checking, checking_mask; unsigned short height, width; unsigned int check_interval = CHK_INTERVAL; int updates_available = FALSE; char *script; /* * M A I N */ int main(int argc, char **argv) { /* Find bash update script */ script = get_update_script(); /* Set callbacks for events */ DACallbacks eventCallbacks = { destroy, /* destroy */ NULL, /* buttonPress */ &buttonrelease, /* buttonRelease */ NULL, /* motion (mouse) */ NULL, /* mouse enters window */ NULL, /* mouse leaves window */ check_for_updates /* timeout */ }; int interval = 0; /* Set program options */ DAProgramOption options[] = { { "-c", "--check-interval", "Check interval in minutes. Default 10 minutes.", DONatural, False, {&interval} }, }; /* provide standard command-line options */ DAParseArguments( argc, argv, /* Where the options come from */ options, 1, /* Our list with options */ "This is dockapp watch for available updates " "in Arch Linux packages.\n", VERSION); /* Set the check interval */ check_interval = interval ? (interval * 60) : CHK_INTERVAL; /* Check if correct libdockapp version exists in system */ DASetExpectedVersion(20050716); DAInitialize("", "WMArchUp", 56, 56, argc, argv); DAMakePixmapFromData( archlinux, &arch, &arch_mask, &height, &width); DAMakePixmapFromData( archlinux_bw, &arch_bw, &arch_bw_mask, &height, &width); DAMakePixmapFromData( loading, &checking, &checking_mask, &height, &width); /* Respond to destroy and timeout events (the ones not NULL in the * eventCallbacks variable. */ DASetCallbacks(&eventCallbacks); /* Set timeout in msec */ DASetTimeout(check_interval * 1000); /* Show the dockapp window. */ DAShow(); /* Check for updates at the begining */ check_for_updates(); /* Loop for events */ DAEventLoop(); /* not reached */ exit(EXIT_SUCCESS); } void update() { if (updates_available == TRUE) { XSelectInput(DAGetDisplay(NULL), DAGetWindow(), NoEventMask); int ret = system(script); if (WEXITSTATUS(ret) == 0) { updates_available = FALSE; DASetShape(arch_bw_mask); DASetPixmap(arch_bw); } XSelectInput(DAGetDisplay(NULL), DAGetWindow(), ButtonPressMask | ButtonReleaseMask); } } void check_for_updates() { XSelectInput(DAGetDisplay(NULL), DAGetWindow(), NoEventMask); char res[MAX]; DASetShape(checking_mask); DASetPixmap(checking); /* Read output from command */ FILE *fp = popen("checkupdates", "r"); if (fgets(res, MAX, fp) != NULL) { updates_available = TRUE; DASetShape(arch_mask); DASetPixmap(arch); } else { updates_available = FALSE; DASetShape(arch_bw_mask); DASetPixmap(arch_bw); } if (pclose(fp) != 0) { fprintf(stderr, " Error: Failed to close command stream \n"); } XSelectInput(DAGetDisplay(NULL), DAGetWindow(), ButtonPressMask | ButtonReleaseMask); } void destroy(void) { return; } /* A mouse button was pressed and released. * See if it was button 1 left click or button 3 right click. */ void buttonrelease(int button, int state, int x, int y) { if (button == 1) { update(); } else if (button == 3) { check_for_updates(); } } char * get_update_script() { int length; char *p; char *script_name = "arch_update.sh"; char *fullpath = malloc(MAXPATHLEN + strlen(script_name)); if (fullpath == NULL) { perror("Can't allocate memory."); exit(1); } /* * /proc/self is a symbolic link to the process-ID subdir of /proc, e.g. * /proc/4323 when the pid of the process of this program is 4323. * Inside /proc/ there is a symbolic link to the executable that is * running as this . This symbolic link is called "exe". So if we * read the path where the symlink /proc/self/exe points to we have the * full path of the executable. */ length = readlink("/proc/self/exe", fullpath, MAXPATHLEN); /* * Catch some errors: */ if (length < 0) { perror("resolving symlink /proc/self/exe."); exit(1); } if (length >= MAXPATHLEN) { fprintf(stderr, "Path too long.\n"); exit(1); } fullpath[length] = '\0'; if ((p = strrchr(fullpath, '/'))) { *(p + 1) = '\0'; } strcat(fullpath, script_name); return fullpath; }