Skip to content
Snippets Groups Projects
events.c 31.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.

	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.

        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

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);
Olivier Fourdan's avatar
Olivier Fourdan committed
}

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
                    clientMove(c, (XEvent *) ev);
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);
                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 gboolean isDoubleClick(Window w, XEvent * ev)
{
    int xcurrent, ycurrent, x, y, total = 0;
    int g = GrabSuccess;
    Time t0;
    
    g_return_val_if_fail(ev != NULL, FALSE);
    g_return_val_if_fail(w != None, FALSE);

    g = XGrabPointer(dpy, w, False, ButtonMotionMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, ev->xbutton.time);    
    if (g != GrabSuccess)
    {
        DBG("grab failed in isDoubleClick\n");
        gdk_beep();
        return FALSE;
    }
    x = xcurrent = ev->xbutton.x_root;
    y = ycurrent = ev->xbutton.y_root;
    t0 = CurrentTime;
    
    while ((total < 250) && (ABS(x - xcurrent) < 2) && (ABS(y - ycurrent) < 2) && ((CurrentTime - t0) < 250))
    {
	if (XCheckMaskEvent (dpy, ButtonPressMask, ev))
	{
	    return TRUE;
	}
	if (XCheckMaskEvent (dpy, ButtonMotionMask | PointerMotionMask, ev))
	{
	    xcurrent = ev->xmotion.x_root;
	    ycurrent = ev->xmotion.y_root;
	    if ((ABS(x - xcurrent) > 0) || (ABS(y - ycurrent) > 0))
	    {
	        break;
	    }
	}
	g_usleep (10);
	total += 10;
    }
static inline void handleButtonPress(XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    Client *c;
    Window win;
    int state, replay = False;
    static Time last_button_time;

    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;
	    if ((win == c->buttons[MENU_BUTTON]) && isDoubleClick(c->frame, &copy_event))
	    {
	        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
        {
            if (win == c->title)
	    {
	        clientSetFocus(c, True);
                clientRaise(c);
            }
	    if(isDoubleClick(c->frame, (XEvent *) ev))
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;
                }
                last_button_time = 0;
            }
            else
            {
                if((c->has_border) && !(c->fullscreen))
                {
                    clientMove(c, (XEvent *) ev);
                }
Olivier Fourdan's avatar
Olivier Fourdan committed
                last_button_time = ev->time;
            }
        }
        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);
        }
        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);
        }
        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);
        }
        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);
        }
        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);
        }
        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);
        }
        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);
        }
        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
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            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;
        default:
            if(c)
            {
                frameDraw(c);
            }
            break;
    }
    menu_free(menu);
static gboolean show_popup_cb(GtkWidget * widget, GdkEventButton * ev, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{