1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-01-07 14:24:14 +01:00
Files
wmaker/WINGs/wevent.c
dan 9aca0d5f6e - Check whether libXft is at least version 2.1.2 else refuse to compile.
- Fixed bug in icon chooser dialog that could cause a segmentation fault
  in some cases (Pascal Hofstee <caelian@gmail.com>)
- Fixed crash in asm code in wrlib, with new versions of gcc.
- Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly
  used the r, g, b fields in the conversion.
- Fixed x86 ASM code in wrlib to work on 64 bit architectures.
- Fixed the focus flicker seen with some apps (notably gtk2)
  (Alexey Spiridonov <snarkmaster@gmail.com>)
- Fixed all crashing bugs that were generated by wmaker starting with the
  WMState file missing.
- Added NetWM support (a modified version of the patch originaly written
  by Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied patch to enhance the Virtual Desktop behaviour, and to integrate
  it with the NetWM code (Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied a few xinerama and placement fixes (Peter Zijlstra
    <a.p.zijlstra@chello.nl>)
- Fixed memory leak in dock code.
- Fixed and enhanced the text wrapping in WINGs.
- Fixed the layout of some elements in WPrefs.app
- Added workaround for aplications that don't set the required hints on the
  client leader window, but they set them on normal windows (observer with
  KDE 3.3.0 mainly). This will allow these apps to get an appicon again.
  (they should be fixed still)
- Added workaround for applications that do not set a command with
  XSetCommand(), but instead they set the _NET_WM_PID property. This works
  with operating systems that offer a /proc interface similar to what linux
  has. (This also is to fix problems with KDE 3.3.0 apps, but not only them).
- Fixed bug with autostart and exit scripts not being executed if user
  GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT)
- Added utf8 support in WINGs (removed old X core font code)
- Added utility to convert old font names to new font names in style files
2004-10-12 01:34:32 +00:00

474 lines
13 KiB
C

/*
* This event handling stuff was inspired on Tk.
*/
#include "WINGsP.h"
/* table to map event types to event masks */
static unsigned long eventMasks[] = {
0,
0,
KeyPressMask, /* KeyPress */
KeyReleaseMask, /* KeyRelease */
ButtonPressMask, /* ButtonPress */
ButtonReleaseMask, /* ButtonRelease */
PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
|Button1MotionMask|Button2MotionMask|Button3MotionMask
|Button4MotionMask|Button5MotionMask,
/* MotionNotify */
EnterWindowMask, /* EnterNotify */
LeaveWindowMask, /* LeaveNotify */
FocusChangeMask, /* FocusIn */
FocusChangeMask, /* FocusOut */
KeymapStateMask, /* KeymapNotify */
ExposureMask, /* Expose */
ExposureMask, /* GraphicsExpose */
ExposureMask, /* NoExpose */
VisibilityChangeMask, /* VisibilityNotify */
SubstructureNotifyMask, /* CreateNotify */
StructureNotifyMask, /* DestroyNotify */
StructureNotifyMask, /* UnmapNotify */
StructureNotifyMask, /* MapNotify */
SubstructureRedirectMask, /* MapRequest */
StructureNotifyMask, /* ReparentNotify */
StructureNotifyMask, /* ConfigureNotify */
SubstructureRedirectMask, /* ConfigureRequest */
StructureNotifyMask, /* GravityNotify */
ResizeRedirectMask, /* ResizeRequest */
StructureNotifyMask, /* CirculateNotify */
SubstructureRedirectMask, /* CirculateRequest */
PropertyChangeMask, /* PropertyNotify */
0, /* SelectionClear */
0, /* SelectionRequest */
0, /* SelectionNotify */
ColormapChangeMask, /* ColormapNotify */
ClientMessageMask, /* ClientMessage */
0, /* Mapping Notify */
};
/* hook for other toolkits or wmaker process their events */
static WMEventHook *extraEventHandler=NULL;
/*
* WMCreateEventHandler--
* Create an event handler and put it in the event handler list for the
* view. If the same callback and clientdata are already used in another
* handler, the masks are OR'ed.
*
*/
void
WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
void *clientData)
{
W_EventHandler *hPtr;
WMArrayIterator iter;
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
if (hPtr->clientData==clientData && hPtr->proc==eventProc) {
hPtr->eventMask |= mask;
return;
}
}
hPtr = wmalloc(sizeof(W_EventHandler));
/* select events for window */
hPtr->eventMask = mask;
hPtr->proc = eventProc;
hPtr->clientData = clientData;
WMAddToArray(view->eventHandlers, hPtr);
}
static int
matchHandler(void *item, void *cdata)
{
#define H1 ((W_EventHandler*)item)
#define H2 ((W_EventHandler*)cdata)
return (H1->eventMask==H2->eventMask && H1->proc==H2->proc &&
H1->clientData==H2->clientData);
}
/*
* WMDeleteEventHandler--
* Delete event handler matching arguments from windows
* event handler list.
*
*/
void
WMDeleteEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc,
void *clientData)
{
W_EventHandler tmp;
tmp.eventMask = mask;
tmp.proc = eventProc;
tmp.clientData = clientData;
WMRemoveFromArrayMatching(view->eventHandlers, matchHandler, (void*)&tmp);
}
static Time
getEventTime(WMScreen *screen, XEvent *event)
{
switch (event->type) {
case ButtonPress:
case ButtonRelease:
return event->xbutton.time;
case KeyPress:
case KeyRelease:
return event->xkey.time;
case MotionNotify:
return event->xmotion.time;
case EnterNotify:
case LeaveNotify:
return event->xcrossing.time;
case PropertyNotify:
return event->xproperty.time;
case SelectionClear:
return event->xselectionclear.time;
case SelectionRequest:
return event->xselectionrequest.time;
case SelectionNotify:
return event->xselection.time;
default:
return screen->lastEventTime;
}
}
void
W_CallDestroyHandlers(W_View *view)
{
XEvent event;
WMArrayIterator iter;
W_EventHandler *hPtr;
event.type = DestroyNotify;
event.xdestroywindow.window = view->window;
event.xdestroywindow.event = view->window;
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
if (hPtr->eventMask & StructureNotifyMask) {
(*hPtr->proc)(&event, hPtr->clientData);
}
}
}
void
WMSetViewNextResponder(WMView *view, WMView *responder)
{
/* set the widget to receive keyboard events that aren't handled
* by this widget */
view->nextResponder = responder;
}
void
WMRelayToNextResponder(WMView *view, XEvent *event)
{
unsigned long mask = eventMasks[event->xany.type];
if (view->nextResponder) {
WMView *next = view->nextResponder;
W_EventHandler *hPtr;
WMArrayIterator iter;
WM_ITERATE_ARRAY(next->eventHandlers, hPtr, iter) {
if ((hPtr->eventMask & mask)) {
(*hPtr->proc)(event, hPtr->clientData);
}
}
}
}
int
WMHandleEvent(XEvent *event)
{
W_EventHandler *hPtr;
W_View *view, *toplevel;
unsigned long mask;
Window window;
WMArrayIterator iter;
if (event->type == MappingNotify) {
XRefreshKeyboardMapping(&event->xmapping);
return True;
}
mask = eventMasks[event->xany.type];
window = event->xany.window;
/* diferentiate SubstructureNotify with StructureNotify */
if (mask == StructureNotifyMask) {
if (event->xmap.event != event->xmap.window) {
mask = SubstructureNotifyMask;
window = event->xmap.event;
}
}
view = W_GetViewForXWindow(event->xany.display, window);
if (!view) {
if (extraEventHandler)
(extraEventHandler)(event);
return False;
}
view->screen->lastEventTime = getEventTime(view->screen, event);
toplevel = W_TopLevelOfView(view);
if (event->type == SelectionNotify || event->type == SelectionClear
|| event->type == SelectionRequest) {
/* handle selection related events */
W_HandleSelectionEvent(event);
}
/* if it's a key event, redispatch it to the focused control */
if (mask & (KeyPressMask|KeyReleaseMask)) {
W_View *focused = W_FocusedViewOfToplevel(toplevel);
if (focused) {
view = focused;
}
}
/* compress Motion events */
if (event->type == MotionNotify && !view->flags.dontCompressMotion) {
while (XPending(event->xmotion.display)) {
XEvent ev;
XPeekEvent(event->xmotion.display, &ev);
if (ev.type == MotionNotify
&& event->xmotion.window == ev.xmotion.window
&& event->xmotion.subwindow == ev.xmotion.subwindow) {
/* replace events */
XNextEvent(event->xmotion.display, event);
} else break;
}
}
/* compress expose events */
if (event->type == Expose && !view->flags.dontCompressExpose) {
while (XCheckTypedWindowEvent(event->xexpose.display, view->window,
Expose, event));
}
if (view->screen->modalLoop && toplevel!=view->screen->modalView
&& !toplevel->flags.worksWhenModal) {
if (event->type == KeyPress || event->type == KeyRelease
|| event->type == MotionNotify || event->type == ButtonPress
|| event->type == ButtonRelease
|| event->type == FocusIn || event->type == FocusOut) {
return True;
}
}
/* do balloon stuffs */
if (event->type == EnterNotify)
W_BalloonHandleEnterView(view);
else if (event->type == LeaveNotify)
W_BalloonHandleLeaveView(view);
/* This is a hack. It will make the panel be secure while
* the event handlers are handled, as some event handler
* might destroy the widget. */
W_RetainView(toplevel);
WM_ITERATE_ARRAY(view->eventHandlers, hPtr, iter) {
if ((hPtr->eventMask & mask)) {
(*hPtr->proc)(event, hPtr->clientData);
}
}
#if 0
/* pass the event to the top level window of the widget */
/* TODO: change this to a responder chain */
if (view->parent != NULL) {
vPtr = view;
while (vPtr->parent != NULL)
vPtr = vPtr->parent;
WM_ITERATE_ARRAY(vPtr->eventHandlers, hPtr, iter) {
if (hPtr->eventMask & mask) {
(*hPtr->proc)(event, hPtr->clientData);
}
}
}
#endif
/* save button click info to track double-clicks */
if (view->screen->ignoreNextDoubleClick) {
view->screen->ignoreNextDoubleClick = 0;
} else {
if (event->type == ButtonPress) {
view->screen->lastClickWindow = event->xbutton.window;
view->screen->lastClickTime = event->xbutton.time;
}
}
if (event->type == ClientMessage) {
/* must be handled at the end, for such message can destroy the view */
W_HandleDNDClientMessage(toplevel, &event->xclient);
}
W_ReleaseView(toplevel);
return True;
}
int
WMIsDoubleClick(XEvent *event)
{
W_View *view;
if (event->type != ButtonPress)
return False;
view = W_GetViewForXWindow(event->xany.display, event->xbutton.window);
if (!view)
return False;
if (view->screen->lastClickWindow != event->xbutton.window)
return False;
if (event->xbutton.time - view->screen->lastClickTime
< WINGsConfiguration.doubleClickDelay) {
view->screen->lastClickTime = 0;
view->screen->lastClickWindow = None;
view->screen->ignoreNextDoubleClick = 1;
return True;
} else
return False;
}
/*
* Check for X and input events. If X events are present input events will
* not be checked.
*
* Return value: True if a X event is available or any input event was
* processed, false otherwise (including return because of
* some timer handler expired).
*
* If waitForInput is False, it will just peek for available input and return
* without processing. Return vaue will be True if input is available.
*
* If waitForInput is True, it will wait until an input event arrives on the
* registered input handlers and ConnectionNumber(dpy), or will return when
* a timer handler expires if no input event arrived until then.
*/
static Bool
waitForEvent(Display *dpy, unsigned long xeventmask, Bool waitForInput)
{
XSync(dpy, False);
if (xeventmask==0) {
if (XPending(dpy))
return True;
} else {
XEvent ev;
if (XCheckMaskEvent(dpy, xeventmask, &ev)) {
XPutBackEvent(dpy, &ev);
return True;
}
}
return W_HandleInputEvents(waitForInput, ConnectionNumber(dpy));
}
void
WMNextEvent(Display *dpy, XEvent *event)
{
/* Check any expired timers */
W_CheckTimerHandlers();
while (XPending(dpy) == 0) {
/* Do idle and timer stuff while there are no input or X events */
while (!waitForEvent(dpy, 0, False) && W_CheckIdleHandlers()) {
/* dispatch timer events */
W_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 for something to happen or a timer to expire */
waitForEvent(dpy, 0, True);
/* Check any expired timers */
W_CheckTimerHandlers();
}
XNextEvent(dpy, event);
}
void
WMMaskEvent(Display *dpy, long mask, XEvent *event)
{
/* Check any expired timers */
W_CheckTimerHandlers();
while (!XCheckMaskEvent(dpy, mask, event)) {
/* Do idle and timer stuff while there are no input or X events */
while (!waitForEvent(dpy, mask, False) && W_CheckIdleHandlers()) {
W_CheckTimerHandlers();
}
if (XCheckMaskEvent(dpy, mask, event))
return;
/* Wait for input on the X connection socket or another input handler */
waitForEvent(dpy, mask, True);
/* Check any expired timers */
W_CheckTimerHandlers();
}
}
Bool
WMScreenPending(WMScreen *scr)
{
if (XPending(scr->display))
return True;
else
return False;
}
WMEventHook*
WMHookEventHandler(WMEventHook *handler)
{
WMEventHook *oldHandler = extraEventHandler;
extraEventHandler = handler;
return oldHandler;
}