Skip to content
Snippets Groups Projects
events.c 32.3 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.
Olivier Fourdan's avatar
Olivier Fourdan committed

        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.
Olivier Fourdan's avatar
Olivier Fourdan committed

        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 Olivier Fourdan

 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

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
#include <X11/Xlib.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "main.h"
#include "workspaces.h"
#include "settings.h"
#include "frame.h"
#include "client.h"
#include "menu.h"
#include "gtktoxevent.h"
#include "debug.h"

static guint raise_timeout = 0;
static gulong button_handler_id = 0;
static GdkAtom atom_rcfiles = GDK_NONE;

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_DRAG           = 1,
  XFWM_BUTTON_CLICK          = 2,
  XFWM_BUTTON_DOUBLE_CLICK   = 4
} XfwmButtonClickType;

static inline XfwmButtonClickType typeOfClick(Window w, XEvent * ev)
{
    int xcurrent, ycurrent, x, y, total = 0;
    int g = GrabSuccess;
    int clicks = 1;
    Time t0;
    
    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);    
    if (g != GrabSuccess)
    {
        DBG("grab failed in typeOfClick\n");
        gdk_beep();
        return XFWM_BUTTON_UNDEFINED;
    }
    x = xcurrent = ev->xbutton.x_root;
    y = ycurrent = ev->xbutton.y_root;
    t0 = CurrentTime;
    
    while ((ABS(x - xcurrent) < 1) && (ABS(y - ycurrent) < 1) && (total < 250) && ((CurrentTime - t0) < 250))
    {
        g_usleep (10);
        total += 10;
        if (XCheckMaskEvent (dpy, ButtonReleaseMask | ButtonPressMask, ev))
        {
            clicks++;
        }
        if (XCheckMaskEvent (dpy, ButtonMotionMask | PointerMotionMask | PointerMotionHintMask, ev))
        {
            xcurrent = ev->xmotion.x_root;
            ycurrent = ev->xmotion.y_root;
        }
        if ((XfwmButtonClickType) clicks == XFWM_BUTTON_DOUBLE_CLICK)
        {
            break;
        }
    }
    XUngrabPointer(dpy, ev->xbutton.time);
    return (XfwmButtonClickType) clicks;
}

Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        gtk_timeout_remove(raise_timeout);
        raise_timeout = 0;
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    DBG("entering raise_cb\n");

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
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    raise_timeout = gtk_timeout_add(raise_delay, (GtkFunction) raise_cb, NULL);
static inline void handleKeyPress(XKeyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    int state, key;
    XEvent e;

    DBG("entering handleKeyEvent\n");

    c = clientGetFocus();
    state = ev->state & (ShiftMask | ControlMask | AltMask | MetaMask);
Olivier Fourdan's avatar
Olivier Fourdan committed
    for(key = 0; key < KEY_COUNT; key++)
    {
        if((keys[key].keycode == ev->keycode) && (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:
Olivier Fourdan's avatar
Olivier Fourdan committed
                break;
            case KEY_RESIZE_UP:
            case KEY_RESIZE_DOWN:
            case KEY_RESIZE_LEFT:
            case KEY_RESIZE_RIGHT:
                clientResize(c, CORNER_BOTTOM_RIGHT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
                break;
            case KEY_CYCLE_WINDOWS:
                clientCycle(c);
                break;
            case KEY_CLOSE_WINDOW:
                clientClose(c);
                break;
            case KEY_HIDE_WINDOW:
                clientHide(c, 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_RAISE_WINDOW_LAYER:
                clientSetLayer(c, c->win_layer + 1);
                break;
            case KEY_LOWER_WINDOW_LAYER:
                clientSetLayer(c, c->win_layer - 1);
                break;
            case KEY_NEXT_WORKSPACE:
                workspaceSwitch(workspace + 1, NULL);
                break;
            case KEY_PREV_WORKSPACE:
                workspaceSwitch(workspace - 1, NULL);
                break;
            case KEY_ADD_WORKSPACE:
                workspaceSetCount(workspace_count + 1);
                break;
            case KEY_DEL_WORKSPACE:
                workspaceSetCount(workspace_count - 1);
                break;
            case KEY_STICK_WINDOW:
                clientToggleSticky(c);
                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_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;
        }
    }
    else
    {
        switch (key)
        {
            case KEY_CYCLE_WINDOWS:
Olivier Fourdan's avatar
Olivier Fourdan committed
                    clientCycle(clients->prev);
Olivier Fourdan's avatar
Olivier Fourdan committed
                break;
            case KEY_NEXT_WORKSPACE:
                workspaceSwitch(workspace + 1, NULL);
                break;
            case KEY_PREV_WORKSPACE:
                workspaceSwitch(workspace - 1, NULL);
                break;
            case KEY_ADD_WORKSPACE:
                workspaceSetCount(workspace_count + 1);
                break;
            case KEY_DEL_WORKSPACE:
                workspaceSetCount(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;
        }
    }

    while(XCheckTypedEvent(dpy, EnterNotify, &e));
}

static inline void handleButtonPress(XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    Window win;
    int state, replay = False;

    DBG("entering handleButtonPress\n");

    /* Clear timeout */
Olivier Fourdan's avatar
Olivier Fourdan committed

Olivier Fourdan's avatar
Olivier Fourdan committed
    if(c)
    {
        state = ev->state & (ShiftMask | ControlMask | AltMask | MetaMask);
        win = ev->subwindow;
        
        if((win == c->buttons[HIDE_BUTTON]) || (win == c->buttons[CLOSE_BUTTON]) || (win == c->buttons[MAXIMIZE_BUTTON]) || (win == c->buttons[SHADE_BUTTON]) || (win == c->buttons[STICK_BUTTON]))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientButtonPress(c, win, ev);
        }
        else if(((win == c->title) && (ev->button == Button3)) || ((win == c->buttons[MENU_BUTTON]) && (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;
            
            if ((win == c->buttons[MENU_BUTTON]) && ((tclick = typeOfClick(c->frame, &copy_event)) && (tclick == XFWM_BUTTON_DOUBLE_CLICK)))
            {
                clientClose(c);
            }
            else
            {
                clientSetFocus(c, True);
                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. */
            }
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if(((win == c->title) && ((ev->button == Button1) && (state == 0))) || ((ev->button == Button1) && (state == AltMask)))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            XfwmButtonClickType tclick;
            if (win == c->title)
            {
                clientSetFocus(c, True);
            tclick = typeOfClick(c->frame, &copy_event);
            if((tclick == XFWM_BUTTON_DRAG) || (tclick == XFWM_BUTTON_CLICK_AND_DRAG))
            {
                if((c->has_border) && !(c->fullscreen))
                {
            else if(tclick == XFWM_BUTTON_DOUBLE_CLICK)
Olivier Fourdan's avatar
Olivier Fourdan committed
            {
                switch (double_click_action)
                {
                    case ACTION_MAXIMIZE:
                        clientToggleMaximized(c, WIN_STATE_MAXIMIZED);
                        break;
                    case ACTION_SHADE:
                        clientToggleShaded(c);
                        break;
                    case ACTION_HIDE:
                        clientHide(c, True);
                        break;
                }
            }
        }
        else if((win == c->corners[CORNER_TOP_LEFT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, CORNER_TOP_LEFT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->corners[CORNER_TOP_RIGHT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, CORNER_TOP_RIGHT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->corners[CORNER_BOTTOM_LEFT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, CORNER_BOTTOM_LEFT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->corners[CORNER_BOTTOM_RIGHT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, CORNER_BOTTOM_RIGHT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->sides[SIDE_BOTTOM]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, 4 + SIDE_BOTTOM, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->sides[SIDE_LEFT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, 4 + SIDE_LEFT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((win == c->sides[SIDE_RIGHT]) && (ev->button == Button1) && (state == 0))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientRaise(c);
            clientResize(c, 4 + SIDE_RIGHT, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if(((ev->window != c->window) && (ev->button == Button2) && (state == 0)) || ((ev->button == Button2) && (state == (AltMask | ControlMask))))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            if (ev->button == Button1)
            {
                clientSetFocus(c, True);
                clientRaise(c);
            if(ev->window == c->window)
Olivier Fourdan's avatar
Olivier Fourdan committed
                replay = True;
            }
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
{
    DBG("entering handleButtonRelease\n");

    XSendEvent(dpy, gnome_win, False, SubstructureNotifyMask, (XEvent *) ev);
}

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

    DBG("entering handleDestroyNotify\n");

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        clientUnframe(c, False);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if(clients)
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientSetFocus(clientGetNext(clients->prev, 0), True);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
static inline void handleUnmapNotify(XUnmapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    DBG("entering handleUnmapNotify\n");

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        if(c->ignore_unmap)
Olivier Fourdan's avatar
Olivier Fourdan committed
            c->ignore_unmap--;
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            clientUnframe(c, False);
            if(clients)
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientSetFocus(clientGetNext(clients->prev, 0), True);
            }
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientSetFocus(NULL, True);
static inline void handleMapRequest(XMapRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    DBG("entering handleMapRequest\n");

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        DBG("Mapping None ???\n");
        return;
    }
    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        clientShow(c, True);
    }
    else
    {
        clientFrame(ev->window);
    }
}

static inline void handleConfigureRequest(XConfigureRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    XWindowChanges wc;

    DBG("entering handleConfigureRequest\n");

    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);
    if(c)
    {
        if(c->type == WINDOW_DESKTOP)
        {
            /* Ignore stacking request for DESKTOP windows */
            wc.stack_mode &= ~CWStackMode;
        }
        clientCoordGravitate(c, APPLY, &wc.x, &wc.y);
        if ((ev->value_mask & (CWX | CWY | CWWidth | CWHeight)) && c->maximized)
        {
            clientRemoveMaximizeFlag(c);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        clientConfigure(c, &wc, ev->value_mask);
    }
    else
    {
        XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
    }
}

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

    DBG("entering handleEnterNotify\n");

    while(XCheckTypedEvent(dpy, EnterNotify, (XEvent *) ev));

    DBG("EnterNotify window is (%#lx)\n", ev->window);

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

    DBG("entering handleFocusIn\n");
    DBG("FocusIn window is (%#lx)\n", ev->window);

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);
    if(c)
    {
        DBG("focus set to \"%s\" (%#lx)\n", c->name, c->window);
        clientUpdateFocus(c);
        frameDraw(c);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if(raise_on_focus && !click_to_focus)
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else if(clients)
    {
        DBG("focus set to top window in list\n");
        clientSetFocus(clientGetNext(clients->prev, 0), True);
    }
    else
    {
        DBG("focus set to default fallback window\n");
        clientSetFocus(NULL, True);
    }
}

static inline void handleFocusOut(XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    DBG("entering handleFocusOut\n");
}

static inline void handlePropertyNotify(XPropertyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    long dummy;

    DBG("entering handlePropertyNotify\n");

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        if(ev->atom == XA_WM_NORMAL_HINTS)
        {
            DBG("client \"%s\" (%#lx) has received a XA_WM_NORMAL_HINTS notify\n", c->name, c->window);
            XGetWMNormalHints(dpy, c->window, c->size, &dummy);
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
        {
            DBG("client \"%s\" (%#lx) has received a XA_WM_NAME notify\n", c->name, c->window);
            if(c->name)
Olivier Fourdan's avatar
Olivier Fourdan committed
                free(c->name);
            }
Olivier Fourdan's avatar
Olivier Fourdan committed
            frameDraw(c);
        }
        else if(ev->atom == win_hints)
        {
            DBG("client \"%s\" (%#lx) has received a win_hints notify\n", 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
        {
            DBG("client \"%s\" (%#lx) has received a win_layer notify\n", c->name, c->window);
            getGnomeHint(dpy, c->window, win_layer, &dummy);
            clientSetLayer(c, dummy);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            DBG("client \"%s\" (%#lx) has received a net_wm_window_type notify\n", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((ev->atom == win_workspace) && !(c->transient_for))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            DBG("client \"%s\" (%#lx) has received a win_workspace notify\n", c->name, c->window);
            getGnomeHint(dpy, c->window, win_workspace, &dummy);
            clientSetWorkspace(c, dummy, TRUE);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        {
            DBG("client \"%s\" (%#lx) has received a net_wm_strut notify\n", c->name, c->window);
        else if(ev->atom == wm_colormap_windows)
        {
            clientUpdateColormaps(c);
            if(c == clientGetFocus())
            {
                clientInstallColormaps(c);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else
    {
        if(ev->atom == win_workspace_count)
        {
            DBG("root has received a win_workspace_count notify\n");
            getGnomeHint(dpy, root, win_workspace_count, &dummy);
            workspaceSetCount(dummy);
        }
        else if(ev->atom == gnome_panel_desktop_area)
        {
            DBG("root has received a gnome_panel_desktop_area notify\n");
            workspaceUpdateArea(margins, gnome_margins);
static inline void handleClientMessage(XClientMessageEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    DBG("entering handleClientMessage\n");

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        if((ev->message_type == wm_change_state) && (ev->format == 32) && (ev->data.l[0] == IconicState))
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a wm_change_state event\n", c->name, c->window);
            clientHide(c, True);
        }
        else if((ev->message_type == win_state) && (ev->format == 32) && (ev->data.l[0] & WIN_STATE_SHADED))
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a win_state/shaded event\n", c->name, c->window);
            clientToggleShaded(c);
        }
        else if((ev->message_type == win_state) && (ev->format == 32) && (ev->data.l[0] & WIN_STATE_STICKY))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            DBG("client \"%s\" (%#lx) has received a win_state/stick event\n", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        }
        else if((ev->message_type == win_layer) && (ev->format == 32))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a win_layer event\n", c->name, c->window);
            clientSetLayer(c, ev->data.l[0]);
        }
        else if((ev->message_type == win_workspace) && (ev->format == 32) && !(c->transient_for))
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a win_workspace event\n", c->name, c->window);
            clientSetWorkspace(c, ev->data.l[0], TRUE);
        }
        else if((ev->message_type == net_wm_desktop) && (ev->format == 32))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a net_wm_desktop event\n", c->name, c->window);
            else if (!(c->transient_for))
                clientSetWorkspace(c, ev->data.l[0], TRUE);
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((ev->message_type == net_close_window) && (ev->format == 32))
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("client \"%s\" (%#lx) has received a net_close_window event\n", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((ev->message_type == net_wm_state) && (ev->format == 32))
        {
            DBG("client \"%s\" (%#lx) has received a net_wm_state event\n", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((ev->message_type == net_wm_moveresize) && (ev->format == 32))
        {
            DBG("client \"%s\" (%#lx) has received a net_wm_moveresize event\n", c->name, c->window);
            g_message("Operation not supported (yet)\n");
            /* TBD */
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        else if((ev->message_type == net_active_window) && (ev->format == 32))
        {
            DBG("client \"%s\" (%#lx) has received a net_active_window event\n", c->name, c->window);
            workspaceSwitch(c->win_workspace, NULL);
            clientShow(c, True);
            clientRaise(c);
            clientSetFocus(c, True);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else
    {
        if(((ev->message_type == win_workspace) || (ev->message_type == net_current_desktop)) && (ev->format == 32))
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("root has received a win_workspace or a net_current_desktop event\n");
            workspaceSwitch(ev->data.l[0], NULL);
        }
        else if(((ev->message_type == win_workspace_count) || (ev->message_type == net_number_of_desktops)) && (ev->format == 32))
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            DBG("root has received a win_workspace_count event\n");
            workspaceSetCount(ev->data.l[0]);
static inline void handleShape(XShapeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;

    DBG("entering handleShape\n");

    c = clientGetFromWindow(ev->window, WINDOW);
    if(c)
    {
        frameDraw(c);
    }
}

static inline void handleColormapNotify(XColormapEvent * ev)
    DBG("entering handleColormapNotify\n");
    c = clientGetFromWindow(ev->window, WINDOW);
    if((c) && (ev->window == c->window) && (ev->new))
Olivier Fourdan's avatar
Olivier Fourdan committed
void handleEvent(XEvent * ev)
{
    DBG("entering handleEvent\n");

    switch (ev->type)
    {
        case KeyPress:
            handleKeyPress((XKeyEvent *) ev);
            break;
        case ButtonPress:
            handleButtonPress((XButtonEvent *) ev);
            break;
        case ButtonRelease:
            handleButtonRelease((XButtonEvent *) ev);
            break;
        case DestroyNotify:
            handleDestroyNotify((XDestroyWindowEvent *) ev);
            break;
        case UnmapNotify:
            handleUnmapNotify((XUnmapEvent *) ev);
            break;
        case MapRequest:
            handleMapRequest((XMapRequestEvent *) ev);
            break;
        case ConfigureRequest:
            handleConfigureRequest((XConfigureRequestEvent *) ev);
            break;
        case EnterNotify:
            handleEnterNotify((XCrossingEvent *) ev);
            break;
        case FocusIn:
            handleFocusIn((XFocusChangeEvent *) ev);
            break;
        case FocusOut:
            handleFocusOut((XFocusChangeEvent *) ev);
            break;
        case PropertyNotify:
            handlePropertyNotify((XPropertyEvent *) ev);
            break;
        case ClientMessage:
            handleClientMessage((XClientMessageEvent *) ev);
            break;
        case ColormapNotify:
            handleColormapNotify((XColormapEvent *) ev);
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
        default:
            if(shape && (ev->type == shape_event))
Olivier Fourdan's avatar
Olivier Fourdan committed
                handleShape((XShapeEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
            reloadSettings();
            reload = False;
Olivier Fourdan's avatar
Olivier Fourdan committed
            gtk_main_quit();
GtkToXEventFilterStatus xfwm4_event_filter(XEvent * xevent, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    DBG("entering xfwm4_event_filter\n");
    handleEvent(xevent);
    DBG("leaving xfwm4_event_filter\n");
    return XEV_FILTER_STOP;
}

/* GTK stuff (menu, etc...) */

static void menu_callback(Menu * menu, MenuOp op, Window client_xwindow, gpointer menu_data, gpointer item_data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    DBG("entering menu_callback\n");
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        c = (Client *) menu_data;
        c = clientGetFromWindow(c->window, WINDOW);
        if(c)
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            c->button_pressed[MENU_BUTTON] = False;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    switch (op)
    {
        case MENU_OP_QUIT:
            gtk_main_quit();
            break;
        case MENU_OP_MAXIMIZE:
        case MENU_OP_UNMAXIMIZE:
            if(c)
            {
                clientToggleMaximized(c, WIN_STATE_MAXIMIZED);
            }
            break;
        case MENU_OP_MINIMIZE:
            if(c)
            {
                clientHide(c, True);
            }
            break;
        case MENU_OP_MINIMIZE_ALL:
            clientHideAll(c);
            break;
        case MENU_OP_UNMINIMIZE:
            if(c)
            {
                clientShow(c, True);
            }
            break;
        case MENU_OP_SHADE:
        case MENU_OP_UNSHADE:
            if(c)
            {
                clientToggleShaded(c);
            }
            break;
        case MENU_OP_STICK:
        case MENU_OP_UNSTICK:
            if(c)
            {
                clientToggleSticky(c);
                frameDraw(c);
            }
            break;
        case MENU_OP_DELETE:
            if(c)
            {
                clientClose(c);
                frameDraw(c);
            }
            break;
        case MENU_OP_DESTROY:
            if(c)
            {
                clientKill(c);
                frameDraw(c);
            }
            break;