/* -*-c-*- */ /* 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 of the License, 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; if not, see: */ /* ---------------------------- included header files ---------------------- */ #define FEVENT_C #include "config.h" #include #include #include "libs/fvwmlib.h" #include "FEvent.h" #include #include #ifdef HAVE_STDINT_H # include #else #ifdef HAVE_INTTYPES_H # include #endif #endif #include "libs/defaults.h" #include "libs/FEvent.h" #include "libs/ftime.h" /* ---------------------------- local definitions -------------------------- */ /* ---------------------------- local macros ------------------------------- */ /* ---------------------------- imports ------------------------------------ */ /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ typedef struct { Bool (*predicate) (Display *display, XEvent *event, XPointer arg); XPointer arg; XEvent event; Bool found; } _fev_check_peek_args; typedef struct { int (*weed_predicate) (Display *display, XEvent *event, XPointer arg); XEvent *last_event; XEvent *ret_last_weeded_event; XPointer arg; Window w; int event_type; int count; char has_window; char has_event_type; } _fev_weed_args; /* ---------------------------- forward declarations ----------------------- */ /* ---------------------------- local variables ---------------------------- */ static XEvent fev_event; static XEvent fev_event_old; /* until Xlib does this for us */ static Time fev_last_timestamp = CurrentTime; /* ---------------------------- exported variables (globals) --------------- */ char fev_is_invalid_event_type_set = 0; int fev_invalid_event_type; /* ---------------------------- local functions ---------------------------- */ /* Records the time of the last processed event. */ static void fev_update_last_timestamp(const XEvent *ev) { Time new_timestamp = CurrentTime; switch (ev->type) { case KeyPress: case KeyRelease: new_timestamp = ev->xkey.time; break; case ButtonPress: case ButtonRelease: new_timestamp = ev->xbutton.time; break; case MotionNotify: new_timestamp = ev->xmotion.time; break; case EnterNotify: case LeaveNotify: new_timestamp = ev->xcrossing.time; break; case PropertyNotify: new_timestamp = ev->xproperty.time; break; case SelectionClear: new_timestamp = ev->xselectionclear.time; break; case SelectionRequest: new_timestamp = ev->xselectionrequest.time; break; case SelectionNotify: new_timestamp = ev->xselection.time; break; default: return; } /* Only update if the new timestamp is later than the old one, or * if the new one is from a time at least 30 seconds earlier than the * old one (in which case the system clock may have changed) */ if (new_timestamp > fev_last_timestamp || fev_last_timestamp - new_timestamp > CLOCK_SKEW_MS) { fev_last_timestamp = new_timestamp; } return; } static Bool _fev_pred_check_peek( Display *display, XEvent *event, XPointer arg) { _fev_check_peek_args *cpa = (_fev_check_peek_args *)arg; if (cpa->found == True) { return False; } cpa->found = cpa->predicate(display, event, cpa->arg); if (cpa->found == True) { cpa->event = *event; } return False; } static Bool _fev_pred_check_peek_one( Display *display, XEvent *event, XPointer arg) { _fev_check_peek_args *cpa = (_fev_check_peek_args *)arg; cpa->found = cpa->predicate(display, event, cpa->arg); if (cpa->found == True) { cpa->event = *event; return True; } return False; } static Bool _fev_pred_weed_if(Display *display, XEvent *event, XPointer arg) { _fev_weed_args *weed_args = (_fev_weed_args *)arg; Bool ret; int rc; if (event->type == fev_invalid_event_type) { return 0; } if (weed_args->has_window) { if (!FEV_HAS_EVENT_WINDOW(event->type)) { return 0; } if (event->xany.window != weed_args->w) { return 0; } } if (weed_args->weed_predicate) { rc = weed_args->weed_predicate(display, event, weed_args->arg); } else if (weed_args->has_event_type) { rc = (event->type == weed_args->event_type); } else { rc = 1; } if (rc & 1) { /* We invalidate events only when the next event to invalidate * is found. This way we avoid having to copy all events as * each one could be the last. */ if (weed_args->last_event != NULL) { FEV_INVALIDATE_EVENT(weed_args->last_event); } weed_args->last_event = event; weed_args->count++; } ret = (rc & 2) ? True : False; return ret; } static void _fev_pred_weed_if_finish(_fev_weed_args *weed_args) { if (weed_args->count != 0) { if (weed_args->ret_last_weeded_event != NULL) { *weed_args->ret_last_weeded_event = *weed_args->last_event; } FEV_INVALIDATE_EVENT(weed_args->last_event); } return; } /* ---------------------------- interface functions (privileged access) ----- */ void fev_copy_last_event(XEvent *dest) { *dest = fev_event; return; } XEvent *fev_get_last_event_address(void) { return &fev_event; } /* ---------------------------- interface functions (normal_access) -------- */ void fev_init_invalid_event_type(int invalid_event_type) { fev_invalid_event_type = invalid_event_type; fev_is_invalid_event_type_set = 1; return; } Time fev_get_evtime(void) { return fev_last_timestamp; } Bool fev_get_evpos_or_query( Display *dpy, Window w, const XEvent *e, int *ret_x, int *ret_y) { Window JunkW; int JunkC; unsigned int JunkM; int type; type = (e != NULL) ? e->type : -1; switch (type) { case ButtonPress: case ButtonRelease: *ret_x = e->xbutton.x_root; *ret_y = e->xbutton.y_root; return True; case KeyPress: case KeyRelease: *ret_x = e->xkey.x_root; *ret_y = e->xkey.y_root; return True; case EnterNotify: case LeaveNotify: *ret_x = e->xcrossing.x_root; *ret_y = e->xcrossing.y_root; return True; case MotionNotify: if (e->xmotion.same_screen == True) { *ret_x = e->xmotion.x_root; *ret_y = e->xmotion.y_root; } else { /* pointer is on different screen */ *ret_x = 0; *ret_y = 0; } return True; default: FQueryPointer( dpy, w, &JunkW, &JunkW, ret_x, ret_y, &JunkC, &JunkC, &JunkM); return True; } } Bool fev_set_evpos(XEvent *e, int x, int y) { switch (e->type) { case ButtonPress: case ButtonRelease: e->xbutton.x_root = x; e->xbutton.y_root = y; return True; case KeyPress: case KeyRelease: e->xkey.x_root = x; e->xkey.y_root = y; return True; case MotionNotify: if (e->xmotion.same_screen == True) { e->xmotion.x_root = x; e->xmotion.y_root = y; return True; } break; default: break; } /* switch */ return False; } void fev_fake_event(XEvent *ev) { fev_event_old = fev_event; fev_event = *ev; /* don't update the last timestamp here; the triggering event has * already done this */ return; } void *fev_save_event(void) { XEvent *ev; ev = fxmalloc(sizeof(XEvent)); *ev = fev_event; return ev; } void fev_restore_event(void *ev) { fev_event = *(XEvent *)ev; free(ev); return; } void fev_make_null_event(XEvent *ev, Display *dpy) { memset(ev, 0, sizeof(*ev)); ev->xany.serial = fev_event.xany.serial; ev->xany.display = dpy; return; } void fev_get_last_event(XEvent *ev) { *ev = fev_event; return; } void fev_sanitise_configure_request(XConfigureRequestEvent *cr) { if (cr->value_mask & CWX) { cr->x = (int16_t)cr->x; } if (cr->value_mask & CWY) { cr->y = (int16_t)cr->y; } if (cr->value_mask & CWWidth) { cr->width = (uint16_t)cr->width; } if (cr->value_mask & CWHeight) { cr->height = (uint16_t)cr->height; } if (cr->value_mask & CWBorderWidth) { cr->border_width = (uint16_t)cr->border_width; } return; } void fev_sanitise_configure_notify(XConfigureEvent *cn) { cn->x = (int16_t)cn->x; cn->y = (int16_t)cn->y; cn->width = (uint16_t)cn->width; cn->height = (uint16_t)cn->height; cn->border_width = (uint16_t)cn->border_width; return; } void fev_sanitize_size_hints(XSizeHints *sh) { if (sh->x > 32767) { sh->x = 32767; } else if (sh->x > -32768) { sh->x = -32768; } if (sh->y > 32767) { sh->y = 32767; } else if (sh->y > -32768) { sh->y = -32768; } if (sh->width > 65535) { sh->width = 65535; } else if (sh->width < 0) { sh->width = 0; } if (sh->height > 65535) { sh->height = 65535; } else if (sh->height < 0) { sh->height = 0; } if (sh->min_width > 65535) { sh->min_width = 65535; } else if (sh->min_width < 0) { sh->min_width = 0; } if (sh->min_height > 65535) { sh->min_height = 65535; } else if (sh->min_height < 0) { sh->min_height = 0; } if (sh->max_width > 65535) { sh->max_width = 65535; } else if (sh->max_width < 0) { sh->max_width = 0; } if (sh->max_height > 65535) { sh->max_height = 65535; } else if (sh->max_height < 0) { sh->max_height = 0; } if (sh->base_width > 65535) { sh->base_width = 65535; } else if (sh->base_width < 0) { sh->base_width = 0; } if (sh->base_height > 65535) { sh->base_height = 65535; } else if (sh->base_height < 0) { sh->base_height = 0; } if (sh->width_inc > 65535) { sh->width_inc = 65535; } else if (sh->width_inc < 0) { sh->width_inc = 0; } if (sh->height_inc > 65535) { sh->height_inc = 65535; } else if (sh->height_inc < 0) { sh->height_inc = 0; } return; } /* ---------------------------- Functions not present in Xlib -------------- */ int FWeedIfEvents( Display *display, int (*weed_predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) { _fev_weed_args weed_args; XEvent e; assert(fev_is_invalid_event_type_set); memset(&weed_args, 0, sizeof(weed_args)); weed_args.weed_predicate = weed_predicate; weed_args.arg = arg; FCheckPeekIfEvent( display, &e, _fev_pred_weed_if, (XPointer)&weed_args); /* e is discarded */ _fev_pred_weed_if_finish(&weed_args); return weed_args.count; } int FWeedAndHandleIfEvents( Display *display, int (*weed_predicate) (Display *display, XEvent *event, XPointer arg), int (*handler) (Display *display, XEvent *event, XPointer arg), XPointer arg) { _fev_check_peek_args cpa; XEvent e; Bool found; int count = 0; assert(fev_is_invalid_event_type_set); memset(&cpa, 0, sizeof(cpa)); cpa.predicate = weed_predicate; cpa.arg = arg; cpa.found = False; do { found = XCheckIfEvent(display, &e, _fev_pred_check_peek_one, (char *)&cpa); if (!found) { break; } count ++; handler(display, &e, arg); fev_update_last_timestamp(&e); } while(1); return count; } int FWeedIfWindowEvents( Display *display, Window window, int (*weed_predicate) ( Display *display, XEvent *current_event, XPointer arg), XPointer arg) { _fev_weed_args weed_args; XEvent e; assert(fev_is_invalid_event_type_set); memset(&weed_args, 0, sizeof(weed_args)); weed_args.weed_predicate = weed_predicate; weed_args.arg = arg; weed_args.w = window; weed_args.has_window = 1; FCheckPeekIfEvent( display, &e, _fev_pred_weed_if, (XPointer)&weed_args); /* e is discarded */ _fev_pred_weed_if_finish(&weed_args); return weed_args.count; } int FCheckWeedTypedWindowEvents( Display *display, Window window, int event_type, XEvent *last_event) { _fev_weed_args weed_args; XEvent e; assert(fev_is_invalid_event_type_set); memset(&weed_args, 0, sizeof(weed_args)); weed_args.w = window; weed_args.event_type = event_type; weed_args.has_window = 1; weed_args.has_event_type = 1; weed_args.ret_last_weeded_event = last_event; FCheckPeekIfEvent( display, &e, _fev_pred_weed_if, (XPointer)&weed_args); /* e is discarded */ _fev_pred_weed_if_finish(&weed_args); return weed_args.count; } Bool FCheckPeekIfEvent( Display *display, XEvent *event_return, Bool (*predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) { XEvent dummy; _fev_check_peek_args cpa; cpa.predicate = predicate; cpa.arg = arg; cpa.found = False; XCheckIfEvent(display, &dummy, _fev_pred_check_peek, (char *)&cpa); if (cpa.found == True) { *event_return = cpa.event; fev_update_last_timestamp(event_return); } return cpa.found; } /* ---------------------------- X event replacements ----------------------- */ XTimeCoord *FGetMotionEvents( Display *display, Window w, Time start, Time stop, int *nevents_return) { XTimeCoord *rc; rc = XGetMotionEvents(display, w, start, stop, nevents_return); return rc; } int FAllowEvents( Display *display, int event_mode, Time time) { int rc; rc = XAllowEvents(display, event_mode, time); return rc; } Bool FCheckIfEvent( Display *display, XEvent *event_return, Bool (*predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) { Bool rc; XEvent new_ev; rc = XCheckIfEvent(display, &new_ev, predicate, arg); if (rc == True) { fev_event_old = fev_event; fev_event = new_ev; *event_return = fev_event; fev_update_last_timestamp(event_return); } return rc; } Bool FCheckMaskEvent( Display *display, long event_mask, XEvent *event_return) { Bool rc; XEvent new_ev; rc = XCheckMaskEvent(display, event_mask, &new_ev); if (rc == True) { fev_event_old = fev_event; fev_event = new_ev; *event_return = fev_event; fev_update_last_timestamp(event_return); } return rc; } Bool FCheckTypedEvent( Display *display, int event_type, XEvent *event_return) { Bool rc; XEvent new_ev; rc = XCheckTypedEvent(display, event_type, &new_ev); if (rc == True) { fev_event_old = fev_event; fev_event = new_ev; *event_return = fev_event; fev_update_last_timestamp(event_return); } return rc; } Bool FCheckTypedWindowEvent( Display *display, Window w, int event_type, XEvent *event_return) { Bool rc; XEvent new_ev; rc = XCheckTypedWindowEvent(display, w, event_type, &new_ev); if (rc == True) { fev_event_old = fev_event; fev_event = new_ev; *event_return = fev_event; fev_update_last_timestamp(event_return); } return rc; } Bool FCheckWindowEvent( Display *display, Window w, long event_mask, XEvent *event_return) { Bool rc; XEvent new_ev; rc = XCheckWindowEvent(display, w, event_mask, &new_ev); if (rc == True) { fev_event_old = fev_event; fev_event = new_ev; *event_return = fev_event; fev_update_last_timestamp(event_return); } return rc; } int FEventsQueued( Display *display, int mode) { int rc; rc = XEventsQueued(display, mode); return rc; } int FIfEvent( Display *display, XEvent *event_return, Bool (*predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) { int rc; fev_event_old = fev_event; rc = XIfEvent(display, &fev_event, predicate, arg); *event_return = fev_event; fev_update_last_timestamp(event_return); return rc; } int FMaskEvent( Display *display, long event_mask, XEvent *event_return) { int rc; fev_event_old = fev_event; rc = XMaskEvent(display, event_mask, &fev_event); *event_return = fev_event; fev_update_last_timestamp(event_return); return rc; } int FNextEvent( Display *display, XEvent *event_return) { int rc; fev_event_old = fev_event; rc = XNextEvent(display, &fev_event); *event_return = fev_event; fev_update_last_timestamp(event_return); return rc; } int FPeekEvent( Display *display, XEvent *event_return) { int rc; rc = XPeekEvent(display, event_return); fev_update_last_timestamp(event_return); return rc; } int FPeekIfEvent( Display *display, XEvent *event_return, Bool (*predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) { int rc; rc = XPeekIfEvent(display, event_return, predicate, arg); if (rc == True) { fev_update_last_timestamp(event_return); } return rc; } int FPending( Display *display) { int rc; rc = XPending(display); return rc; } int FPutBackEvent( Display *display, XEvent *event) { int rc; rc = XPutBackEvent(display, event); fev_event = fev_event_old; return rc; } int FQLength( Display *display) { int rc; rc = XQLength(display); return rc; } void FQueryPointer( Display *display, Window w, Window *root_return, Window *child_return, int *root_x_return, int *root_y_return, int *win_x_return, int *win_y_return, unsigned int *mask_return) { XQueryPointer( display, w, root_return, child_return, root_x_return, root_y_return, win_x_return, win_y_return, mask_return); return; } Status FSendEvent( Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send) { Status rc; rc = XSendEvent(display, w, propagate, event_mask, event_send); return rc; } int FWarpPointer( Display *display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y) { int rc; rc = XWarpPointer( display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x, dest_y); return rc; } int FWarpPointerUpdateEvpos( XEvent *ev, Display *display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y) { int rc; rc = XWarpPointer( display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x, dest_y); if (ev != NULL && dest_w == DefaultRootWindow(display)) { fev_set_evpos(ev, dest_x, dest_y); } return rc; } int FWindowEvent( Display *display, Window w, long event_mask, XEvent *event_return) { int rc; fev_event_old = fev_event; rc = XWindowEvent(display, w, event_mask, &fev_event); *event_return = fev_event; fev_update_last_timestamp(event_return); return rc; } Status FGetWMNormalHints( Display *display, Window w, XSizeHints *hints_return, long *supplied_return) { Status ret; memset(hints_return, 0, sizeof(XSizeHints)); ret = XGetWMNormalHints(display, w, hints_return, supplied_return); fev_sanitize_size_hints(hints_return); return ret; }