Skip to content
Snippets Groups Projects
events.c 54.6 KiB
Newer Older
Olivier Fourdan's avatar
Olivier Fourdan committed
/*
        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; You may only use version 2 of the License,
        you have no option to use any other 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
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Olivier Fourdan's avatar
Olivier Fourdan committed
        oroborus - (c) 2001 Ken Lynch
        xfwm4    - (c) 2002-2003 Olivier Fourdan
Olivier Fourdan's avatar
Olivier Fourdan committed
 */

#ifdef HAVE_CONFIG_H
Olivier Fourdan's avatar
Olivier Fourdan committed
#endif

#include <X11/Xlib.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <gtk/gtk.h>
#include <gdk/gdk.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <gdk/gdkx.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <libxfce4util/i18n.h>
#include <libxfcegui4/libxfcegui4.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "main.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "misc.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "workspaces.h"
#include "settings.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "mywindow.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "frame.h"
#include "client.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "events.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "menu.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "hints.h"
#include "startup_notification.h"
Olivier Fourdan's avatar
Olivier Fourdan committed

#define WIN_IS_BUTTON(win)      ((win == MYWINDOW_XWINDOW(c->buttons[HIDE_BUTTON])) || \
                                 (win == MYWINDOW_XWINDOW(c->buttons[CLOSE_BUTTON])) || \
                                 (win == MYWINDOW_XWINDOW(c->buttons[MAXIMIZE_BUTTON])) || \
                                 (win == MYWINDOW_XWINDOW(c->buttons[SHADE_BUTTON])) || \
                                 (win == MYWINDOW_XWINDOW(c->buttons[STICK_BUTTON])))

#define DBL_CLICK_GRAB          (ButtonMotionMask | \
                                 PointerMotionMask | \
                                 PointerMotionHintMask | \
                                 ButtonPressMask | \
                                 ButtonReleaseMask)
                                 
#define MODIFIER_MASK           (ShiftMask | \
                                 ControlMask | \
                                 AltMask | \
                                 MetaMask | \
                                 SuperMask | \
                                 HyperMask)
Olivier Fourdan's avatar
Olivier Fourdan committed
static guint raise_timeout = 0;
static gulong button_handler_id = 0;
static GdkAtom atom_rcfiles = GDK_NONE;
static Window menu_event_window = None;
Olivier Fourdan's avatar
Olivier Fourdan committed

static void menu_callback (Menu * menu, MenuOp op, Window client_xwindow,
    gpointer menu_data, gpointer item_data);
static gboolean show_popup_cb (GtkWidget * widget, GdkEventButton * ev,
static gboolean client_event_cb (GtkWidget * widget, GdkEventClient * ev);
Olivier Fourdan's avatar
Olivier Fourdan committed

typedef enum
{
    XFWM_BUTTON_UNDEFINED = 0,
    XFWM_BUTTON_DRAG = 1,
    XFWM_BUTTON_CLICK = 2,
    XFWM_BUTTON_CLICK_AND_DRAG = 3,
    XFWM_BUTTON_DOUBLE_CLICK = 4
}
XfwmButtonClickType;
static inline XfwmButtonClickType
typeOfClick (Window w, XEvent * ev, gboolean allow_double_click)
    unsigned int button;
    g_return_val_if_fail (ev != NULL, XFWM_BUTTON_UNDEFINED);
    g_return_val_if_fail (w != None, XFWM_BUTTON_UNDEFINED);
Olivier Fourdan's avatar
Olivier Fourdan committed
    XFlush (dpy);
    g = XGrabPointer (dpy, w, FALSE, DBL_CLICK_GRAB, GrabModeAsync,
        GrabModeAsync, None, None, ev->xbutton.time);
        TRACE ("grab failed in typeOfClick");
        gdk_beep ();
        return XFWM_BUTTON_UNDEFINED;
    button = ev->xbutton.button;
    x = xcurrent = ev->xbutton.x_root;
    y = ycurrent = ev->xbutton.y_root;
    while ((ABS (x - xcurrent) < 1) && (ABS (y - ycurrent) < 1)
        && (total < params.dbl_click_time)
        && ((t1 - t0) < params.dbl_click_time))
    {
        g_usleep (10000);
        total += 10;
        if (XCheckMaskEvent (dpy, ButtonReleaseMask | ButtonPressMask, ev))
        {
            if (ev->xbutton.button == button)
            {
                clicks++;
            }
            t1 = ev->xbutton.time;
        }
        if (XCheckMaskEvent (dpy,
                ButtonMotionMask | PointerMotionMask | PointerMotionHintMask,
                ev))
        {
            xcurrent = ev->xmotion.x_root;
            ycurrent = ev->xmotion.y_root;
            t1 = ev->xmotion.time;
        }
        if ((XfwmButtonClickType) clicks == XFWM_BUTTON_DOUBLE_CLICK
            || (!allow_double_click
                && (XfwmButtonClickType) clicks == XFWM_BUTTON_CLICK))
        {
            break;
        }
    }
    XUngrabPointer (dpy, ev->xbutton.time);
Olivier Fourdan's avatar
Olivier Fourdan committed
    XFlush (dpy);
static inline void
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        g_source_remove (raise_timeout);
        raise_timeout = 0;
static inline gboolean
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    TRACE ("entering raise_cb");
Olivier Fourdan's avatar
Olivier Fourdan committed

    clear_timeout ();
    c = clientGetFocus ();
    if (c)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    return (TRUE);
}

static inline void
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        g_source_remove (raise_timeout);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
        g_timeout_add_full (0, params.raise_delay, (GtkFunction) raise_cb,
        NULL, NULL);
static inline void
moveRequest (Client * c, XEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (CLIENT_FLAG_TEST_AND_NOT (c, CLIENT_FLAG_HAS_MOVE, CLIENT_FLAG_FULLSCREEN))
static inline void
resizeRequest (Client * c, int corner, XEvent * ev)
    clientSetFocus (c, TRUE, FALSE);
    if (CLIENT_FLAG_TEST_ALL (c,
            CLIENT_FLAG_HAS_RESIZE | CLIENT_FLAG_IS_RESIZABLE))
        clientResize (c, corner, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else if (CLIENT_FLAG_TEST_AND_NOT (c, CLIENT_FLAG_HAS_MOVE, CLIENT_FLAG_FULLSCREEN))
static inline void
spawn_shortcut (int i)
    if ((i >= NB_KEY_SHORTCUTS) || (!params.shortcut_exec[i])
        || !strlen (params.shortcut_exec[i]))
    if (!g_spawn_command_line_async (params.shortcut_exec[i], &error))
        if (error)
        {
            g_warning ("%s: %s", g_get_prgname (), error->message);
            g_error_free (error);
        }
static inline void
handleMotionNotify (XMotionEvent * ev)
    TRACE ("entering handleMotionNotify");

    if (params.workspace_count && params.wrap_workspaces
        && params.wrap_resistance)
    {
        msx = ev->x_root;
        msy = ev->y_root;
        max = MyDisplayFullWidth (dpy, screen) - 1;

        if ((msx == 0) || (msx == max))
        {
            edge_scroll_x++;
        }
        else
        {
            edge_scroll_x = 0;
        }
        if (edge_scroll_x > params.wrap_resistance)
        {
            edge_scroll_x = 0;
            if (msx == 0)
            {
                XWarpPointer (dpy, None, root, 0, 0, 0, 0, max - 10, msy);
                workspaceSwitch (workspace - 1, NULL);
            }
            else if (msx == max)
            {
                XWarpPointer (dpy, None, root, 0, 0, 0, 0, 10, msy);
                workspaceSwitch (workspace + 1, NULL);
            }
            while (XCheckWindowEvent(dpy, ev->window, PointerMotionMask, (XEvent *) ev))
static inline void
handleKeyPress (XKeyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    int state, key;

    TRACE ("entering handleKeyEvent");

    c = clientGetFocus ();
    state = ev->state & MODIFIER_MASK;
    
    for (key = 0; key < KEY_COUNT; key++)
    {
        if ((params.keys[key].keycode == ev->keycode)
            && (params.keys[key].modifier == state))
        {
            break;
        }
        switch (key)
        {
            case KEY_MOVE_UP:
            case KEY_MOVE_DOWN:
            case KEY_MOVE_LEFT:
            case KEY_MOVE_RIGHT:
                moveRequest (c, (XEvent *) ev);
                break;
            case KEY_RESIZE_UP:
            case KEY_RESIZE_DOWN:
            case KEY_RESIZE_LEFT:
            case KEY_RESIZE_RIGHT:
                if (CLIENT_FLAG_TEST_ALL (c,
                        CLIENT_FLAG_HAS_RESIZE | CLIENT_FLAG_IS_RESIZABLE))
                {
                    clientResize (c, CORNER_BOTTOM_RIGHT, (XEvent *) ev);
                }
                break;
            case KEY_CYCLE_WINDOWS:
                clientCycle (c, (XEvent *) ev);
                break;
            case KEY_CLOSE_WINDOW:
                clientClose (c);
                break;
            case KEY_HIDE_WINDOW:
                if (CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientHide (c, c->win_workspace, TRUE);
                }
                break;
            case KEY_MAXIMIZE_WINDOW:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
                break;
            case KEY_MAXIMIZE_VERT:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED_VERT);
                break;
            case KEY_MAXIMIZE_HORIZ:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED_HORIZ);
                break;
            case KEY_SHADE_WINDOW:
                clientToggleShaded (c);
                break;
            case KEY_STICK_WINDOW:
                clientToggleSticky (c, TRUE);
                frameDraw (c, FALSE, FALSE);
                break;
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            case KEY_RAISE_WINDOW:
                clientRaise (c);
                break;
            case KEY_LOWER_WINDOW:
                clientLower (c);
                break;
            case KEY_MOVE_NEXT_WORKSPACE:
                workspaceSwitch (workspace + 1, c);
                break;
            case KEY_MOVE_PREV_WORKSPACE:
                workspaceSwitch (workspace - 1, c);
                break;
            case KEY_MOVE_WORKSPACE_1:
                workspaceSwitch (0, c);
                break;
            case KEY_MOVE_WORKSPACE_2:
                workspaceSwitch (1, c);
                break;
            case KEY_MOVE_WORKSPACE_3:
                workspaceSwitch (2, c);
                break;
            case KEY_MOVE_WORKSPACE_4:
                workspaceSwitch (3, c);
                break;
            case KEY_MOVE_WORKSPACE_5:
                workspaceSwitch (4, c);
                break;
            case KEY_MOVE_WORKSPACE_6:
                workspaceSwitch (5, c);
                break;
            case KEY_MOVE_WORKSPACE_7:
                workspaceSwitch (6, c);
                break;
            case KEY_MOVE_WORKSPACE_8:
                workspaceSwitch (7, c);
                break;
            case KEY_MOVE_WORKSPACE_9:
                workspaceSwitch (8, c);
                break;
            default:
                break;
        }
        switch (key)
        {
            case KEY_CYCLE_WINDOWS:
                if (clients)
                {
                    clientCycle (clients->prev, (XEvent *) ev);
        case KEY_NEXT_WORKSPACE:
            workspaceSwitch (workspace + 1, NULL);
            break;
        case KEY_PREV_WORKSPACE:
            workspaceSwitch (workspace - 1, NULL);
            break;
        case KEY_ADD_WORKSPACE:
            workspaceSetCount (params.workspace_count + 1);
            break;
        case KEY_DEL_WORKSPACE:
            workspaceSetCount (params.workspace_count - 1);
            break;
        case KEY_WORKSPACE_1:
            workspaceSwitch (0, NULL);
            break;
        case KEY_WORKSPACE_2:
            workspaceSwitch (1, NULL);
            break;
        case KEY_WORKSPACE_3:
            workspaceSwitch (2, NULL);
            break;
        case KEY_WORKSPACE_4:
            workspaceSwitch (3, NULL);
            break;
        case KEY_WORKSPACE_5:
            workspaceSwitch (4, NULL);
            break;
        case KEY_WORKSPACE_6:
            workspaceSwitch (5, NULL);
            break;
        case KEY_WORKSPACE_7:
            workspaceSwitch (6, NULL);
            break;
        case KEY_WORKSPACE_8:
            workspaceSwitch (7, NULL);
            break;
        case KEY_WORKSPACE_9:
            workspaceSwitch (8, NULL);
            break;
        case KEY_SHORTCUT_1:
            spawn_shortcut (0);
            break;
        case KEY_SHORTCUT_2:
            spawn_shortcut (1);
            break;
        case KEY_SHORTCUT_3:
            spawn_shortcut (2);
            break;
        case KEY_SHORTCUT_4:
            spawn_shortcut (3);
            break;
        case KEY_SHORTCUT_5:
            spawn_shortcut (4);
            break;
        case KEY_SHORTCUT_6:
            spawn_shortcut (5);
            break;
        case KEY_SHORTCUT_7:
            spawn_shortcut (6);
            break;
        case KEY_SHORTCUT_8:
            spawn_shortcut (7);
            break;
        case KEY_SHORTCUT_9:
            spawn_shortcut (8);
            break;
        case KEY_SHORTCUT_10:
            spawn_shortcut (9);
            break;
        default:
            break;
/* User has clicked on an edge or corner.
 * Button 1 : Raise and resize
 * Button 2 : Move
 * Button 3 : Resize
 */
static inline void
edgeButton (Client * c, int part, XButtonEvent * ev)
    if (ev->button == Button2)
        XfwmButtonClickType tclick;
        tclick = typeOfClick (c->frame, (XEvent *) ev, FALSE);
        if (tclick == XFWM_BUTTON_CLICK)
        {
            clientLower (c);
        }
        else
        {
            moveRequest (c, (XEvent *) ev);
        }
        if (ev->button == Button1)
        {
            clientRaise (c);
        }
        if ((ev->button == Button1) || (ev->button == Button3))
        {
            resizeRequest (c, part, (XEvent *) ev);
        }
static inline void
button1Action (Client * c, XButtonEvent * ev)
{
    XEvent copy_event = (XEvent) * ev;
    XfwmButtonClickType tclick;

    g_return_if_fail (c != NULL);
    g_return_if_fail (ev != NULL);
    clientSetFocus (c, TRUE, FALSE);
    tclick = typeOfClick (c->frame, &copy_event, TRUE);
    if ((tclick == XFWM_BUTTON_DRAG)
        || (tclick == XFWM_BUTTON_CLICK_AND_DRAG))
        moveRequest (c, (XEvent *) ev);
    else if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
        switch (params.double_click_action)
        {
            case ACTION_MAXIMIZE:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
                break;
            case ACTION_SHADE:
                clientToggleShaded (c);
                break;
            case ACTION_HIDE:
                if (CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientHide (c, c->win_workspace, TRUE);
                }
static inline void
titleButton (Client * c, int state, XButtonEvent * ev)
    g_return_if_fail (c != NULL);
    g_return_if_fail (ev != NULL);

    if (ev->button == Button1)
    {
        button1Action (c, ev);
    }
    else if (ev->button == Button2)
    {
    }
    else if (ev->button == Button3)
    {
        /*
           We need to copy the event to keep the original event untouched
           for gtk to handle it (in case we open up the menu)
         */

        XEvent copy_event = (XEvent) * ev;
        XfwmButtonClickType tclick;

        tclick = typeOfClick (c->frame, &copy_event, FALSE);

        if (tclick == XFWM_BUTTON_DRAG)
        {
            moveRequest (c, (XEvent *) ev);
        }
        else
        {
            clientSetFocus (c, TRUE, FALSE);
            if (params.raise_on_click)
            {
                clientRaise (c);
            }
            ev->window = ev->root;
            if (button_handler_id)
            {
                g_signal_handler_disconnect (GTK_OBJECT (getDefaultGtkWidget
                        ()), button_handler_id);
            }
            button_handler_id =
                g_signal_connect (GTK_OBJECT (getDefaultGtkWidget ()),
                "button_press_event", GTK_SIGNAL_FUNC (show_popup_cb),
                (gpointer) c);
            /* Let GTK handle this for us. */
        }
    }
    else if (ev->button == Button4)
    {
        /* Mouse wheel scroll up */
        if (!CLIENT_FLAG_TEST (c, CLIENT_FLAG_SHADED))
        {
            clientShade (c);
        }
    else if (ev->button == Button5)
        /* Mouse wheel scroll down */
        if (CLIENT_FLAG_TEST (c, CLIENT_FLAG_SHADED))
        {
            clientUnshade (c);
        }
static inline void
rootScrollButton (XButtonEvent * ev)
{
    static Time lastscroll = (Time) 0;
    XEvent otherEvent;

    while (XCheckTypedWindowEvent (dpy, root, ButtonPress, &otherEvent))
        if (otherEvent.xbutton.button != ev->button)
        {
            XPutBackEvent (dpy, &otherEvent);
        }
    if ((ev->time - lastscroll) < 100)  /* ms */
        /* Too many events in too little time, drop this event... */
        return;
    }
    lastscroll = ev->time;
    if (ev->button == Button4)
    {
        workspaceSwitch (workspace - 1, NULL);
        workspaceSwitch (workspace + 1, NULL);
static inline void
handleButtonPress (XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    Window win;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleButtonPress");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Clear timeout */
    clear_timeout ();

    c = clientGetFromWindow (ev->window, ANY);
    if (c)
    {
        state = ev->state &  MODIFIER_MASK;
        if ((ev->button == Button1) && (state == AltMask) && (params.easy_click))
        else if ((ev->button == Button2) && (state == AltMask) && (params.easy_click))
        {
            clientLower (c);
        }
        else if ((ev->button == Button3) && (state == AltMask) && (params.easy_click))
            if ((ev->x < c->width / 2) && (ev->y < c->height / 2))
            {
                edgeButton (c, CORNER_TOP_LEFT, ev);
            }
            else if ((ev->x < c->width / 2) && (ev->y > c->height / 2))
            {
                edgeButton (c, CORNER_BOTTOM_LEFT, ev);
            }
            else if ((ev->x > c->width / 2) && (ev->y < c->height / 2))
            {
                edgeButton (c, CORNER_TOP_RIGHT, ev);
            }
            else
            {
                edgeButton (c, CORNER_BOTTOM_RIGHT, ev);
            }
        }
        else if (WIN_IS_BUTTON (win))
        {
            if (ev->button <= Button3)
            {
                clientSetFocus (c, TRUE, FALSE);
                if (params.raise_on_click)
                {
                    clientRaise (c);
                }
                clientButtonPress (c, win, ev);
            }
        }
        else if (win == MYWINDOW_XWINDOW (c->title))
        {
            titleButton (c, state, ev);
        }
        else if (win == MYWINDOW_XWINDOW (c->buttons[MENU_BUTTON]))
        {
            if (ev->button == Button1)
            {
                /*
                   We need to copy the event to keep the original event untouched
                   for gtk to handle it (in case we open up the menu)
                 */

                XEvent copy_event = (XEvent) * ev;
                XfwmButtonClickType tclick;

                tclick = typeOfClick (c->frame, &copy_event, TRUE);

                if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
                {
                    clientClose (c);
                }
                else
                {
                    clientSetFocus (c, TRUE, FALSE);
                    if (params.raise_on_click)
                    {
                        clientRaise (c);
                    }
                    ev->window = ev->root;
                    if (button_handler_id)
                    {
                        g_signal_handler_disconnect (GTK_OBJECT
                            (getDefaultGtkWidget ()), button_handler_id);
                    }
                    button_handler_id =
                        g_signal_connect (GTK_OBJECT (getDefaultGtkWidget ()),
                        "button_press_event", GTK_SIGNAL_FUNC (show_popup_cb),
                        (gpointer) c);
                    /* Let GTK handle this for us. */
                }
            }
        }
        else if (((ev->window != c->window) && (ev->button == Button2)
                && (state == 0)) || ((ev->button == Button2)
                && (state == (AltMask | ControlMask))))
        {
            clientLower (c);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_TOP_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_TOP_RIGHT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_BOTTOM_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_BOTTOM_RIGHT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_BOTTOM, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_RIGHT, ev);
        }
        else
        {
            if (ev->button == Button1)
            {
                clientSetFocus (c, TRUE, FALSE);
                if (params.raise_on_click)
                {
                    clientRaise (c);
                }
            }
            if (ev->window == c->window)
            {
                replay = TRUE;
            }
        }

        if (replay)
        {
            XAllowEvents (dpy, ReplayPointer, ev->time);
        }
        else
        {
            XAllowEvents (dpy, SyncPointer, ev->time);
        }
    }
    else if ((ev->window == root) && ((ev->button == Button4)
            || (ev->button == Button5)))
    {
        rootScrollButton (ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else
    {
        XSendEvent (dpy, gnome_win, FALSE, SubstructureNotifyMask,
            (XEvent *) ev);
static inline void
handleButtonRelease (XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering handleButtonRelease");
Olivier Fourdan's avatar
Olivier Fourdan committed

    XSendEvent (dpy, gnome_win, FALSE, SubstructureNotifyMask, (XEvent *) ev);
static inline void
handleDestroyNotify (XDestroyWindowEvent * ev)
    TRACE ("entering handleDestroyNotify");
    TRACE ("DestroyNotify on window (0x%lx)", ev->window);
    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
        TRACE ("DestroyNotify for \"%s\" (0x%lx)", c->name, c->window);
        clientPassFocus (c);
        clientUnframe (c, FALSE);
static inline void
handleMapRequest (XMapRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    TRACE ("entering handleMapRequest");
    TRACE ("MapRequest on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("Mapping None ???");
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientShow");
        if (CLIENT_FLAG_TEST (c, CLIENT_FLAG_MAP_PENDING))
        {
            TRACE ("Ignoring MapRequest on window (0x%lx)", ev->window);
            return;
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (CLIENT_FLAG_TEST (c, CLIENT_FLAG_STICKY) ||
            (c->win_workspace == workspace))
        {
            clientFocusNew(c);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientFrame");
        clientFrame (ev->window, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
static inline void
handleMapNotify (XMapEvent * ev)
{
    Client *c;

    TRACE ("entering handleMapNotify");
    TRACE ("MapNotify on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = clientGetFromWindow (ev->window, WINDOW);
    if (c)
    {
        TRACE ("MapNotify for \"%s\" (0x%lx)", c->name, c->window);
        if (CLIENT_FLAG_TEST (c, CLIENT_FLAG_MAP_PENDING))
        {
            CLIENT_FLAG_UNSET (c, CLIENT_FLAG_MAP_PENDING);
        }
    }
}

static inline void
handleUnmapNotify (XUnmapEvent * ev)
{
    Client *c = NULL;

    TRACE ("entering handleUnmapNotify");
    TRACE ("UnmapNotify on window (0x%lx)", ev->window);
    
    if (ev->from_configure)
    {
        TRACE ("Ignoring UnmapNotify caused by parent's resize\n");
        return;
    }

    c = clientGetFromWindow (ev->window, WINDOW); 
    if (c)
    {
        TRACE ("UnmapNotify for \"%s\" (0x%lx)", c->name, c->window);
        TRACE ("ignore_unmaps for \"%s\" is %i", c->name, c->ignore_unmap);
        if (CLIENT_FLAG_TEST (c, CLIENT_FLAG_MAP_PENDING))
             * This UnmapNotify event is caused by reparenting
             * so we just ignore it, so the window won't return 
             * to withdrawn state by mistake.
             */
            TRACE ("Client \"%s\" is not mapped, event ignored", c->name);
        
        /*
         * ICCCM spec states that a client wishing to switch
         * to WithdrawnState should send a synthetic UnmapNotify 
         * with the event field set to root if the client window 
         * is already unmapped.
         * Therefore, bypass the ignore_unmap counter and
         * unframe the client.
         */
        if ((ev->event == root) && (ev->send_event))
        {
            TRACE ("ICCCM UnmapNotify for \"%s\"", c->name);
            clientUnframe (c, FALSE);
            return;
        }
        if (c->ignore_unmap)
        {
            c->ignore_unmap--;
            TRACE ("ignore_unmaps for \"%s\" is  now %i", 
                 c->name, c->ignore_unmap);
        }
        else
        {
            clientUnframe (c, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
static inline void
handleConfigureNotify (XConfigureEvent * ev)
{
    TRACE ("entering handleConfigureNotify");

    if (ev->window == root)
    {
        TRACE ("ConfigureNotify on the root win (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_RANDR
        XRRUpdateConfiguration (ev);
#else
        xscreen->width   = ev->width;
        xscreen->height  = ev->height;
#endif
Olivier Fourdan's avatar
Olivier Fourdan committed
        placeSidewalks (params.wrap_workspaces);
        clientScreenResize ();
static inline void
handleConfigureRequest (XConfigureRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    XWindowChanges wc;
Olivier Fourdan's avatar
Olivier Fourdan committed
    XEvent otherEvent;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleConfigureRequest");
    TRACE ("ConfigureRequest on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    /* Compress events - logic taken from kwin */
    while (XCheckTypedWindowEvent (dpy, ev->window, ConfigureRequest,
            &otherEvent))