Files
wmaker/src/event.c
T

1875 lines
51 KiB
C
Raw Normal View History

1998-09-29 22:36:29 +00:00
/* event.c- event loop and handling
2004-10-12 21:28:27 +00:00
*
1998-10-21 14:43:47 +00:00
* Window Maker window manager
2004-10-12 21:28:27 +00:00
*
2003-01-16 23:30:45 +00:00
* Copyright (c) 1997-2003 Alfredo K. Kojima
2004-10-12 21:28:27 +00:00
*
1998-09-29 22:36:29 +00:00
* 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, write to the Free Software
2004-10-12 21:28:27 +00:00
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
1998-09-29 22:36:29 +00:00
* USA.
*/
#include <sys/inotify.h>
1998-09-29 22:36:29 +00:00
#include "wconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
1999-10-20 03:25:06 +00:00
1998-09-29 22:36:29 +00:00
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef SHAPE
1999-10-20 03:25:06 +00:00
# include <X11/extensions/shape.h>
1998-09-29 22:36:29 +00:00
#endif
1999-05-17 20:21:43 +00:00
#ifdef XDND
#include "xdnd.h"
1998-10-21 14:43:47 +00:00
#endif
2004-10-12 21:28:27 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
#include <X11/XKBlib.h>
1998-11-03 12:53:26 +00:00
#endif /* KEEP_XKB_LOCK_STATUS */
1998-09-29 22:36:29 +00:00
#include "WindowMaker.h"
#include "window.h"
#include "actions.h"
#include "client.h"
#include "funcs.h"
#include "keybind.h"
#include "application.h"
#include "stacking.h"
#include "defaults.h"
#include "workspace.h"
#include "dock.h"
#include "framewin.h"
#include "properties.h"
#include "balloon.h"
#include "xinerama.h"
1999-09-16 02:58:56 +00:00
#ifdef NETWM_HINTS
# include "wmspec.h"
#endif
1998-09-29 22:36:29 +00:00
/******** Global Variables **********/
extern XContext wWinContext;
extern XContext wVEdgeContext;
1998-09-29 22:36:29 +00:00
extern Cursor wCursor[WCUR_LAST];
extern WShortKey wKeyBindings[WKBD_LAST];
extern int wScreenCount;
extern Time LastTimestamp;
extern Time LastFocusChange;
extern WPreferences wPreferences;
#define MOD_MASK wPreferences.modifier_mask
1998-11-03 12:53:26 +00:00
extern Atom _XA_WM_COLORMAP_NOTIFY;
1998-09-29 22:36:29 +00:00
extern Atom _XA_WM_CHANGE_STATE;
extern Atom _XA_WM_DELETE_WINDOW;
extern Atom _XA_GNUSTEP_WM_ATTR;
1998-10-21 14:43:47 +00:00
extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
1998-09-29 22:36:29 +00:00
extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
1999-04-03 03:51:17 +00:00
extern Atom _XA_WINDOWMAKER_COMMAND;
1998-09-29 22:36:29 +00:00
#ifdef SHAPE
1998-10-21 14:43:47 +00:00
extern Bool wShapeSupported;
extern int wShapeEventBase;
1998-09-29 22:36:29 +00:00
#endif
2004-10-12 21:28:27 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
1999-05-23 19:33:19 +00:00
extern int wXkbEventBase;
#endif
1998-09-29 22:36:29 +00:00
/* special flags */
/*extern char WDelayedActionSet;*/
1998-09-29 22:36:29 +00:00
/************ Local stuff ***********/
static void saveTimestamp(XEvent *event);
static void handleColormapNotify();
2004-10-12 21:28:27 +00:00
static void handleMapNotify();
static void handleUnmapNotify();
static void handleButtonPress();
static void handleExpose();
1998-09-29 22:36:29 +00:00
static void handleDestroyNotify();
static void handleConfigureRequest();
static void handleMapRequest();
static void handlePropertyNotify();
static void handleEnterNotify();
static void handleLeaveNotify();
static void handleExtensions();
static void handleClientMessage();
static void handleKeyPress();
static void handleFocusIn();
static void handleMotionNotify();
static void handleVisibilityNotify();
1998-11-03 12:53:26 +00:00
1999-01-25 19:06:50 +00:00
1998-09-29 22:36:29 +00:00
#ifdef SHAPE
static void handleShapeNotify();
#endif
/* called from the signal handler */
void NotifyDeadProcess(pid_t pid, unsigned char status);
/* real dead process handler */
static void handleDeadProcess(void *foo);
typedef struct DeadProcesses {
pid_t pid;
unsigned char exit_status;
} DeadProcesses;
/* stack of dead processes */
static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
static int deadProcessPtr=0;
typedef struct DeathHandler {
WDeathHandler *callback;
pid_t pid;
void *client_data;
} DeathHandler;
static WMArray *deathHandlers=NULL;
1998-09-29 22:36:29 +00:00
1998-11-03 12:53:26 +00:00
WMagicNumber
1998-09-29 22:36:29 +00:00
wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
{
DeathHandler *handler;
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
handler = malloc(sizeof(DeathHandler));
if (!handler)
2004-10-12 21:28:27 +00:00
return 0;
1999-09-16 02:58:56 +00:00
1998-09-29 22:36:29 +00:00
handler->pid = pid;
handler->callback = callback;
handler->client_data = cdata;
1999-09-16 02:58:56 +00:00
if (!deathHandlers)
2004-10-12 21:28:27 +00:00
deathHandlers = WMCreateArrayWithDestructor(8, wfree);
1999-09-16 02:58:56 +00:00
WMAddToArray(deathHandlers, handler);
1998-09-29 22:36:29 +00:00
return handler;
}
2004-10-12 21:28:27 +00:00
void
1998-11-03 12:53:26 +00:00
wDeleteDeathHandler(WMagicNumber id)
1998-09-29 22:36:29 +00:00
{
1999-09-16 02:58:56 +00:00
DeathHandler *handler=(DeathHandler*)id;
1998-09-29 22:36:29 +00:00
1999-09-16 02:58:56 +00:00
if (!handler || !deathHandlers)
2004-10-12 21:28:27 +00:00
return;
1998-09-29 22:36:29 +00:00
/* array destructor will call wfree(handler) */
WMRemoveFromArray(deathHandlers, handler);
1998-09-29 22:36:29 +00:00
}
void
DispatchEvent(XEvent *event)
{
1999-09-16 02:58:56 +00:00
if (deathHandlers)
2004-10-12 21:28:27 +00:00
handleDeadProcess(NULL);
1999-09-16 02:58:56 +00:00
1999-03-09 14:58:01 +00:00
if (WCHECK_STATE(WSTATE_NEED_EXIT)) {
2004-10-12 21:28:27 +00:00
WCHANGE_STATE(WSTATE_EXITING);
/* received SIGTERM */
/*
* WMHandleEvent() can't be called from anything
* executed inside here, or we can get in a infinite
* recursive loop.
*/
Shutdown(WSExitMode);
1999-01-06 15:22:33 +00:00
1999-03-09 14:58:01 +00:00
} else if (WCHECK_STATE(WSTATE_NEED_RESTART)) {
2004-10-12 21:28:27 +00:00
WCHANGE_STATE(WSTATE_RESTARTING);
1998-09-29 22:36:29 +00:00
2004-10-12 21:28:27 +00:00
Shutdown(WSRestartPreparationMode);
/* received SIGHUP */
Restart(NULL, True);
2001-01-30 03:04:02 +00:00
} else if (WCHECK_STATE(WSTATE_NEED_REREAD)) {
WCHANGE_STATE(WSTATE_NORMAL);
wDefaultsCheckDomains("bla");
1998-09-29 22:36:29 +00:00
}
/* for the case that all that is wanted to be dispatched is
* the stuff above */
if (!event)
2004-10-12 21:28:27 +00:00
return;
1999-09-16 02:58:56 +00:00
saveTimestamp(event);
1998-09-29 22:36:29 +00:00
switch (event->type) {
2004-10-12 21:28:27 +00:00
case MapRequest:
handleMapRequest(event);
break;
case KeyPress:
handleKeyPress(event);
break;
case MotionNotify:
handleMotionNotify(event);
break;
case ConfigureRequest:
handleConfigureRequest(event);
break;
case DestroyNotify:
handleDestroyNotify(event);
break;
case MapNotify:
handleMapNotify(event);
break;
case UnmapNotify:
handleUnmapNotify(event);
break;
case ButtonPress:
handleButtonPress(event);
break;
case Expose:
handleExpose(event);
break;
case PropertyNotify:
handlePropertyNotify(event);
break;
case EnterNotify:
handleEnterNotify(event);
break;
case LeaveNotify:
1998-09-29 22:36:29 +00:00
handleLeaveNotify(event);
2004-10-12 21:28:27 +00:00
break;
case ClientMessage:
handleClientMessage(event);
break;
case ColormapNotify:
handleColormapNotify(event);
break;
case MappingNotify:
if (event->xmapping.request == MappingKeyboard
|| event->xmapping.request == MappingModifier)
XRefreshKeyboardMapping(&event->xmapping);
break;
case FocusIn:
handleFocusIn(event);
break;
case VisibilityNotify:
handleVisibilityNotify(event);
break;
default:
handleExtensions(event);
break;
1998-09-29 22:36:29 +00:00
}
}
/*
*----------------------------------------------------------------------
* inotifyHandleEvents-
* Check for inotify events
*
* Returns:
* After reading events for the given file descriptor (fd) and
* watch descriptor (wd)
*
* Side effects:
* Calls wDefaultsCheckDomains if config database is updated
*----------------------------------------------------------------------
*/
/* Allow for 1024 simultanious events */
#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
void inotifyHandleEvents (int fd, int wd)
{
ssize_t eventQLength, i = 0;
char buff[BUFF_SIZE] = {0};
extern void wDefaultsCheckDomains();
int oneShotFlag=0; /* Only check config once per read of the event queue */
/* Read off the queued events
* queue overflow is not checked (IN_Q_OVERFLOW). In practise this should
* not occur; the block is on Xevents, but a config file change will normally
* occur as a result of an Xevent - so the event queue should never have more than
* a few entries before a read().
*/
eventQLength = read (fd, buff, BUFF_SIZE);
/* check what events occured */
/* Should really check wd here too, but for now we only have one watch! */
while (i < eventQLength) {
struct inotify_event *pevent = (struct inotify_event *)&buff[i];
/*
* see inotify.h for event types.
*/
if (pevent->mask & IN_DELETE_SELF) {
wwarning(_("the defaults database has been deleted!"
" Restart Window Maker to create the database"
" with the default settings"));
close(fd);
}
if (pevent->mask & IN_UNMOUNT) {
wwarning(_("the unit containing the defaults database has"
" been unmounted. Setting --static mode."
" Any changes will not be saved."));
close(fd);
wPreferences.flags.noupdates=1;
}
if ((pevent->mask & IN_MODIFY) && oneShotFlag == 0) {
fprintf(stdout,"wmaker: reading config files in defaults database.\n");
wDefaultsCheckDomains(NULL);
}
/* Check for filename (length of name (len) > 0) */
/* if (pevent->len) printf ("name=%s\n", pevent->name); */
i += sizeof(struct inotify_event) + pevent->len; /* move to next event in the buffer */
}
} /* inotifyHandleEvents */
1998-09-29 22:36:29 +00:00
/*
*----------------------------------------------------------------------
* EventLoop-
* Processes X and internal events indefinitely.
2004-10-12 21:28:27 +00:00
*
1998-09-29 22:36:29 +00:00
* Returns:
* Never returns
2004-10-12 21:28:27 +00:00
*
1998-09-29 22:36:29 +00:00
* Side effects:
* The LastTimestamp global variable is updated.
* Calls inotifyGetEvents if defaults database changes.
2004-10-12 21:28:27 +00:00
*----------------------------------------------------------------------
1998-09-29 22:36:29 +00:00
*/
void
EventLoop()
{
XEvent event;
extern int inotifyFD;
extern int inotifyWD;
struct timeval time;
fd_set rfds;
int retVal=0;
if (inotifyFD < 0 || inotifyWD < 0)
retVal = -1;
1998-09-29 22:36:29 +00:00
for(;;) {
2008-05-02 20:01:50 -03:00
WMNextEvent(dpy, &event); /* Blocks here */
WMHandleEvent(&event);
if (retVal != -1 ) {
time.tv_sec = 0;
time.tv_usec = 0;
FD_ZERO (&rfds);
FD_SET (inotifyFD, &rfds);
/* check for available read data from inotify - don't block! */
retVal = select (inotifyFD + 1, &rfds, NULL, NULL, &time);
if (retVal < 0) { /* an error has occured */
wwarning(_("select failed. The inotify instance will be closed."
" Changes to the defaults database will require"
" a restart to take effect."));
close(inotifyFD);
continue;
}
if (FD_ISSET (inotifyFD, &rfds))
inotifyHandleEvents(inotifyFD,inotifyWD);
}
1998-09-29 22:36:29 +00:00
}
}
/*
*----------------------------------------------------------------------
* ProcessPendingEvents --
* Processes the events that are currently pending (at the time
* this function is called) in the display's queue.
*
* Returns:
* After the pending events that were present at the function call
* are processed.
*
* Side effects:
2004-10-12 21:28:27 +00:00
* Many -- whatever handling events may involve.
*
*----------------------------------------------------------------------
*/
void
ProcessPendingEvents()
{
XEvent event;
int count;
XSync(dpy, False);
/* Take a snapshot of the event count in the queue */
count = XPending(dpy);
while (count>0 && XPending(dpy)) {
WMNextEvent(dpy, &event);
WMHandleEvent(&event);
count--;
}
}
1998-09-29 22:36:29 +00:00
2004-10-12 21:28:27 +00:00
Bool
1998-09-29 22:36:29 +00:00
IsDoubleClick(WScreen *scr, XEvent *event)
{
2004-10-12 21:28:27 +00:00
if ((scr->last_click_time>0) &&
(event->xbutton.time-scr->last_click_time<=wPreferences.dblclick_time)
&& (event->xbutton.button == scr->last_click_button)
&& (event->xbutton.window == scr->last_click_window)) {
1998-09-29 22:36:29 +00:00
2004-10-12 21:28:27 +00:00
scr->flags.next_click_is_not_double = 1;
scr->last_click_time = 0;
scr->last_click_window = event->xbutton.window;
1998-09-29 22:36:29 +00:00
2004-10-12 21:28:27 +00:00
return True;
1998-09-29 22:36:29 +00:00
}
return False;
}
void
NotifyDeadProcess(pid_t pid, unsigned char status)
{
if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
2004-10-12 21:28:27 +00:00
wwarning("stack overflow: too many dead processes");
return;
1998-09-29 22:36:29 +00:00
}
/* stack the process to be handled later,
* as this is called from the signal handler */
deadProcesses[deadProcessPtr].pid = pid;
deadProcesses[deadProcessPtr].exit_status = status;
deadProcessPtr++;
}
static void
handleDeadProcess(void *foo)
{
DeathHandler *tmp;
1998-10-21 14:43:47 +00:00
int i;
1998-09-29 22:36:29 +00:00
1998-10-21 14:43:47 +00:00
for (i=0; i<deadProcessPtr; i++) {
2004-10-12 21:28:27 +00:00
wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
1998-09-29 22:36:29 +00:00
}
1999-09-16 02:58:56 +00:00
if (!deathHandlers) {
2004-10-12 21:28:27 +00:00
deadProcessPtr=0;
return;
1998-09-29 22:36:29 +00:00
}
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
/* get the pids on the queue and call handlers */
while (deadProcessPtr>0) {
2004-10-12 21:28:27 +00:00
deadProcessPtr--;
for (i = WMGetArrayItemCount(deathHandlers)-1; i >= 0; i--) {
tmp = WMGetFromArray(deathHandlers, i);
if (!tmp)
continue;
if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
(*tmp->callback)(tmp->pid,
deadProcesses[deadProcessPtr].exit_status,
tmp->client_data);
wDeleteDeathHandler(tmp);
}
}
1998-09-29 22:36:29 +00:00
}
}
static void
saveTimestamp(XEvent *event)
{
/*
* Never save CurrentTime as LastTimestamp because CurrentTime
* it's not a real timestamp (it's the 0L constant)
*/
1998-09-29 22:36:29 +00:00
switch (event->type) {
2004-10-12 21:28:27 +00:00
case ButtonRelease:
case ButtonPress:
LastTimestamp = event->xbutton.time;
break;
case KeyPress:
case KeyRelease:
LastTimestamp = event->xkey.time;
break;
case MotionNotify:
LastTimestamp = event->xmotion.time;
break;
case PropertyNotify:
LastTimestamp = event->xproperty.time;
break;
case EnterNotify:
case LeaveNotify:
LastTimestamp = event->xcrossing.time;
break;
case SelectionClear:
LastTimestamp = event->xselectionclear.time;
break;
case SelectionRequest:
LastTimestamp = event->xselectionrequest.time;
break;
case SelectionNotify:
LastTimestamp = event->xselection.time;
1999-05-17 20:21:43 +00:00
#ifdef XDND
wXDNDProcessSelection(event);
1999-05-17 20:21:43 +00:00
#endif
2004-10-12 21:28:27 +00:00
break;
1998-09-29 22:36:29 +00:00
}
}
static int
matchWindow(void *item, void *cdata)
{
return (((WFakeGroupLeader*)item)->origLeader == (Window)cdata);
}
1998-09-29 22:36:29 +00:00
static void
handleExtensions(XEvent *event)
{
2004-10-12 21:28:27 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
1999-05-22 21:30:35 +00:00
XkbEvent *xkbevent;
1999-05-23 19:33:19 +00:00
xkbevent = (XkbEvent *)event;
#endif /*KEEP_XKB_LOCK_STATUS*/
1998-09-29 22:36:29 +00:00
#ifdef SHAPE
1998-10-21 14:43:47 +00:00
if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
2004-10-12 21:28:27 +00:00
handleShapeNotify(event);
1998-09-29 22:36:29 +00:00
}
2004-10-12 21:28:27 +00:00
#endif
#ifdef KEEP_XKB_LOCK_STATUS
1999-05-23 19:33:19 +00:00
if (wPreferences.modelock && (xkbevent->type == wXkbEventBase)){
handleXkbIndicatorStateNotify(event);
}
#endif /*KEEP_XKB_LOCK_STATUS*/
1998-09-29 22:36:29 +00:00
}
1999-01-06 15:22:33 +00:00
2004-10-12 21:28:27 +00:00
static void
1998-09-29 22:36:29 +00:00
handleMapRequest(XEvent *ev)
{
WWindow *wwin;
WScreen *scr = NULL;
Window window = ev->xmaprequest.window;
#ifdef DEBUG
printf("got map request for %x\n", (unsigned)window);
1998-09-29 22:36:29 +00:00
#endif
if ((wwin = wWindowFor(window))) {
2004-10-12 21:28:27 +00:00
if (wwin->flags.shaded) {
wUnshadeWindow(wwin);
}
/* deiconify window */
if (wwin->flags.miniaturized) {
wDeiconifyWindow(wwin);
} else if (wwin->flags.hidden) {
1998-09-29 22:36:29 +00:00
WApplication *wapp = wApplicationOf(wwin->main_window);
/* go to the last workspace that the user worked on the app */
if (wapp) {
wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
}
2004-10-12 21:28:27 +00:00
wUnhideApplication(wapp, False, False);
}
return;
1998-09-29 22:36:29 +00:00
}
scr = wScreenForRootWindow(ev->xmaprequest.parent);
wwin = wManageWindow(scr, window);
2004-10-12 21:28:27 +00:00
/*
1998-09-29 22:36:29 +00:00
* This is to let the Dock know that the application it launched
2004-10-12 21:28:27 +00:00
* has already been mapped (eg: it has finished launching).
1998-09-29 22:36:29 +00:00
* It is not necessary for normally docked apps, but is needed for
* apps that were forcedly docked (like with dockit).
*/
if (scr->last_dock) {
2004-10-12 21:28:27 +00:00
if (wwin && wwin->main_window!=None && wwin->main_window!=window)
wDockTrackWindowLaunch(scr->last_dock, wwin->main_window);
else
wDockTrackWindowLaunch(scr->last_dock, window);
1998-09-29 22:36:29 +00:00
}
if (wwin) {
2004-10-12 21:28:27 +00:00
wClientSetState(wwin, NormalState, None);
if (wwin->flags.maximized) {
wMaximizeWindow(wwin, wwin->flags.maximized);
}
if (wwin->flags.shaded) {
wwin->flags.shaded = 0;
wwin->flags.skip_next_animation = 1;
wShadeWindow(wwin);
}
if (wwin->flags.miniaturized) {
wwin->flags.miniaturized = 0;
wwin->flags.skip_next_animation = 1;
wIconifyWindow(wwin);
}
2005-08-22 23:58:19 +00:00
if (wwin->flags.fullscreen) {
wwin->flags.fullscreen = 0;
wFullscreenWindow(wwin);
}
2004-10-12 21:28:27 +00:00
if (wwin->flags.hidden) {
WApplication *wapp = wApplicationOf(wwin->main_window);
wwin->flags.hidden = 0;
wwin->flags.skip_next_animation = 1;
if (wapp) {
wHideApplication(wapp);
}
}
1998-09-29 22:36:29 +00:00
}
}
static void
1999-01-06 15:22:33 +00:00
handleDestroyNotify(XEvent *event)
1998-09-29 22:36:29 +00:00
{
WWindow *wwin;
WApplication *app;
1999-01-06 15:22:33 +00:00
Window window = event->xdestroywindow.window;
WScreen *scr = wScreenForRootWindow(event->xdestroywindow.event);
int index;
1999-01-06 15:22:33 +00:00
1998-09-29 22:36:29 +00:00
#ifdef DEBUG
printf("got destroy notify\n");
1999-10-20 03:25:06 +00:00
#endif
1998-09-29 22:36:29 +00:00
wwin = wWindowFor(window);
if (wwin) {
2004-10-12 21:28:27 +00:00
wUnmanageWindow(wwin, False, True);
1998-09-29 22:36:29 +00:00
}
if (scr != NULL) {
while ((index = WMFindInArray(scr->fakeGroupLeaders, matchWindow,
(void*)window)) != WANotFound) {
WFakeGroupLeader *fPtr;
fPtr = WMGetFromArray(scr->fakeGroupLeaders, index);
if (fPtr->retainCount > 0) {
fPtr->retainCount--;
if (fPtr->retainCount==0 && fPtr->leader!=None) {
XDestroyWindow(dpy, fPtr->leader);
fPtr->leader = None;
XFlush(dpy);
}
}
fPtr->origLeader = None;
}
}
1998-09-29 22:36:29 +00:00
app = wApplicationOf(window);
if (app) {
2004-10-12 21:28:27 +00:00
if (window == app->main_window) {
app->refcount = 0;
wwin = app->main_window_desc->screen_ptr->focused_window;
while (wwin) {
if (wwin->main_window == window) {
wwin->main_window = None;
}
wwin = wwin->prev;
}
}
wApplicationDestroy(app);
1998-09-29 22:36:29 +00:00
}
}
2004-10-12 21:28:27 +00:00
static void
1998-09-29 22:36:29 +00:00
handleExpose(XEvent *event)
{
WObjDescriptor *desc;
XEvent ev;
1998-09-29 22:36:29 +00:00
1999-10-20 03:25:06 +00:00
#ifdef DEBUG
printf("got expose\n");
1998-09-29 22:36:29 +00:00
#endif
while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
2004-10-12 21:28:27 +00:00
if (XFindContext(dpy, event->xexpose.window, wWinContext,
(XPointer *)&desc)==XCNOENT) {
return;
1998-09-29 22:36:29 +00:00
}
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
if (desc->handle_expose) {
2004-10-12 21:28:27 +00:00
(*desc->handle_expose)(desc, event);
1998-09-29 22:36:29 +00:00
}
}
static void
executeButtonAction(WScreen *scr, XEvent *event, int action)
{
switch(action) {
2004-10-12 21:28:27 +00:00
case WA_SELECT_WINDOWS:
wUnselectWindows(scr);
wSelectWindows(scr, event);
break;
2004-10-12 21:28:27 +00:00
case WA_OPEN_APPMENU:
OpenRootMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
/* ugly hack */
if (scr->root_menu) {
if (scr->root_menu->brother->flags.mapped)
event->xbutton.window = scr->root_menu->brother->frame->core->window;
else
event->xbutton.window = scr->root_menu->frame->core->window;
}
break;
2004-10-12 21:28:27 +00:00
case WA_OPEN_WINLISTMENU:
OpenSwitchMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
if (scr->switch_menu) {
if (scr->switch_menu->brother->flags.mapped)
event->xbutton.window = scr->switch_menu->brother->frame->core->window;
else
event->xbutton.window = scr->switch_menu->frame->core->window;
}
break;
default:
break;
}
}
1998-09-29 22:36:29 +00:00
/* bindable */
static void
handleButtonPress(XEvent *event)
{
WObjDescriptor *desc;
WScreen *scr;
2004-10-12 21:28:27 +00:00
1999-10-20 03:25:06 +00:00
#ifdef DEBUG
printf("got button press\n");
1998-09-29 22:36:29 +00:00
#endif
scr = wScreenForRootWindow(event->xbutton.root);
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
#ifdef BALLOON_TEXT
wBalloonHide(scr);
#endif
2004-10-12 21:28:27 +00:00
1999-01-06 15:22:33 +00:00
#ifndef LITE
2004-10-12 21:28:27 +00:00
if (event->xbutton.window==scr->root_win) {
if (event->xbutton.button==Button1 &&
wPreferences.mouse_button1!=WA_NONE) {
executeButtonAction(scr, event, wPreferences.mouse_button1);
} else if (event->xbutton.button==Button2 &&
wPreferences.mouse_button2!=WA_NONE) {
executeButtonAction(scr, event, wPreferences.mouse_button2);
} else if (event->xbutton.button==Button3 &&
wPreferences.mouse_button3!=WA_NONE) {
executeButtonAction(scr, event, wPreferences.mouse_button3);
} else if (event->xbutton.button==Button4 &&
wPreferences.mouse_wheel!=WA_NONE) {
2004-10-12 21:28:27 +00:00
wWorkspaceRelativeChange(scr, 1);
} else if (event->xbutton.button==Button5 &&
wPreferences.mouse_wheel!=WA_NONE) {
wWorkspaceRelativeChange(scr, -1);
}
1998-11-23 11:32:19 +00:00
}
1999-01-06 15:22:33 +00:00
#endif /* !LITE */
1998-09-29 22:36:29 +00:00
desc = NULL;
1998-11-23 11:32:19 +00:00
if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
2004-10-12 21:28:27 +00:00
(XPointer *)&desc)==XCNOENT) {
if (XFindContext(dpy, event->xbutton.window, wWinContext,
(XPointer *)&desc)==XCNOENT) {
return;
}
1998-09-29 22:36:29 +00:00
}
if (desc->parent_type == WCLASS_WINDOW) {
2004-10-12 21:28:27 +00:00
XSync(dpy, 0);
if (event->xbutton.state & MOD_MASK) {
XAllowEvents(dpy, AsyncPointer, CurrentTime);
}
/* if (wPreferences.focus_mode == WKF_CLICK) {*/
if (wPreferences.ignore_focus_click) {
XAllowEvents(dpy, AsyncPointer, CurrentTime);
}
XAllowEvents(dpy, ReplayPointer, CurrentTime);
/* }*/
XSync(dpy, 0);
1998-09-29 22:36:29 +00:00
} else if (desc->parent_type == WCLASS_APPICON
2004-10-12 21:28:27 +00:00
|| desc->parent_type == WCLASS_MINIWINDOW
|| desc->parent_type == WCLASS_DOCK_ICON) {
if (event->xbutton.state & MOD_MASK) {
XSync(dpy, 0);
XAllowEvents(dpy, AsyncPointer, CurrentTime);
XSync(dpy, 0);
}
1998-09-29 22:36:29 +00:00
}
if (desc->handle_mousedown!=NULL) {
2004-10-12 21:28:27 +00:00
(*desc->handle_mousedown)(desc, event);
}
1998-09-29 22:36:29 +00:00
/* save double-click information */
if (scr->flags.next_click_is_not_double) {
2004-10-12 21:28:27 +00:00
scr->flags.next_click_is_not_double = 0;
1998-09-29 22:36:29 +00:00
} else {
2004-10-12 21:28:27 +00:00
scr->last_click_time = event->xbutton.time;
scr->last_click_button = event->xbutton.button;
scr->last_click_window = event->xbutton.window;
1998-09-29 22:36:29 +00:00
}
}
static void
handleMapNotify(XEvent *event)
1998-09-29 22:36:29 +00:00
{
WWindow *wwin;
#ifdef DEBUG
printf("got map\n");
1998-09-29 22:36:29 +00:00
#endif
wwin = wWindowFor(event->xmap.event);
if (wwin && wwin->client_win == event->xmap.event) {
2004-10-12 21:28:27 +00:00
if (wwin->flags.miniaturized) {
wDeiconifyWindow(wwin);
} else {
XGrabServer(dpy);
wWindowMap(wwin);
wClientSetState(wwin, NormalState, None);
XUngrabServer(dpy);
}
1998-09-29 22:36:29 +00:00
}
}
static void
handleUnmapNotify(XEvent *event)
{
WWindow *wwin;
XEvent ev;
Bool withdraw = False;
1998-09-29 22:36:29 +00:00
#ifdef DEBUG
printf("got unmap\n");
1998-09-29 22:36:29 +00:00
#endif
2004-10-12 21:28:27 +00:00
/* only process windows with StructureNotify selected
* (ignore SubstructureNotify) */
1998-09-29 22:36:29 +00:00
wwin = wWindowFor(event->xunmap.window);
if (!wwin)
2004-10-12 21:28:27 +00:00
return;
/* whether the event is a Withdrawal request */
if (event->xunmap.event == wwin->screen_ptr->root_win
2004-10-12 21:28:27 +00:00
&& event->xunmap.send_event)
withdraw = True;
if (wwin->client_win != event->xunmap.event && !withdraw)
2004-10-12 21:28:27 +00:00
return;
1998-09-29 22:36:29 +00:00
if (!wwin->flags.mapped && !withdraw
2004-10-12 21:28:27 +00:00
&& wwin->frame->workspace == wwin->screen_ptr->current_workspace
&& !wwin->flags.miniaturized && !wwin->flags.hidden)
return;
1998-09-29 22:36:29 +00:00
XGrabServer(dpy);
XUnmapWindow(dpy, wwin->frame->core->window);
wwin->flags.mapped = 0;
XSync(dpy, 0);
/* check if the window was destroyed */
if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
2004-10-12 21:28:27 +00:00
DispatchEvent(&ev);
1998-09-29 22:36:29 +00:00
} else {
2004-10-12 21:28:27 +00:00
Bool reparented = False;
if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
reparented = True;
/* withdraw window */
wwin->flags.mapped = 0;
if (!reparented)
wClientSetState(wwin, WithdrawnState, None);
/* if the window was reparented, do not reparent it back to the
* root window */
wUnmanageWindow(wwin, !reparented, False);
1998-09-29 22:36:29 +00:00
}
XUngrabServer(dpy);
}
static void
handleConfigureRequest(XEvent *event)
{
WWindow *wwin;
#ifdef DEBUG
printf("got configure request\n");
1998-09-29 22:36:29 +00:00
#endif
if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
2004-10-12 21:28:27 +00:00
/*
* Configure request for unmapped window
*/
wClientConfigure(NULL, &(event->xconfigurerequest));
1998-09-29 22:36:29 +00:00
} else {
2004-10-12 21:28:27 +00:00
wClientConfigure(wwin, &(event->xconfigurerequest));
1998-09-29 22:36:29 +00:00
}
}
static void
handlePropertyNotify(XEvent *event)
{
WWindow *wwin;
WApplication *wapp;
Window jr;
int ji;
unsigned int ju;
1999-01-06 15:22:33 +00:00
WScreen *scr;
1998-09-29 22:36:29 +00:00
#ifdef DEBUG
printf("got property notify\n");
1998-09-29 22:36:29 +00:00
#endif
2009-08-08 23:37:27 +02:00
wwin = wWindowFor(event->xproperty.window);
if (wwin) {
2004-10-12 21:28:27 +00:00
if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
&ju, &ju, &ju, &ju)) {
return;
}
wClientCheckProperty(wwin, &event->xproperty);
1998-09-29 22:36:29 +00:00
}
wapp = wApplicationOf(event->xproperty.window);
if (wapp) {
2004-10-12 21:28:27 +00:00
wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
1998-09-29 22:36:29 +00:00
}
2004-10-12 21:28:27 +00:00
1999-01-25 19:06:50 +00:00
scr = wScreenForWindow(event->xproperty.window);
1998-09-29 22:36:29 +00:00
}
static void
handleClientMessage(XEvent *event)
{
WWindow *wwin;
WObjDescriptor *desc;
#ifdef DEBUG
printf("got client message\n");
1998-09-29 22:36:29 +00:00
#endif
/* handle transition from Normal to Iconic state */
if (event->xclient.message_type == _XA_WM_CHANGE_STATE
2004-10-12 21:28:27 +00:00
&& event->xclient.format == 32
&& event->xclient.data.l[0] == IconicState) {
wwin = wWindowFor(event->xclient.window);
if (!wwin) return;
if (!wwin->flags.miniaturized)
wIconifyWindow(wwin);
1998-11-03 12:53:26 +00:00
} else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
2004-10-12 21:28:27 +00:00
&& event->xclient.format == 32) {
WScreen *scr = wScreenSearchForRootWindow(event->xclient.window);
1998-11-03 12:53:26 +00:00
2004-10-12 21:28:27 +00:00
if (!scr)
return;
1998-11-03 12:53:26 +00:00
2004-10-12 21:28:27 +00:00
if (event->xclient.data.l[1] == 1) { /* starting */
wColormapAllowClientInstallation(scr, True);
} else { /* stopping */
wColormapAllowClientInstallation(scr, False);
}
1999-04-03 03:51:17 +00:00
} else if (event->xclient.message_type == _XA_WINDOWMAKER_COMMAND) {
2004-10-12 21:28:27 +00:00
wDefaultsCheckDomains("bla");
1999-04-03 03:51:17 +00:00
1998-09-29 22:36:29 +00:00
} else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
2004-10-12 21:28:27 +00:00
WApplication *wapp;
int done=0;
wapp = wApplicationOf(event->xclient.window);
if (wapp) {
switch (event->xclient.data.l[0]) {
case WMFHideOtherApplications:
wHideOtherApplications(wapp->main_window_desc);
done = 1;
break;
case WMFHideApplication:
wHideApplication(wapp);
done = 1;
break;
}
}
if (!done) {
wwin = wWindowFor(event->xclient.window);
if (wwin) {
switch (event->xclient.data.l[0]) {
case WMFHideOtherApplications:
wHideOtherApplications(wwin);
break;
case WMFHideApplication:
wHideApplication(wApplicationOf(wwin->main_window));
break;
}
}
}
} else if (event->xclient.message_type == _XA_GNUSTEP_WM_ATTR) {
2004-10-12 21:28:27 +00:00
wwin = wWindowFor(event->xclient.window);
if (!wwin) return;
switch (event->xclient.data.l[0]) {
case GSWindowLevelAttr:
{
int level = (int)event->xclient.data.l[1];
if (WINDOW_LEVEL(wwin) != level) {
ChangeStackingLevel(wwin->frame->core, level);
}
}
break;
}
} else if (event->xclient.message_type == _XA_GNUSTEP_TITLEBAR_STATE) {
2004-10-12 21:28:27 +00:00
wwin = wWindowFor(event->xclient.window);
if (!wwin) return;
switch (event->xclient.data.l[0]) {
case WMTitleBarNormal:
wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
break;
case WMTitleBarMain:
wFrameWindowChangeState(wwin->frame, WS_PFOCUSED);
break;
case WMTitleBarKey:
wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
break;
}
#ifdef NETWM_HINTS
} else if (wNETWMProcessClientMessage(&event->xclient)) {
2004-10-12 21:28:27 +00:00
/* do nothing */
#endif
1999-05-17 20:21:43 +00:00
#ifdef XDND
} else if (wXDNDProcessClientMessage(&event->xclient)) {
2004-10-12 21:28:27 +00:00
/* do nothing */
1999-05-17 20:21:43 +00:00
#endif /* XDND */
1998-09-29 22:36:29 +00:00
} else {
2004-10-12 21:28:27 +00:00
/*
* Non-standard thing, but needed by OffiX DND.
* For when the icon frame gets a ClientMessage
* that should have gone to the icon_window.
*/
if (XFindContext(dpy, event->xbutton.window, wWinContext,
(XPointer *)&desc)!=XCNOENT) {
struct WIcon *icon=NULL;
if (desc->parent_type == WCLASS_MINIWINDOW) {
icon = (WIcon*)desc->parent;
} else if (desc->parent_type == WCLASS_DOCK_ICON
|| desc->parent_type == WCLASS_APPICON) {
icon = ((WAppIcon*)desc->parent)->icon;
}
if (icon && (wwin=icon->owner)) {
if (wwin->client_win!=event->xclient.window) {
event->xclient.window = wwin->client_win;
XSendEvent(dpy, wwin->client_win, False, NoEventMask,
event);
}
}
}
1998-09-29 22:36:29 +00:00
}
}
static void
raiseWindow(WScreen *scr)
{
WWindow *wwin;
scr->autoRaiseTimer = NULL;
2004-10-12 21:28:27 +00:00
wwin = wWindowFor(scr->autoRaiseWindow);
1998-09-29 22:36:29 +00:00
if (!wwin)
2004-10-12 21:28:27 +00:00
return;
1998-09-29 22:36:29 +00:00
if (!wwin->flags.destroyed && wwin->flags.focused) {
2004-10-12 21:28:27 +00:00
wRaiseFrame(wwin->frame->core);
/* this is needed or a race condition will occur */
XSync(dpy, False);
1998-09-29 22:36:29 +00:00
}
}
2004-10-12 21:28:27 +00:00
static void
1998-09-29 22:36:29 +00:00
handleEnterNotify(XEvent *event)
{
WWindow *wwin;
WObjDescriptor *desc = NULL;
#ifdef VIRTUAL_DESKTOP
void (*vdHandler)(XEvent * event);
#endif
1998-09-29 22:36:29 +00:00
XEvent ev;
WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
#ifdef DEBUG
printf("got enter notify\n");
1998-09-29 22:36:29 +00:00
#endif
1999-12-18 11:52:49 +00:00
#ifdef VIRTUAL_DESKTOP
if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext,
(XPointer *)&vdHandler)!=XCNOENT) {
(*vdHandler)(event);
1999-12-18 11:52:49 +00:00
}
#endif
1998-09-29 22:36:29 +00:00
if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
2004-10-12 21:28:27 +00:00
&ev)) {
/* already left the window... */
saveTimestamp(&ev);
if (ev.xcrossing.mode==event->xcrossing.mode
&& ev.xcrossing.detail==event->xcrossing.detail) {
return;
}
1998-09-29 22:36:29 +00:00
}
if (XFindContext(dpy, event->xcrossing.window, wWinContext,
(XPointer *)&desc)!=XCNOENT) {
if(desc->handle_enternotify)
(*desc->handle_enternotify)(desc, event);
}
/* enter to window */
wwin = wWindowFor(event->xcrossing.window);
if (!wwin) {
2004-10-12 21:28:27 +00:00
if (wPreferences.colormap_mode==WCM_POINTER) {
wColormapInstallForWindow(scr, NULL);
}
if (scr->autoRaiseTimer
&& event->xcrossing.root==event->xcrossing.window) {
WMDeleteTimerHandler(scr->autoRaiseTimer);
scr->autoRaiseTimer = NULL;
}
1998-09-29 22:36:29 +00:00
} else {
2004-10-12 21:28:27 +00:00
/* set auto raise timer even if in focus-follows-mouse mode
* and the event is for the frame window, even if the window
* has focus already. useful if you move the pointer from a focused
* window to the root window and back pretty fast
*
* set focus if in focus-follows-mouse mode and the event
* is for the frame window and window doesn't have focus yet */
if (wPreferences.focus_mode==WKF_SLOPPY
&& wwin->frame->core->window==event->xcrossing.window
&& !scr->flags.doing_alt_tab) {
if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable))
wSetFocusTo(scr, wwin);
if (scr->autoRaiseTimer)
WMDeleteTimerHandler(scr->autoRaiseTimer);
scr->autoRaiseTimer = NULL;
if (wPreferences.raise_delay && !WFLAGP(wwin, no_focusable)) {
scr->autoRaiseWindow = wwin->frame->core->window;
scr->autoRaiseTimer
= WMAddTimerHandler(wPreferences.raise_delay,
(WMCallback*)raiseWindow, scr);
}
}
/* Install colormap for window, if the colormap installation mode
* is colormap_follows_mouse */
if (wPreferences.colormap_mode==WCM_POINTER) {
if (wwin->client_win==event->xcrossing.window)
wColormapInstallForWindow(scr, wwin);
else
wColormapInstallForWindow(scr, NULL);
}
1998-09-29 22:36:29 +00:00
}
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
/* a little kluge to hide the clip balloon */
if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
2004-10-12 21:28:27 +00:00
if (!desc) {
XUnmapWindow(dpy, scr->clip_balloon);
scr->flags.clip_balloon_mapped = 0;
} else {
if (desc->parent_type!=WCLASS_DOCK_ICON
|| scr->clip_icon != desc->parent) {
XUnmapWindow(dpy, scr->clip_balloon);
scr->flags.clip_balloon_mapped = 0;
}
}
1998-09-29 22:36:29 +00:00
}
if (event->xcrossing.window == event->xcrossing.root
2004-10-12 21:28:27 +00:00
&& event->xcrossing.detail == NotifyNormal
&& event->xcrossing.detail != NotifyInferior
&& wPreferences.focus_mode != WKF_CLICK) {
wSetFocusTo(scr, scr->focused_window);
1998-09-29 22:36:29 +00:00
}
#ifdef BALLOON_TEXT
wBalloonEnteredObject(scr, desc);
#endif
}
static void
handleLeaveNotify(XEvent *event)
{
WObjDescriptor *desc = NULL;
2000-01-20 11:51:42 +00:00
2004-10-12 21:28:27 +00:00
if (XFindContext(dpy, event->xcrossing.window, wWinContext,
(XPointer *)&desc)!=XCNOENT) {
1998-09-29 22:36:29 +00:00
if(desc->handle_leavenotify)
2004-10-12 21:28:27 +00:00
(*desc->handle_leavenotify)(desc, event);
1998-09-29 22:36:29 +00:00
}
}
#ifdef SHAPE
static void
handleShapeNotify(XEvent *event)
{
XShapeEvent *shev = (XShapeEvent*)event;
WWindow *wwin;
1998-10-21 14:43:47 +00:00
XEvent ev;
1999-10-21 00:54:37 +00:00
#ifdef DEBUG
printf("got shape notify\n");
1998-09-29 22:36:29 +00:00
#endif
1998-10-21 14:43:47 +00:00
while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
2004-10-12 21:28:27 +00:00
XShapeEvent *sev = (XShapeEvent*)&ev;
if (sev->kind == ShapeBounding) {
if (sev->shaped == shev->shaped) {
*shev = *sev;
} else {
XPutBackEvent(dpy, &ev);
break;
}
}
1998-10-21 14:43:47 +00:00
}
wwin = wWindowFor(shev->window);
1998-09-29 22:36:29 +00:00
if (!wwin || shev->kind != ShapeBounding)
2004-10-12 21:28:27 +00:00
return;
1998-10-21 14:43:47 +00:00
if (!shev->shaped && wwin->flags.shaped) {
2004-10-12 21:28:27 +00:00
wwin->flags.shaped = 0;
wWindowClearShape(wwin);
1998-10-21 14:43:47 +00:00
} else if (shev->shaped) {
2004-10-12 21:28:27 +00:00
wwin->flags.shaped = 1;
wWindowSetShape(wwin);
1998-10-21 14:43:47 +00:00
}
1998-09-29 22:36:29 +00:00
}
#endif /* SHAPE */
2004-10-12 21:28:27 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
/* please help ]d if you know what to do */
handleXkbIndicatorStateNotify(XEvent *event)
{
WWindow *wwin;
WScreen *scr;
XkbStateRec staterec;
int i;
for (i=0; i<wScreenCount; i++) {
scr = wScreenWithNumber(i);
2004-10-12 21:28:27 +00:00
wwin = scr->focused_window;
if (wwin && wwin->flags.focused) {
XkbGetState(dpy,XkbUseCoreKbd,&staterec);
if (wwin->frame->languagemode != staterec.group) {
wwin->frame->last_languagemode = wwin->frame->languagemode;
wwin->frame->languagemode = staterec.group;
}
1999-05-20 23:30:53 +00:00
#ifdef XKB_BUTTON_HINT
2004-10-12 21:28:27 +00:00
if (wwin->frame->titlebar) {
wFrameWindowPaint(wwin->frame);
}
1999-05-20 23:30:53 +00:00
#endif
2004-10-12 21:28:27 +00:00
}
}
}
#endif /*KEEP_XKB_LOCK_STATUS*/
1998-09-29 22:36:29 +00:00
2004-10-12 21:28:27 +00:00
static void
1998-09-29 22:36:29 +00:00
handleColormapNotify(XEvent *event)
{
WWindow *wwin;
WScreen *scr;
Bool reinstall = False;
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
wwin = wWindowFor(event->xcolormap.window);
if (!wwin)
2004-10-12 21:28:27 +00:00
return;
1998-09-29 22:36:29 +00:00
scr = wwin->screen_ptr;
do {
2004-10-12 21:28:27 +00:00
if (wwin) {
if (event->xcolormap.new) {
XWindowAttributes attr;
XGetWindowAttributes(dpy, wwin->client_win, &attr);
if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
scr->current_colormap = attr.colormap;
reinstall = True;
} else if (event->xcolormap.state == ColormapUninstalled &&
scr->current_colormap == event->xcolormap.colormap) {
/* some bastard app (like XV) removed our colormap */
/*
* can't enforce or things like xscreensaver wont work
* reinstall = True;
*/
} else if (event->xcolormap.state == ColormapInstalled &&
scr->current_colormap == event->xcolormap.colormap) {
/* someone has put our colormap back */
reinstall = False;
}
}
1998-09-29 22:36:29 +00:00
} while (XCheckTypedEvent(dpy, ColormapNotify, event)
2004-10-12 21:28:27 +00:00
&& ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1998-09-29 22:36:29 +00:00
if (reinstall && scr->current_colormap!=None) {
2004-10-12 21:28:27 +00:00
if (!scr->flags.colormap_stuff_blocked)
XInstallColormap(dpy, scr->current_colormap);
1998-09-29 22:36:29 +00:00
}
}
static void
handleFocusIn(XEvent *event)
{
WWindow *wwin;
/*
* For applications that like stealing the focus.
*/
2004-10-12 21:28:27 +00:00
while (XCheckTypedEvent(dpy, FocusIn, event));
1998-09-29 22:36:29 +00:00
saveTimestamp(event);
1998-10-21 14:43:47 +00:00
if (event->xfocus.mode == NotifyUngrab
2004-10-12 21:28:27 +00:00
|| event->xfocus.mode == NotifyGrab
|| event->xfocus.detail > NotifyNonlinearVirtual) {
return;
1998-09-29 22:36:29 +00:00
}
wwin = wWindowFor(event->xfocus.window);
if (wwin && !wwin->flags.focused) {
2004-10-12 21:28:27 +00:00
if (wwin->flags.mapped)
wSetFocusTo(wwin->screen_ptr, wwin);
else
wSetFocusTo(wwin->screen_ptr, NULL);
1998-09-29 22:36:29 +00:00
} else if (!wwin) {
2004-10-12 21:28:27 +00:00
WScreen *scr = wScreenForWindow(event->xfocus.window);
if (scr)
wSetFocusTo(scr, NULL);
1998-09-29 22:36:29 +00:00
}
}
static WWindow*
windowUnderPointer(WScreen *scr)
{
unsigned int mask;
int foo;
Window bar, win;
2004-10-12 21:28:27 +00:00
1998-09-29 22:36:29 +00:00
if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
2004-10-12 21:28:27 +00:00
&mask))
return wWindowFor(win);
1998-09-29 22:36:29 +00:00
return NULL;
}
1999-09-16 02:58:56 +00:00
static int CheckFullScreenWindowFocused(WScreen *scr)
{
if (scr->focused_window && scr->focused_window->flags.fullscreen)
return 1;
else
return 0;
}
1999-09-16 02:58:56 +00:00
1998-09-29 22:36:29 +00:00
static void
handleKeyPress(XEvent *event)
{
WScreen *scr = wScreenForRootWindow(event->xkey.root);
WWindow *wwin = scr->focused_window;
int i;
int modifiers;
1999-09-16 02:58:56 +00:00
int command=-1, index;
2004-10-12 21:28:27 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
XkbStateRec staterec;
1998-11-03 12:53:26 +00:00
#endif /*KEEP_XKB_LOCK_STATUS*/
1998-09-29 22:36:29 +00:00
/* ignore CapsLock */
modifiers = event->xkey.state & ValidModMask;
for (i=0; i<WKBD_LAST; i++) {
2004-10-12 21:28:27 +00:00
if (wKeyBindings[i].keycode==0)
continue;
if (wKeyBindings[i].keycode==event->xkey.keycode
&& (/*wKeyBindings[i].modifier==0
||*/ wKeyBindings[i].modifier==modifiers)) {
command = i;
break;
}
1998-09-29 22:36:29 +00:00
}
1998-09-29 22:36:29 +00:00
if (command < 0) {
1999-01-06 15:22:33 +00:00
#ifdef LITE
2004-10-12 21:28:27 +00:00
{
1999-01-06 15:22:33 +00:00
#if 0
2004-10-12 21:28:27 +00:00
}
1999-01-06 15:22:33 +00:00
#endif
#else
2004-10-12 21:28:27 +00:00
if (!wRootMenuPerformShortcut(event)) {
1999-01-06 15:22:33 +00:00
#endif
2004-10-12 21:28:27 +00:00
static int dontLoop = 0;
if (dontLoop > 10) {
wwarning("problem with key event processing code");
return;
}
dontLoop++;
/* if the focused window is an internal window, try redispatching
* the event to the managed window, as it can be a WINGs window */
if (wwin && wwin->flags.internal_window
&& wwin->client_leader!=None) {
/* client_leader contains the WINGs toplevel */
event->xany.window = wwin->client_leader;
WMHandleEvent(event);
}
dontLoop--;
}
return;
1998-09-29 22:36:29 +00:00
}
#define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
#define ISFOCUSED(w) ((w) && (w)->flags.focused)
switch (command) {
1999-01-06 15:22:33 +00:00
#ifndef LITE
2004-10-12 21:28:27 +00:00
case WKBD_ROOTMENU:
/*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
if (!CheckFullScreenWindowFocused(scr)) {
2004-10-12 21:28:27 +00:00
WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
OpenRootMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
2004-10-12 21:28:27 +00:00
}
break;
2004-10-12 21:28:27 +00:00
case WKBD_WINDOWLIST:
if (!CheckFullScreenWindowFocused(scr)) {
2004-10-12 21:28:27 +00:00
WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
OpenSwitchMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
2004-10-12 21:28:27 +00:00
}
break;
1999-01-06 15:22:33 +00:00
#endif /* !LITE */
2004-10-12 21:28:27 +00:00
case WKBD_WINDOWMENU:
if (ISMAPPED(wwin) && ISFOCUSED(wwin))
OpenWindowMenu(wwin, wwin->frame_x,
wwin->frame_y+wwin->frame->top_width, True);
break;
case WKBD_MINIATURIZE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin)
&& !WFLAGP(wwin, no_miniaturizable)) {
CloseWindowMenu(scr);
if (wwin->protocols.MINIATURIZE_WINDOW)
wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
event->xbutton.time);
else {
wIconifyWindow(wwin);
}
}
break;
case WKBD_HIDE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
WApplication *wapp = wApplicationOf(wwin->main_window);
CloseWindowMenu(scr);
if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
wHideApplication(wapp);
}
}
break;
case WKBD_HIDE_OTHERS:
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
CloseWindowMenu(scr);
2002-01-04 05:44:20 +00:00
wHideOtherApplications(wwin);
2004-10-12 21:28:27 +00:00
}
break;
case WKBD_MAXIMIZE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
int newdir = (MAX_VERTICAL|MAX_HORIZONTAL);
CloseWindowMenu(scr);
2004-10-12 21:28:27 +00:00
if (wwin->flags.maximized == newdir) {
wUnmaximizeWindow(wwin);
} else {
2004-10-12 21:28:27 +00:00
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
}
}
break;
case WKBD_VMAXIMIZE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
int newdir = (MAX_VERTICAL ^ wwin->flags.maximized);
2004-10-12 21:28:27 +00:00
CloseWindowMenu(scr);
if (newdir) {
2004-10-12 21:28:27 +00:00
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
} else {
wUnmaximizeWindow(wwin);
}
2004-10-12 21:28:27 +00:00
}
break;
case WKBD_HMAXIMIZE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized);
2004-10-12 21:28:27 +00:00
CloseWindowMenu(scr);
if (newdir) {
2004-10-12 21:28:27 +00:00
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
} else {
wUnmaximizeWindow(wwin);
}
2004-10-12 21:28:27 +00:00
}
break;
case WKBD_RAISE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
CloseWindowMenu(scr);
wRaiseFrame(wwin->frame->core);
}
break;
case WKBD_LOWER:
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
CloseWindowMenu(scr);
wLowerFrame(wwin->frame->core);
}
break;
case WKBD_RAISELOWER:
/* raise or lower the window under the pointer, not the
* focused one
*/
wwin = windowUnderPointer(scr);
if (wwin)
wRaiseLowerFrame(wwin->frame->core);
break;
case WKBD_SHADE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
if (wwin->flags.shaded)
wUnshadeWindow(wwin);
else
wShadeWindow(wwin);
}
break;
case WKBD_MOVERESIZE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) &&
(IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) {
CloseWindowMenu(scr);
wKeyboardMoveResizeWindow(wwin);
}
break;
case WKBD_CLOSE:
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
CloseWindowMenu(scr);
if (wwin->protocols.DELETE_WINDOW)
wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
event->xkey.time);
}
break;
1998-09-29 22:36:29 +00:00
case WKBD_SELECT:
2004-10-12 21:28:27 +00:00
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
wSelectWindow(wwin, !wwin->flags.selected);
}
break;
case WKBD_FOCUSNEXT:
StartWindozeCycle(wwin, event, True);
1998-09-29 22:36:29 +00:00
break;
2004-10-12 21:28:27 +00:00
case WKBD_FOCUSPREV:
StartWindozeCycle(wwin, event, False);
break;
1998-10-21 14:43:47 +00:00
#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
#define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
2004-10-12 21:28:27 +00:00
i = (scr->current_workspace/10)*10 + wk - 1;\
if (wPreferences.ws_advance || i<scr->workspace_count)\
wWorkspaceChange(scr, i);\
break
1998-10-21 14:43:47 +00:00
#else
#define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
2004-10-12 21:28:27 +00:00
i = (scr->current_workspace/10)*10 + wk - 1;\
if (wPreferences.ws_advance || i<scr->workspace_count)\
wWorkspaceChange(scr, i);\
break
1998-10-21 14:43:47 +00:00
#endif
2004-10-12 21:28:27 +00:00
GOTOWORKS(1);
GOTOWORKS(2);
GOTOWORKS(3);
GOTOWORKS(4);
GOTOWORKS(5);
GOTOWORKS(6);
GOTOWORKS(7);
GOTOWORKS(8);
GOTOWORKS(9);
GOTOWORKS(10);
1998-10-21 14:43:47 +00:00
#undef GOTOWORKS
2004-10-12 21:28:27 +00:00
case WKBD_NEXTWORKSPACE:
wWorkspaceRelativeChange(scr, 1);
break;
case WKBD_PREVWORKSPACE:
wWorkspaceRelativeChange(scr, -1);
break;
case WKBD_WINDOW1:
case WKBD_WINDOW2:
case WKBD_WINDOW3:
case WKBD_WINDOW4:
case WKBD_WINDOW5:
case WKBD_WINDOW6:
case WKBD_WINDOW7:
case WKBD_WINDOW8:
case WKBD_WINDOW9:
case WKBD_WINDOW10:
index = command-WKBD_WINDOW1;
if (scr->shortcutWindows[index]) {
WMArray *list = scr->shortcutWindows[index];
int cw;
2004-10-12 21:28:27 +00:00
int count = WMGetArrayItemCount(list);
WWindow *twin;
WMArrayIterator iter;
WWindow *wwin;
wUnselectWindows(scr);
cw = scr->current_workspace;
WM_ETARETI_ARRAY(list, wwin, iter) {
2004-10-12 21:28:27 +00:00
if (count > 1)
wWindowChangeWorkspace(wwin, cw);
1999-09-16 02:58:56 +00:00
wMakeWindowVisible(wwin);
1999-05-14 04:30:01 +00:00
2004-10-12 21:28:27 +00:00
if (count > 1)
wSelectWindow(wwin, True);
}
2004-10-12 21:28:27 +00:00
/* rotate the order of windows, to create a cycling effect */
twin = WMGetFromArray(list, 0);
WMDeleteFromArray(list, 0);
WMAddToArray(list, twin);
1999-05-14 04:30:01 +00:00
1998-11-03 12:53:26 +00:00
} else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
if (scr->shortcutWindows[index]) {
WMFreeArray(scr->shortcutWindows[index]);
scr->shortcutWindows[index] = NULL;
}
1999-09-16 02:58:56 +00:00
if (wwin->flags.selected && scr->selected_windows) {
scr->shortcutWindows[index] =
WMDuplicateArray(scr->selected_windows);
/*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
2004-10-12 21:28:27 +00:00
WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
} else {
scr->shortcutWindows[index] = WMCreateArray(4);
WMAddToArray(scr->shortcutWindows[index], wwin);
}
wSelectWindow(wwin, !wwin->flags.selected);
XFlush(dpy);
wusleep(3000);
wSelectWindow(wwin, !wwin->flags.selected);
XFlush(dpy);
1999-05-14 04:30:01 +00:00
2004-10-12 21:28:27 +00:00
} else if (scr->selected_windows
&& WMGetArrayItemCount(scr->selected_windows)) {
1999-09-16 02:58:56 +00:00
if (wwin->flags.selected && scr->selected_windows) {
if (scr->shortcutWindows[index]) {
WMFreeArray(scr->shortcutWindows[index]);
}
scr->shortcutWindows[index] =
WMDuplicateArray(scr->selected_windows);
}
1998-11-03 12:53:26 +00:00
}
1998-11-03 12:53:26 +00:00
break;
2004-10-12 21:28:27 +00:00
case WKBD_SWITCH_SCREEN:
if (wScreenCount > 1) {
WScreen *scr2;
int i;
/* find index of this screen */
for (i = 0; i < wScreenCount; i++) {
if (wScreenWithNumber(i) == scr)
break;
}
i++;
if (i >= wScreenCount) {
i = 0;
}
scr2 = wScreenWithNumber(i);
if (scr2) {
XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
scr2->scr_width/2, scr2->scr_height/2);
}
}
break;
case WKBD_NEXTWSLAYER:
case WKBD_PREVWSLAYER:
{
int row, column;
row = scr->current_workspace/10;
column = scr->current_workspace%10;
if (command==WKBD_NEXTWSLAYER) {
if ((row+1)*10 < scr->workspace_count)
wWorkspaceChange(scr, column+(row+1)*10);
} else {
if (row > 0)
wWorkspaceChange(scr, column+(row-1)*10);
}
}
break;
1998-09-29 22:36:29 +00:00
case WKBD_CLIPLOWER:
if (!wPreferences.flags.noclip)
wDockLower(scr->workspaces[scr->current_workspace]->clip);
break;
2004-10-12 21:28:27 +00:00
case WKBD_CLIPRAISE:
1998-09-29 22:36:29 +00:00
if (!wPreferences.flags.noclip)
wDockRaise(scr->workspaces[scr->current_workspace]->clip);
break;
2004-10-12 21:28:27 +00:00
case WKBD_CLIPRAISELOWER:
1998-09-29 22:36:29 +00:00
if (!wPreferences.flags.noclip)
wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
break;
1998-11-03 12:53:26 +00:00
#ifdef KEEP_XKB_LOCK_STATUS
2004-10-12 21:28:27 +00:00
case WKBD_TOGGLE:
1999-04-10 18:27:21 +00:00
if(wPreferences.modelock) {
/*toggle*/
wwin = scr->focused_window;
if (wwin && wwin->flags.mapped
&& wwin->frame->workspace == wwin->screen_ptr->current_workspace
&& !wwin->flags.miniaturized && !wwin->flags.hidden) {
1999-05-22 21:30:35 +00:00
XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1999-04-10 18:27:21 +00:00
1999-05-22 21:30:35 +00:00
wwin->frame->languagemode = wwin->frame->last_languagemode;
wwin->frame->last_languagemode = staterec.group;
XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
2004-10-12 21:28:27 +00:00
1999-04-10 18:27:21 +00:00
}
1998-11-03 12:53:26 +00:00
}
break;
#endif /* KEEP_XKB_LOCK_STATUS */
#ifdef VIRTUAL_DESKTOP
2004-10-12 21:28:27 +00:00
case WKBD_VDESK_LEFT:
wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT);
break;
2004-10-12 21:28:27 +00:00
case WKBD_VDESK_RIGHT:
wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT);
break;
2004-10-12 21:28:27 +00:00
case WKBD_VDESK_UP:
wWorkspaceKeyboardMoveDesktop(scr, VEC_UP);
break;
2004-10-12 21:28:27 +00:00
case WKBD_VDESK_DOWN:
wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN);
break;
#endif
1998-11-03 12:53:26 +00:00
1998-09-29 22:36:29 +00:00
}
}
2004-10-12 21:28:27 +00:00
static void
1998-09-29 22:36:29 +00:00
handleMotionNotify(XEvent *event)
{
WScreen *scr = wScreenForRootWindow(event->xmotion.root);
if (wPreferences.scrollable_menus) {
2003-07-16 20:58:49 +00:00
WMPoint p = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
WMRect rect = wGetRectForHead(scr, wGetHeadForPoint(scr, p));
2004-10-12 21:28:27 +00:00
if (scr->flags.jump_back_pending ||
p.x <= (rect.pos.x + 1) ||
p.x >= (rect.pos.x + rect.size.width - 2) ||
p.y <= (rect.pos.y + 1) ||
p.y >= (rect.pos.y + rect.size.height - 2)) {
WMenu *menu;
1998-09-29 22:36:29 +00:00
#ifdef DEBUG
printf("pointer at screen edge\n");
1998-09-29 22:36:29 +00:00
#endif
menu = wMenuUnderPointer(scr);
if (menu!=NULL)
wMenuScroll(menu, event);
}
}
}
1999-01-25 19:06:50 +00:00
static void
handleVisibilityNotify(XEvent *event)
{
WWindow *wwin;
wwin = wWindowFor(event->xvisibility.window);
if (!wwin)
2004-10-12 21:28:27 +00:00
return;
wwin->flags.obscured =
(event->xvisibility.state == VisibilityFullyObscured);
}
2004-10-12 21:28:27 +00:00