Skip to content
Snippets Groups Projects
events.c 41.5 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>
#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 "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"
#include "menu.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])))

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, gpointer data);
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);

    g = XGrabPointer(dpy, w, FALSE, ButtonMotionMask | PointerMotionMask | PointerMotionHintMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, ev->xbutton.time);
        TRACE("grab failed in typeOfClick");
    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))
        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;
        if((XfwmButtonClickType) clicks == XFWM_BUTTON_DOUBLE_CLICK || (!allow_double_click && (XfwmButtonClickType) clicks == XFWM_BUTTON_CLICK))
        {
            break;
        }
    }
    XUngrabPointer(dpy, ev->xbutton.time);
    return (XfwmButtonClickType) clicks;
}

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
{
    Client *c;
Olivier Fourdan's avatar
Olivier Fourdan committed

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

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
    }
    raise_timeout = g_timeout_add_full(0, params.raise_delay, (GtkFunction) raise_cb, NULL, NULL);
static inline void moveRequest(Client * c, XEvent * ev)
    if(CLIENT_FLAG_TEST_AND_NOT(c, CLIENT_FLAG_HAS_BORDER | CLIENT_FLAG_HAS_MOVE, CLIENT_FLAG_FULLSCREEN))
static inline void resizeRequest(Client * c, int corner, XEvent * ev)
    if(CLIENT_FLAG_TEST_ALL(c, CLIENT_FLAG_HAS_RESIZE | CLIENT_FLAG_IS_RESIZABLE))
    else if(CLIENT_FLAG_TEST_AND_NOT(c, CLIENT_FLAG_HAS_BORDER | CLIENT_FLAG_HAS_MOVE, CLIENT_FLAG_FULLSCREEN))
static inline void spawn_shortcut(int i)
{
    GError *error = NULL;
    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 handleKeyPress(XKeyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    int state, key;
    XEvent e;

Olivier Fourdan's avatar
Olivier Fourdan committed

    c = clientGetFocus();
Olivier Fourdan's avatar
Olivier Fourdan committed
    state = ev->state & (ShiftMask | ControlMask | AltMask | MetaMask | SuperMask | HyperMask);
Olivier Fourdan's avatar
Olivier Fourdan committed
    for(key = 0; key < KEY_COUNT; key++)
    {
        if((params.keys[key].keycode == ev->keycode) && (params.keys[key].modifier == state))
Olivier Fourdan's avatar
Olivier Fourdan committed
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    if(c)
    {
        switch (key)
        {
        case KEY_MOVE_UP:
        case KEY_MOVE_DOWN:
        case KEY_MOVE_LEFT:
        case KEY_MOVE_RIGHT:
            moveRequest(c, (XEvent *) ev);
        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);
            }
            clientHide(c, c->win_workspace, TRUE);
            clientToggleMaximized(c, WIN_STATE_MAXIMIZED);
            clientToggleMaximized(c, WIN_STATE_MAXIMIZED_VERT);
            clientToggleMaximized(c, WIN_STATE_MAXIMIZED_HORIZ);
            frameDraw(c, FALSE, FALSE);
        case KEY_MOVE_NEXT_WORKSPACE:
            workspaceSwitch(workspace + 1, c);
        case KEY_MOVE_PREV_WORKSPACE:
            workspaceSwitch(workspace - 1, c);
        }
    }
    else
    {
        switch (key)
        {
        case KEY_CYCLE_WINDOWS:
            if(clients)
            {
                clientCycle(clients->prev);
            }
        }
    }
    switch (key)
    {
    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) || (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);

    clientRaise(c);

    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)
        {
            clientToggleMaximized(c, WIN_STATE_MAXIMIZED);
            break;
        case ACTION_SHADE:
            clientToggleShaded(c);
            break;
        case ACTION_HIDE:
            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)
    {
        clientLower(c);
    }
    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
        {
            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 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 */
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    if(c)
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        state = ev->state & (ShiftMask | ControlMask | AltMask | MetaMask | SuperMask | HyperMask);
        win = ev->subwindow;
        if((ev->button == Button1) && (state == AltMask))
        {
            button1Action(c, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
                clientSetFocus(c, TRUE);
                if(params.raise_on_click)
                {
                    clientRaise(c);
                }
                clientButtonPress(c, win, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if(win == MYWINDOW_XWINDOW(c->title))
        {
            titleButton(c, state, ev);
        else if(win == MYWINDOW_XWINDOW(c->buttons[MENU_BUTTON]))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            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);
                    clientSetFocus(c, TRUE);
                    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))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, CORNER_TOP_LEFT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->corners[CORNER_TOP_RIGHT])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, CORNER_TOP_RIGHT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->corners[CORNER_BOTTOM_LEFT])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, CORNER_BOTTOM_LEFT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->corners[CORNER_BOTTOM_RIGHT])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, CORNER_BOTTOM_RIGHT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->sides[SIDE_BOTTOM])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, 4 + SIDE_BOTTOM, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->sides[SIDE_LEFT])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, 4 + SIDE_LEFT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((win == MYWINDOW_XWINDOW(c->sides[SIDE_RIGHT])) && (state == 0))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            edgeButton(c, 4 + SIDE_RIGHT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
                if(params.raise_on_click)
            if(ev->window == c->window)
Olivier Fourdan's avatar
Olivier Fourdan committed
            }
Olivier Fourdan's avatar
Olivier Fourdan committed

        if(replay)
            XAllowEvents(dpy, ReplayPointer, ev->time);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            XAllowEvents(dpy, SyncPointer, ev->time);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
    }
    else
    {
        XUngrabPointer(dpy, CurrentTime);
        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)
{
    Client *c;

    TRACE("entering handleDestroyNotify");
    TRACE("destroyed window is (0x%lx)", ev->window);

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        TRACE("DestroyNotify for \"%s\" (0x%lx)", c->name, c->window);
static inline void handleUnmapNotify(XUnmapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    TRACE("entering handleUnmapNotify");
    TRACE("unmapped window is (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        TRACE("UnmapNotify for \"%s\" (0x%lx)", c->name, c->window);
        /* Reparenting generates an unmapnotify, don't pass focus in that case */
        if (CLIENT_FLAG_TEST(c, CLIENT_FLAG_REPARENTING))
        {
            CLIENT_FLAG_UNSET(c, CLIENT_FLAG_REPARENTING);
        }
        else
        {
            clientPassFocus(c);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        if(c->ignore_unmap)
Olivier Fourdan's avatar
Olivier Fourdan committed
            c->ignore_unmap--;
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
static inline void handleMapRequest(XMapRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

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

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        return;
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else
    {
        clientFrame(ev->window, FALSE);
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("configured window is (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))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        if(otherEvent.xconfigurerequest.value_mask == ev->value_mask)
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            ev = &otherEvent.xconfigurerequest;
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
            XPutBackEvent(dpy, &otherEvent);
            break;
        }
    }

Olivier Fourdan's avatar
Olivier Fourdan committed
    wc.x = ev->x;
    wc.y = ev->y;
    wc.width = ev->width;
    wc.height = ev->height;
    wc.sibling = ev->above;
    wc.stack_mode = ev->detail;
    wc.border_width = ev->border_width;

    c = clientGetFromWindow(ev->window, WINDOW);
    {
        /* Some app tend or try to manipulate the wm frame to achieve fullscreen mode */
        c = clientGetFromWindow(ev->window, FRAME);
            TRACE("client %s (0x%lx) is attempting to manipulate its frame!", c->name, c->window);
                wc.x += frameLeft(c);
                wc.y += frameTop(c);
                wc.width -= frameLeft(c) + frameRight(c);
                wc.height -= frameTop(c) + frameBottom(c);
            /* We don't allow changing stacking order by accessing the frame
               window because that would break the layer management in xfwm4
             */
            ev->value_mask &= ~(CWSibling | CWStackMode);
Olivier Fourdan's avatar
Olivier Fourdan committed
    if(c)
    {
        gboolean constrained = FALSE;
        TRACE("handleConfigureRequest managed window \"%s\" (0x%lx)", c->name, c->window);
        if(CLIENT_FLAG_TEST(c, CLIENT_FLAG_MOVING_RESIZING))
        {
            /* Sorry, but it's not the right time for configure request */
            return;
        }
        if(c->type == WINDOW_DESKTOP)
        {
            /* Ignore stacking request for DESKTOP windows */
            ev->value_mask &= ~(CWSibling | CWStackMode);
        clientCoordGravitate(c, APPLY, &wc.x, &wc.y);
        if(ev->value_mask & (CWX | CWY | CWWidth | CWHeight))
            if(CLIENT_FLAG_TEST(c, CLIENT_FLAG_MAXIMIZED))
            {
                clientRemoveMaximizeFlag(c);
            }
            constrained = TRUE;
        /* Let's say that if the client performs a XRaiseWindow, we show the window if hidden */
        if((ev->value_mask & CWStackMode) && (wc.stack_mode == Above))
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (c->win_workspace == workspace)
Olivier Fourdan's avatar
Olivier Fourdan committed
                if (CLIENT_FLAG_TEST(c, CLIENT_FLAG_HIDDEN))
                {
                    clientShow(c, TRUE);
                }
        clientConfigure(c, &wc, ev->value_mask, constrained);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else
    {
        TRACE("unmanaged configure request for win 0x%lx", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
    }
}

static inline void handleEnterNotify(XCrossingEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

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

    if((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab) || (ev->detail > NotifyNonlinearVirtual))
    {
        /* We're not interested in such notifications */
        return;
    }
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE("entered window is (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = clientGetFromWindow(ev->window, FRAME);
    if(c && !(params.click_to_focus) && (clientAcceptFocus(c)))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE("EnterNotify window is \"%s\"", c->name);
        if((c->type != WINDOW_DOCK) && (c->type != WINDOW_DESKTOP))
        {
static inline void handleFocusIn(XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed


    if((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab) || (ev->detail > NotifyNonlinearVirtual))
    {
        /* We're not interested in such notifications */
        return;
    }
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        /* Don't get fooled by our own gtk window ! */
        return;
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    c = clientGetFromWindow(ev->window, WINDOW);
    while(XCheckTypedEvent(dpy, FocusIn, (XEvent *) ev))
    {
        if((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab) || (ev->detail > NotifyNonlinearVirtual))
        c2 = clientGetFromWindow(ev->window, WINDOW);
    TRACE("focused window is (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    if(c)
    {
        TRACE("focus set to \"%s\" (0x%lx)", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        clientUpdateFocus(c);
        frameDraw(c, FALSE, FALSE);
        if(params.raise_on_focus && !params.click_to_focus)
static inline void handleFocusOut(XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE("entering handleFocusOut - Window (0x%lx)", w);
static inline void handlePropertyNotify(XPropertyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    long dummy;

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

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        if(ev->atom == XA_WM_NORMAL_HINTS)
        {
            unsigned long previous_value;
            TRACE("client \"%s\" (0x%lx) has received a XA_WM_NORMAL_HINTS notify", c->name, c->window);
            XGetWMNormalHints(dpy, c->window, c->size, &dummy);
            previous_value = CLIENT_FLAG_TEST(c, CLIENT_FLAG_IS_RESIZABLE);
            CLIENT_FLAG_UNSET(c, CLIENT_FLAG_IS_RESIZABLE);
            if(((c->size->flags & (PMinSize | PMaxSize)) != (PMinSize | PMaxSize)) || (((c->size->flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize)) && ((c->size->min_width < c->size->max_width) || (c->size->min_height < c->size->max_height))))
            {
                CLIENT_FLAG_SET(c, CLIENT_FLAG_IS_RESIZABLE);
            }
            if(CLIENT_FLAG_TEST(c, CLIENT_FLAG_IS_RESIZABLE) != previous_value)
                frameDraw(c, TRUE, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((ev->atom == XA_WM_NAME) || (ev->atom == net_wm_name))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            TRACE("client \"%s\" (0x%lx) has received a XA_WM_NAME notify", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if(c->name)
Olivier Fourdan's avatar
Olivier Fourdan committed
                free(c->name);
            }
            CLIENT_FLAG_SET(c, CLIENT_FLAG_NAME_CHANGED);
            frameDraw(c, TRUE, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if(ev->atom == motif_wm_hints)
        {
            TRACE("client \"%s\" (0x%lx) has received a motif_wm_hints notify", c->name, c->window);
            clientUpdateMWMHints(c);
            wc.x = c->x;
            wc.y = c->y;
            wc.width = c->width;
            wc.height = c->height;
            clientConfigure(c, &wc, CWX | CWY | CWWidth | CWHeight, FALSE);
            TRACE("client \"%s\" (0x%lx) has received a XA_WM_HINTS notify\n", c->name, c->window);
            c->wmhints = XGetWMHints(dpy, c->window);
            if(c->wmhints)
            {
                c->group_leader = c->wmhints->window_group;
            }
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if(ev->atom == win_hints)
        {
            TRACE("client \"%s\" (0x%lx) has received a win_hints notify", c->name, c->window);
            getGnomeHint(dpy, c->window, win_hints, &c->win_hints);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            TRACE("client \"%s\" (0x%lx) has received a net_wm_window_type notify", c->name, c->window);
            frameDraw(c, TRUE, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
            TRACE("client \"%s\" (0x%lx) has received a net_wm_strut notify", c->name, c->window);
        else if(ev->atom == wm_colormap_windows)
        {
            clientUpdateColormaps(c);
            if(c == clientGetFocus())
            {
                clientInstallColormaps(c);
#ifdef HAVE_STARTUP_NOTIFICATION
        else if(ev->atom == net_startup_id)
        {
            if(c->startup_id)
            {