/* ---------------------------------------------------------------- * * cxt_evnt.c * * Xlib - wrappers and convenience functions * * Christoph Birk, OCIW, Pasadena, CA (birk@obs.carnegiescience.edu) * * v4.00 2002-03-27 libcxt.a * 4.062 2005-10-11 add CBX_UpdateMenu() for menu without callback * 4.070 2015-02-03 XCheckTypedEvent * * http://tronche.com/gui/x/xlib/events/processing-overview.html * * ---------------------------------------------------------------- */ #define IS_CXTLIB_C /* DEFINEs -------------------------------------------------------- */ #ifndef DEBUG #define DEBUG 1 /* debug level */ #endif #define PREFUN __func__ /* INCLUDEs ------------------------------------------------------- */ #define _REENTRANT #include /* memset() */ #include /* select() */ #if (DEBUG > 0) #include /* fprintf() */ #endif #include #include "cxt.h" /* function prototype(s) */ extern void cbx_msleep (int); /* STATICs -------------------------------------------------------- */ static Bool cbx_HandleAutoEdit (MainWindow*,XEvent*); static Bool cbx_HandleAutoButton (MainWindow*,XEvent*); static Bool cbx_HandleAutoMenu (MainWindow*,XEvent*); static Bool cbx_HandleAutoLed (MainWindow*,XEvent*); /* ---------------------------------------------------------------- */ /* event routines */ /* ---------------------------------------------------------------- */ Bool CBX_CheckEvent(MainWindow* mw,long mask,XEvent* ev) { return(CBX_CheckEvent_Ext(mw->disp,mask,ev)); } /* ---------------------------------------------------------------- */ Bool CBX_CheckEvent_Ext(Display* disp,long mask,XEvent* ev) { Bool r; if (disp == NULL) return(False); (void)CBX_Lock(0); r = XCheckMaskEvent(disp,mask,ev); if (!r) { r = XCheckTypedEvent(disp,ClientMessage,ev); /* v4.070 */ if (r) { if (((XClientMessageEvent*)ev)->data.l[0] == cxt_wmDeleteMessage) { ev->type = CXT_WM_CLOSE; } } } CBX_Unlock(); return(r); } /* ---------------------------------------------------------------- */ Bool CBX_WaitEvent(MainWindow* mw,XEvent* ev,int sleeptime) { #if (DEBUG > 2) fprintf(stderr,"%s(): disp=%p, st=%d\n",PREFUN,mw->disp,sleeptime); #endif return(CBX_WaitEvent_Ext(mw->disp,ev,sleeptime)); } /* ---------------------------------------------------------------- */ Bool CBX_WaitEvent_Ext(Display* disp,XEvent* ev,int sleeptime) { while (!CBX_CheckEvent_Ext(disp,CBX_ALL_EVENTS,ev)) { cbx_msleep(sleeptime); } return(True); } /* ---------------------------------------------------------------- */ Bool CBX_AutoEvent(MainWindow* mw,XEvent* ev,int* sleeptime) { if (mw->disp == NULL) return(False); if (CBX_CheckEvent_Ext(mw->disp,CBX_ALL_EVENTS,ev)) { /* there is an event */ *sleeptime = 20; /* reset */ #if (DEBUG > 1) fprintf(stderr,"%s(): type=%d (%d)\n",PREFUN,ev->type,ev->xexpose.count); #endif switch(ev->type) { case Expose: /* expose */ if (ev->xany.window != mw->win) break; if (ev->xexpose.count != 0) break; (void)cbx_HandleAutoEdit(mw,ev); /* handle event */ (void)cbx_HandleAutoButton(mw,ev); (void)cbx_HandleAutoMenu(mw,ev); (void)cbx_HandleAutoLed(mw,ev); break; case MappingNotify: /* keyboard mapping */ (void)CBX_Lock(0); XRefreshKeyboardMapping((XMappingEvent*)ev); CBX_Unlock(); #if (DEBUG > 0) fprintf(stderr,"XRefreshKeyboardMapping on display=%p\n",(void*)mw->disp); #endif break; case EnterNotify: /* enter/leave */ case LeaveNotify: if (cbx_HandleAutoEdit(mw,ev)) return(False); if (cbx_HandleAutoButton(mw,ev)) return(False); break; case KeyPress: /* key press */ if (cbx_HandleAutoEdit(mw,ev)) return(False); break; case ButtonPress: /* button press */ if (cbx_HandleAutoEdit(mw,ev)) return(False); if (cbx_HandleAutoButton(mw,ev)) return(False); if (cbx_HandleAutoMenu(mw,ev)) return(False); break; case ButtonRelease: /* button release */ if (cbx_HandleAutoButton(mw,ev)) return(False); if (cbx_HandleAutoMenu(mw,ev)) return(False); break; case PropertyNotify: if (cbx_HandleAutoEdit(mw,ev)) return(False); break; } } else { /* no event */ if (mw->blist.olist != NULL) { /* we have a Button list */ ManagedButton* list; pthread_mutex_lock(&(mw->blist.lock)); /* MT-safe */ list = (ManagedButton*)mw->blist.olist; /* typecast */ while (list->but) { /* loop over list */ CBX_BlinkButton(list->but,*sleeptime); list++; } pthread_mutex_unlock(&(mw->blist.lock)); /* MT-safe */ } if (mw->llist.olist != NULL) { /* we have an Led list */ ManagedLed* list; pthread_mutex_lock(&(mw->llist.lock)); /* MT-safe */ list = (ManagedLed*)mw->llist.olist; /* typecast */ while (list->led) { /* loop over list */ CBX_BlinkLed(list->led,*sleeptime); list++; } pthread_mutex_unlock(&(mw->llist.lock)); /* MT-safe */ } return(False); } return(True); /* event not handled */ } /* ---------------------------------------------------------------- */ Bool CBX_CheckWindowEvent(MainWindow* mw,Window win,long mask,XEvent* ev) { return(CBX_CheckWindowEvent_Ext(mw->disp,win,mask,ev)); } /* ---------------------------------------------------------------- */ Bool CBX_CheckWindowEvent_Ext(Display* disp,Window win,long mask,XEvent* ev) { Bool r; if (disp == NULL) return(False); (void)CBX_Lock(0); r = XCheckWindowEvent(disp,win,mask,ev); CBX_Unlock(); return(r); } /* ---------------------------------------------------------------- */ Bool CBX_WaitWindowEvent(MainWindow* mw,Window win,long mask,int s,XEvent* ev) { return(CBX_WaitWindowEvent_Ext(mw->disp,win,mask,s,ev)); } /* ---------------------------------------------------------------- */ Bool CBX_WaitWindowEvent_Ext(Display* disp,Window w,long m,int s,XEvent* ev) { while (!CBX_CheckWindowEvent_Ext(disp,w,m,ev)) { cbx_msleep(s); } return(True); } /* ---------------------------------------------------------------- */ static Bool cbx_HandleAutoButton(MainWindow* mw,XEvent* ev) { Bool r=False,found=False; ManagedButton *list; #if (DEBUG > 1) fprintf(stderr,"%s(%p), olist=%p\n",PREFUN,(void*)mw,mw->blist.olist); #endif if (mw->blist.olist == NULL) return(False); /* no list */ pthread_mutex_lock(&(mw->blist.lock)); /* MT-safe */ list = (ManagedButton*)mw->blist.olist; /* typecast */ while (list->but) { /* loop over list */ if ((ev->type == Expose) && (ev->xany.window == list->but->mwin->win)) { CBX_UpdateButton(list->but); /* redraw button */ list++; continue; /* next */ } if (list->but->win != ev->xany.window) { /* not event window */ list++; continue; /* next list member */ } switch (ev->type) { case ButtonPress: /* button press */ #if (DEBUG > 1) fprintf(stderr,"button-%d pressed in button-%ld\n",ev->xbutton.button, ev->xany.window); #endif if (ev->xbutton.button == 1) { /* left button only */ int flag = list->but->flag; /* save flag */ if (CBX_HandleButton(list->but) & CBX_PRESSED) { if (list->callback) { pthread_mutex_unlock(&(mw->blist.lock)); (list->callback)((void*)list->but); pthread_mutex_lock(&(mw->blist.lock)); } } else list->but->flag = flag; /* restore flag */ r = True; } else found = True; break; case ButtonRelease: /* button release */ found = True; /* handle outside */ break; case EnterNotify: case LeaveNotify: r = True; /* ignore */ break; } if (r || found) break; /* event handled */ list++; } /* endwhile(*list) */ pthread_mutex_unlock(&(mw->blist.lock)); return(r); } /* ---------------------------------------------------------------- */ static Bool cbx_HandleAutoMenu(MainWindow* mw,XEvent* ev) { int entry; Bool r=False; ManagedMenu *list; #if (DEBUG > 1) fprintf(stderr,"cbx_HandleAutoMenu(%p), olist=%p\n",(void*)mw, (void*)mw->mlist.olist); #endif if (mw->mlist.olist == NULL) return(False); /* no list */ pthread_mutex_lock(&(mw->mlist.lock)); /* MT-safe */ list = (ManagedMenu*)mw->mlist.olist; /* typecast */ while (list->menu) { /* loop over list */ if ((ev->type == Expose) && (ev->xany.window == list->menu->mwin->win)) { CBX_UpdateMenu(list->menu); /* redraw menu */ list++; continue; /* next */ } if (list->menu->win != ev->xany.window) { /* not event window */ list++; continue; /* next list member */ } switch (ev->type) { case ButtonPress: /* button press */ #if (DEBUG > 1) fprintf(stderr,"button-%d pressed in menu-%ld\n",ev->xbutton.button, ev->xany.window); #endif entry = CBX_HandleMenu(list->menu); if (entry != -1) { list->menu->sel = entry; if (list->callback) { pthread_mutex_unlock(&(mw->mlist.lock)); (list->callback)((void*)list->menu); pthread_mutex_lock(&(mw->mlist.lock)); } else CBX_UpdateMenu(list->menu); } r = True; break; case ButtonRelease: /* button release */ #if (DEBUG > 1) fprintf(stderr,"button-%d released in menu-%ld\n",ev->xbutton.button, ev->xany.window); #endif r = True; /* ignore */ break; case MotionNotify: /* motion notify */ r = True; /* ignore */ break; } if (r) break; /* event handled */ list++; } /* endwhile(*list) */ pthread_mutex_unlock(&(mw->mlist.lock)); return(r); } /* ---------------------------------------------------------------- */ static Bool cbx_HandleAutoEdit(MainWindow* mw,XEvent* ev) { Bool r=False,found=False; ManagedEdit *list; if (mw->elist.olist == NULL) return(False); /* no list */ pthread_mutex_lock(&(mw->elist.lock)); /* MT-safe */ list = (ManagedEdit*)mw->elist.olist; /* typecast */ #if (DEBUG > 1) fprintf(stderr,"%s: mw->elist.olist=%p, nlist=%d \n",PREFUN, (void*)list,mw->elist.nlist); #endif while (list->ewin) { /* loop over list */ if ((ev->type == Expose) && (ev->xany.window == list->ewin->mwin->win)) { #if 0 /* O-O */ (list->ewin->update)(list->ewin); #else CBX_UpdateEditWindow(list->ewin); /* redraw edit-window */ #endif list++; continue; /* next */ } if (list->ewin->win != ev->xany.window) { /* not event window */ list++; continue; /* next list member */ } switch (ev->type) { case EnterNotify: /* enter window */ case LeaveNotify: /* leave window */ CBX_CrossEditWindow(list->ewin,ev->type); r = True; /* event handled */ break; case KeyPress: /* keypress on window */ if (CBX_HandleEditWindow(list->ewin,(XKeyEvent*)ev)) { if (list->callback) { pthread_mutex_unlock(&(mw->elist.lock)); (list->callback)((void*)list->ewin); pthread_mutex_lock(&(mw->elist.lock)); } } r = True; break; case ButtonPress: /* button press */ #if 0 /* IDEA: cut/paste */ #if (DEBUG > 1) fprintf(stderr,"button-%d pressed in window-%ld\n",ev->xbutton.button, ev->xany.window); #endif switch (ev->xbutton.button) { /* button number */ case 1: XSetSelectionOwner(mw->disp,XA_PRIMARY,list->ewin->win,CurrentTime); #if (DEBUG > 0) fprintf(stdout,"%s(): XSetSelectionOwner=%ld\n",PREFUN, XGetSelectionOwner(mw->disp,XA_PRIMARY)); #endif break; case 2: case 3: w = XGetSelectionOwner(mw->disp,XA_PRIMARY); #if (DEBUG > 0) fprintf(stdout,"%s(): XGetSelectionOwner=%ld\n",PREFUN,w); #endif XConvertSelection(mw->disp,XA_PRIMARY,XA_STRING,None,list->ewin->win, CurrentTime); break; } r = True; #else found = True; #endif break; #if 0 /* IDEA: cut/paste */ case PropertyNotify: { char name[32],buf[128]; CBX_GetAtomName_Ext(mw->disp,ev->xproperty.atom,name); if (!strcmp(name,"STRING")) { CBX_GetTextProperty_Ext(mw->disp,ev->xproperty.window,name,buf); #if (DEBUG > 0) fprintf(stdout,"\t%ld (%ld): %s\n",ev->xproperty.window,list->ewin->win,buf); #endif } } r = True; break; #endif } if (r || found) break; /* event handled */ list++; } /* endwhile(*list) */ pthread_mutex_unlock(&(mw->elist.lock)); return(r); } /* ---------------------------------------------------------------- */ static Bool cbx_HandleAutoLed(MainWindow* mw,XEvent* ev) { Bool r=False; ManagedLed *list; #if (DEBUG > 1) fprintf(stderr,"%s(%p), llist=%p\n",PREFUN,(void*)mw,mw->llist.olist); #endif if (mw->llist.olist == NULL) return(False); /* no list */ pthread_mutex_lock(&(mw->llist.lock)); /* MT-safe */ list = (ManagedLed*)mw->llist.olist; /* typecast */ while (list->led) { /* loop over list */ if ((ev->type == Expose) && (ev->xany.window == list->led->mwin->win)) { CBX_UpdateLed(list->led); /* redraw led */ list++; continue; /* next */ } if (list->led->win != ev->xany.window) { /* not event window */ list++; continue; /* next list member */ } list++; } /* endwhile(*list) */ pthread_mutex_unlock(&(mw->llist.lock)); return(r); } /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */