/* * Compiz configuration system library * * Copyright (C) 2007 Danny Baumann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library 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 * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #define _GNU_SOURCE #include #include #include #include #include #if HAVE_SYS_INOTIFY_H #include #endif #include #include #include "ccs-private.h" typedef struct _FilewatchData { char *fileName; int watchDesc; unsigned int watchId; FileWatchCallbackProc callback; void *closure; } FilewatchData; static FilewatchData *fwData = NULL; static int fwDataSize = 0; static int inotifyFd = 0; static inline int findDataIndexById (unsigned int watchId) { int i, index = -1; for (i = 0; i < fwDataSize; i++) if (fwData[i].watchId == watchId) { index = i; break; } return index; } void ccsCheckFileWatches (void) { #if HAVE_SYS_INOTIFY_H char buf[256 * (sizeof (struct inotify_event) + 16)]; struct inotify_event *event; int len, i = 0, j; if (!inotifyFd) return; len = read (inotifyFd, buf, sizeof (buf)); if (len < 0) return; while (i < len) { event = (struct inotify_event *) & buf[i]; for (j = 0; j < fwDataSize; j++) if ((fwData[j].watchDesc == event->wd) && fwData[j].callback) (*fwData[j].callback) (fwData[j].watchId, fwData[j].closure); i += sizeof (*event) + event->len; } #endif } unsigned int ccsAddFileWatch (const char *fileName, Bool enable, FileWatchCallbackProc callback, void *closure) { unsigned int i, maxWatchId = 0; #if HAVE_SYS_INOTIFY_H if (!inotifyFd) { inotifyFd = inotify_init (); fcntl (inotifyFd, F_SETFL, O_NONBLOCK); } #endif fwData = realloc (fwData, (fwDataSize + 1) * sizeof (FilewatchData)); if (!fwData) { fwDataSize = 0; return 0; } fwData[fwDataSize].fileName = strdup (fileName); #if HAVE_SYS_INOTIFY_H if (enable) fwData[fwDataSize].watchDesc = inotify_add_watch (inotifyFd, fileName, IN_MODIFY | IN_MOVE | IN_MOVE_SELF | IN_DELETE_SELF | IN_CREATE | IN_DELETE); else #endif fwData[fwDataSize].watchDesc = 0; fwData[fwDataSize].callback = callback; fwData[fwDataSize].closure = closure; /* determine current highest ID */ for (i = 0; i < fwDataSize; i++) if (fwData[i].watchId > maxWatchId) maxWatchId = fwData[i].watchId; fwData[fwDataSize].watchId = maxWatchId + 1; fwDataSize++; return (maxWatchId + 1); } void ccsRemoveFileWatch (unsigned int watchId) { int selectedIndex, i; selectedIndex = findDataIndexById (watchId); /* not found */ if (selectedIndex < 0) return; /* clear entry */ free (fwData[selectedIndex].fileName); #if HAVE_SYS_INOTIFY_H if (fwData[selectedIndex].watchDesc) inotify_rm_watch (inotifyFd, fwData[selectedIndex].watchDesc); #endif /* shrink array */ for (i = selectedIndex; i < (fwDataSize - 1); i++) fwData[i] = fwData[i+1]; fwDataSize--; if (fwDataSize > 0) { fwData = realloc (fwData, fwDataSize * sizeof (FilewatchData)); if (!fwData) fwDataSize = 0; } else { free (fwData); fwData = NULL; } if (!fwDataSize) { if (inotifyFd) close (inotifyFd); inotifyFd = 0; } } void ccsDisableFileWatch (unsigned int watchId) { int index; index = findDataIndexById (watchId); if (index < 0) return; #if HAVE_SYS_INOTIFY_H if (fwData[index].watchDesc) { inotify_rm_watch (inotifyFd, fwData[index].watchDesc); fwData[index].watchDesc = 0; } #endif } void ccsEnableFileWatch (unsigned int watchId) { int index; index = findDataIndexById (watchId); if (index < 0) return; #if HAVE_SYS_INOTIFY_H if (!fwData[index].watchDesc) fwData[index].watchDesc = inotify_add_watch (inotifyFd, fwData[index].fileName, IN_MODIFY | IN_MOVE | IN_MOVE_SELF | IN_DELETE_SELF | IN_CREATE | IN_DELETE); #endif }