From f2f71a1f09281dace48b940a3765070f33b481dc Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 10 Sep 1999 20:13:44 +0000 Subject: [PATCH] Finished the libWUtil library. --- WINGs/ChangeLog | 44 +++++++++++ WINGs/Makefile.am | 19 ++++- WINGs/Makefile.in | 18 ++++- WINGs/WINGs.h | 2 +- WINGs/WUtil.h | 10 +++ WINGs/wutil.c | 190 ++++++++++++++++++++++++---------------------- 6 files changed, 188 insertions(+), 95 deletions(-) diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 6fecfca7..8aa0f54d 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -3,6 +3,50 @@ changes since wmaker 0.60.0: - added WMScreenWidth() and WMScreenHeight() functions. - fixed some problems when compiling with non gcc compilers. +- added libWUtil, a library that is a subset of libWINGs. It contains utils + that can be used in writing non-GUI programs. They include: hashes, + notifications, input/idle/timer handlers, user defaults database handling, + memory handling, application resource handling, etc. + All the non-GUI stuff from libWINGs is present. + Still linWINGs contain all this stuff so if you use libWINGs, you don't + need to link against libWUtil too. + One notable aspect of libWUtil is that it has a modified version of the + event handling function. It is named WHandleEvents() and will handle all + input/idle/timer events the app has. + If your app has a permanent input handler (as for example a socket a server + is listening on), then the main loop of the app can be: + while(1) { + WHandleEvents(); + } + but if there is no permanent input handler, you need to add some delay to + avoid a too high cpu load by your program: + while(1) { + WHandleEvents(); + wusleep(5000); + } + A permanent input handler is one that is established when the program starts + and is present until the program exits. + One that is deleted and later reinstalled, is not considered permanent. + This difference is because if there is some input handler, the function will + block until some event appears, while if there is no input handler the + function will return almost immediately (after handling the timer/idle + stuff). + + Except the stuff declared in WUtil.h, the following functions declared in + WINGs.h are also present in libWUtil (you will need to #include + if you use one of these): + WMInitializeApplication(char *applicationName, int *argc, char **argv); + WMSetResourcePath(char *path); + WMGetApplicationName(); + WMPathForResourceOfType(char *resource, char *ext); + WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata); + WMDeleteTimerWithClientData(void *cdata); + WMDeleteTimerHandler(WMHandlerID handlerID); + WMAddIdleHandler(WMCallback *callback, void *cdata); + WMDeleteIdleHandler(WMHandlerID handlerID); + WMAddInputHandler(int fd, int condition, WMInputProc *proc, + void *clientData); + WMDeleteInputHandler(WMHandlerID handlerID); changes since wmaker 0.53.0: diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 956c52c5..b7f2f946 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -12,7 +12,7 @@ LIBLIST= $(top_builddir)/wrlib/libwraster.la\ #lib_LTLIBRARIES = libWINGs.la -lib_LIBRARIES = libWINGs.a +lib_LIBRARIES = libWINGs.a libWUtil.a #libWINGs_la_LDFLAGS = -version-info 1:1:0 @@ -101,6 +101,23 @@ libWINGs_a_SOURCES = \ usleep.c +libWUtil_a_SOURCES = \ + WINGs.h \ + WINGsP.h \ + llist.h \ + llist.c \ + international.c \ + notification.c \ + userdefaults.c \ + wapplication.c \ + wutil.c \ + error.c \ + findfile.c \ + hashtable.c \ + memory.c \ + usleep.c + + INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/src \ -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG diff --git a/WINGs/Makefile.in b/WINGs/Makefile.in index 4299b02c..d6a6ec7a 100644 --- a/WINGs/Makefile.in +++ b/WINGs/Makefile.in @@ -101,7 +101,7 @@ LIBLIST = $(top_builddir)/wrlib/libwraster.la @LIBRARY_SEARCH_PATH@ @GFXLIBS@ #lib_LTLIBRARIES = libWINGs.la -lib_LIBRARIES = libWINGs.a +lib_LIBRARIES = libWINGs.a libWUtil.a #libWINGs_la_LDFLAGS = -version-info 1:1:0 @@ -146,6 +146,9 @@ EXTRA_DIST = logo.xpm BUGS libWINGs_a_SOURCES = WINGs.h WINGsP.h configuration.c llist.h llist.c international.c notification.c selection.c userdefaults.c wapplication.c wappresource.c wballoon.c wbrowser.c wbutton.c wcolor.c wcolorpanel.c wcolorwell.c wevent.c wfilepanel.c wframe.c wfont.c wfontpanel.c widgets.c wlabel.c wlist.c wmisc.c wpanel.c wpixmap.c wpopupbutton.c wscroller.c wscrollview.c wslider.c wsplitview.c wtabview.c wtextfield.c wwindow.c wview.c error.c findfile.c hashtable.c memory.c usleep.c +libWUtil_a_SOURCES = WINGs.h WINGsP.h llist.h llist.c international.c notification.c userdefaults.c wapplication.c wutil.c error.c findfile.c hashtable.c memory.c usleep.c + + INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/src -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -169,6 +172,10 @@ wevent.o wfilepanel.o wframe.o wfont.o wfontpanel.o widgets.o wlabel.o \ wlist.o wmisc.o wpanel.o wpixmap.o wpopupbutton.o wscroller.o \ wscrollview.o wslider.o wsplitview.o wtabview.o wtextfield.o wwindow.o \ wview.o error.o findfile.o hashtable.o memory.o usleep.o +libWUtil_a_LIBADD = +libWUtil_a_OBJECTS = llist.o international.o notification.o \ +userdefaults.o wapplication.o wutil.o error.o findfile.o hashtable.o \ +memory.o usleep.o AR = ar PROGRAMS = $(noinst_PROGRAMS) @@ -208,8 +215,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP_ENV = --best -SOURCES = $(libWINGs_a_SOURCES) $(wtest_SOURCES) $(wmquery_SOURCES) $(wmfile_SOURCES) $(fontl_SOURCES) $(testmywidget_SOURCES) $(testcolorpanel_SOURCES) $(testnot_SOURCES) -OBJECTS = $(libWINGs_a_OBJECTS) $(wtest_OBJECTS) $(wmquery_OBJECTS) $(wmfile_OBJECTS) $(fontl_OBJECTS) $(testmywidget_OBJECTS) $(testcolorpanel_OBJECTS) $(testnot_OBJECTS) +SOURCES = $(libWINGs_a_SOURCES) $(libWUtil_a_SOURCES) $(wtest_SOURCES) $(wmquery_SOURCES) $(wmfile_SOURCES) $(fontl_SOURCES) $(testmywidget_SOURCES) $(testcolorpanel_SOURCES) $(testnot_SOURCES) +OBJECTS = $(libWINGs_a_OBJECTS) $(libWUtil_a_OBJECTS) $(wtest_OBJECTS) $(wmquery_OBJECTS) $(wmfile_OBJECTS) $(fontl_OBJECTS) $(testmywidget_OBJECTS) $(testcolorpanel_OBJECTS) $(testnot_OBJECTS) all: all-redirect .SUFFIXES: @@ -297,6 +304,11 @@ libWINGs.a: $(libWINGs_a_OBJECTS) $(libWINGs_a_DEPENDENCIES) $(AR) cru libWINGs.a $(libWINGs_a_OBJECTS) $(libWINGs_a_LIBADD) $(RANLIB) libWINGs.a +libWUtil.a: $(libWUtil_a_OBJECTS) $(libWUtil_a_DEPENDENCIES) + -rm -f libWUtil.a + $(AR) cru libWUtil.a $(libWUtil_a_OBJECTS) $(libWUtil_a_LIBADD) + $(RANLIB) libWUtil.a + mostlyclean-noinstPROGRAMS: clean-noinstPROGRAMS: diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index 93e918a7..8ff293c4 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -477,7 +477,7 @@ typedef struct WMTabViewDelegate { void WMInitializeApplication(char *applicationName, int *argc, char **argv); -void WMSetApplicationDataPath(char *path); +void WMSetResourcePath(char *path); /* don't free the returned string */ char *WMGetApplicationName(); diff --git a/WINGs/WUtil.h b/WINGs/WUtil.h index adf2b860..095fbe1f 100644 --- a/WINGs/WUtil.h +++ b/WINGs/WUtil.h @@ -174,6 +174,16 @@ void wusleep(unsigned int microsec); int wsprintesc(char *buffer, int length, char *format, WMSEscapes **escapes, int count); #endif + +/*......................................................................*/ + +/* This function is used _only_ if you create a NON-GUI program. + * For GUI based programs use WMNextEvent()/WMHandleEvent() instead. + * This function will handle all input/timer/idle events, then return. + */ + +void WHandleEvents(); + /*......................................................................*/ diff --git a/WINGs/wutil.c b/WINGs/wutil.c index e7d6f664..9286a2ae 100644 --- a/WINGs/wutil.c +++ b/WINGs/wutil.c @@ -2,6 +2,7 @@ /* * This event handling stuff was based on Tk. + * adapted from wevent.c */ #include "WINGsP.h" @@ -16,7 +17,7 @@ #endif -//#include +#include #ifdef HAVE_SYS_SELECT_H # include @@ -94,11 +95,11 @@ WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata) { TimerHandler *handler, *tmp; - + handler = malloc(sizeof(TimerHandler)); if (!handler) return NULL; - + rightNow(&handler->when); addmillisecs(&handler->when, milliseconds); handler->callback = callback; @@ -153,7 +154,7 @@ WMDeleteTimerHandler(WMHandlerID handlerID) { TimerHandler *tmp, *handler=(TimerHandler*)handlerID; - if (!handler || !timerHandler) + if (!handler || !timerHandler) return; tmp = timerHandler; @@ -178,7 +179,7 @@ WMHandlerID WMAddIdleHandler(WMCallback *callback, void *cdata) { IdleHandler *handler, *tmp; - + handler = malloc(sizeof(IdleHandler)); if (!handler) return NULL; @@ -232,16 +233,16 @@ WMHandlerID WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData) { InputHandler *handler; - + handler = wmalloc(sizeof(InputHandler)); - + handler->fd = fd; handler->mask = condition; handler->callback = proc; handler->clientData = clientData; - + handler->next = inputHandler; - + inputHandler = handler; return handler; @@ -269,7 +270,7 @@ WMDeleteInputHandler(WMHandlerID handlerID) } tmp = tmp->next; } - } + } } @@ -284,7 +285,7 @@ checkIdleHandlers() } handler = idleHandler; - + /* we will process all idleHandlers so, empty the handler list */ idleHandler = NULL; @@ -293,7 +294,7 @@ checkIdleHandlers() (*handler->callback)(handler->clientData); /* remove the handler */ free(handler); - + handler = tmp; } W_FlushIdleNotificationQueue(); @@ -350,23 +351,46 @@ delayUntilNextTimerEvent(struct timeval *delay) } -Bool -W_WaitForEvent(Display *dpy, unsigned long xeventmask) +/* + * This functions will handle input events on all registered file descriptors. + * Input: + * - waitForInput - True if we want the function to wait until an event + * appears on a file descriptor we watch, False if we + * want the function to immediately return if there is + * no data available on the file descriptors we watch. + * Output: + * if waitForInput is False, the function will return False if there are no + * input handlers registered, or if there is no data + * available on the registered ones, and will return True + * if there is at least one input handler that has data + * available. + * if waitForInput is True, the function will return False if there are no + * input handlers registered, else it will block until an + * event appears on one of the file descriptors it watches + * and then it will return True. + * + * If the retured value is True, the input handlers for the corresponding file + * descriptors are also called. + * + */ +static Bool +handleInputEvents(Bool waitForInput) { #if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT) struct pollfd *fds; InputHandler *handler; - int count, timeout, nfds, k, retval; + int count, timeout, nfds, k; - for (nfds = 1, handler = inputHandler; + if (!inputHandler) + return False; + + for (nfds = 0, handler = inputHandler; handler != 0; handler = handler->next) nfds++; - - fds = wmalloc(nfds * sizeof(struct pollfd)); - fds[0].fd = ConnectionNumber(dpy); - fds[0].events = POLLIN; - for (k = 1, handler = inputHandler; - handler; + fds = wmalloc(nfds * sizeof(struct pollfd)); + + for (k = 0, handler = inputHandler; + handler; handler = handler->next, k++) { fds[k].fd = handler->fd; fds[k].events = 0; @@ -383,10 +407,13 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) } /* - * Setup the select() timeout to the estimated time until the - * next timer expires. + * If we don't wait for input, set timeout to return immediately, + * else setup the timeout to the estimated time until the + * next timer expires or if no timer is pending to infinite. */ - if (timerPending()) { + if (!waitForInput) { + timeout = 0; + } else if (timerPending()) { struct timeval tv; delayUntilNextTimerEvent(&tv); timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000; @@ -394,22 +421,11 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) timeout = -1; } - if (xeventmask==0) { - if (XPending(dpy)) - return True; - } else { - XEvent ev; - if (XCheckMaskEvent(dpy, xeventmask, &ev)) { - XPutBackEvent(dpy, &ev); - return True; - } - } - count = poll(fds, nfds, timeout); if (count > 0) { handler = inputHandler; - k = 1; + k = 0; while (handler) { int mask; InputHandler *next; @@ -418,17 +434,17 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) if (fds[k].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)) mask |= WIReadMask; - + if (fds[k].revents & (POLLOUT | POLLWRBAND)) mask |= WIWriteMask; - + if (fds[k].revents & (POLLHUP | POLLNVAL | POLLERR)) mask |= WIExceptMask; next = handler->next; if (mask!=0 && handler->callback) { - (*handler->callback)(handler->fd, mask, + (*handler->callback)(handler->fd, mask, handler->clientData); } @@ -437,12 +453,11 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) } } - retval = fds[0].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI); free(fds); W_FlushASAPNotificationQueue(); - return retval; + return (count > 0); #else /* not HAVE_POLL */ #ifdef HAVE_SELECT struct timeval timeout; @@ -452,12 +467,14 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) int count; InputHandler *handler = inputHandler; + if (!inputHandler) + return False; + FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); - FD_SET(ConnectionNumber(dpy), &rset); - maxfd = ConnectionNumber(dpy); + maxfd = 0; while (handler) { if (handler->mask & WIReadMask) @@ -475,30 +492,22 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) handler = handler->next; } - /* - * Setup the select() timeout to the estimated time until the - * next timer expires. + * If we don't wait for input, set timeout to return immediately, + * else setup the timeout to the estimated time until the + * next timer expires or if no timer is pending to infinite. */ - if (timerPending()) { + if (!waitForInput) { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + timeoutPtr = &timeout; + } else if (timerPending()) { delayUntilNextTimerEvent(&timeout); timeoutPtr = &timeout; } else { timeoutPtr = (struct timeval*)0; } - XSync(dpy, False); - if (xeventmask==0) { - if (XPending(dpy)) - return True; - } else { - XEvent ev; - if (XCheckMaskEvent(dpy, xeventmask, &ev)) { - XPutBackEvent(dpy, &ev); - return True; - } - } - count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr); if (count > 0) { @@ -512,17 +521,17 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) if (FD_ISSET(handler->fd, &rset)) mask |= WIReadMask; - + if (FD_ISSET(handler->fd, &wset)) mask |= WIWriteMask; - + if (FD_ISSET(handler->fd, &eset)) mask |= WIExceptMask; next = handler->next; if (mask!=0 && handler->callback) { - (*handler->callback)(handler->fd, mask, + (*handler->callback)(handler->fd, mask, handler->clientData); } @@ -532,7 +541,7 @@ W_WaitForEvent(Display *dpy, unsigned long xeventmask) W_FlushASAPNotificationQueue(); - return FD_ISSET(ConnectionNumber(dpy), &rset); + return (count > 0); #else /* not HAVE_SELECT, not HAVE_POLL */ Neither select nor poll. You lose. #endif /* HAVE_SELECT */ @@ -541,39 +550,40 @@ Neither select nor poll. You lose. void -WMNextEvent(Display *dpy, XEvent *event) -{ +WHandleEvents() +{ /* Check any expired timers */ if (timerPending()) { - checkTimerHandlers(); + checkTimerHandlers(); } - while (XPending(dpy) == 0) { - /* Do idle stuff */ - /* Do idle and timer stuff while there are no timer or X events */ - while (!XPending(dpy) && idlePending()) { - if (idlePending()) - checkIdleHandlers(); - /* dispatch timer events */ - if (timerPending()) - checkTimerHandlers(); - } - - /* - * Make sure that new events did not arrive while we were doing - * timer/idle stuff. Or we might block forever waiting for - * an event that already arrived. - */ - /* wait to something happen */ - W_WaitForEvent(dpy, 0); - - /* Check any expired timers */ - if (timerPending()) { - checkTimerHandlers(); + /* We need to make sure that we have some input handler before calling + * checkIdleHandlers() in a while loop, because else the while loop + * can run forever (if some idle handler reinitiates itself). + */ + if (inputHandler) { + /* Do idle and timer stuff while there are no input events */ + while (idlePending() && inputHandler && !handleInputEvents(False)) { + if (idlePending()) + checkIdleHandlers(); + /* dispatch timer events */ + if (timerPending()) + checkTimerHandlers(); } + } else { + if (idlePending()) + checkIdleHandlers(); + /* dispatch timer events */ + if (timerPending()) + checkTimerHandlers(); } - XNextEvent(dpy, event); + handleInputEvents(True); + + /* Check any expired timers */ + if (timerPending()) { + checkTimerHandlers(); + } }