Skip to content
Snippets Groups Projects
events.c 74.5 KiB
Newer Older
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2, or (at your option)
        any later version.
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Olivier Fourdan's avatar
Olivier Fourdan committed
        oroborus - (c) 2001 Ken Lynch
        xfwm4    - (c) 2002-2004 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>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <gdk/gdk.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#include <gdk/gdkx.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <libxfce4util/libxfce4util.h> 
#include <libxfcegui4/libxfcegui4.h>
#include <string.h>

Olivier Fourdan's avatar
Olivier Fourdan committed
#include "misc.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "workspaces.h"
#include "settings.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "mywindow.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "frame.h"
#include "client.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "menu.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "hints.h"
#include "startup_notification.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "compositor.h"
Olivier Fourdan's avatar
Olivier Fourdan committed

#ifndef CHECK_BUTTON_TIME
#define CHECK_BUTTON_TIME 0
#endif

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

#define DBL_CLICK_GRAB          (ButtonMotionMask | \
                                 PointerMotionMask | \
                                 ButtonPressMask | \
                                 ButtonReleaseMask)
                                 
#define MODIFIER_MASK           (ShiftMask | \
                                 ControlMask | \
                                 AltMask | \
                                 MetaMask | \
                                 SuperMask | \
                                 HyperMask)
extern gboolean xfwm4_quit;
extern gboolean xfwm4_reload;

Olivier Fourdan's avatar
Olivier Fourdan committed
static guint raise_timeout = 0;
static GdkAtom atom_rcfiles = GDK_NONE;
static xfwmWindow menu_event_window;
Olivier Fourdan's avatar
Olivier Fourdan committed

static void handleEvent (DisplayInfo *display_info, XEvent * ev);
static void menu_callback (Menu * menu, MenuOp op, Window xid,
    gpointer menu_data, gpointer item_data);
static gboolean show_popup_cb (GtkWidget * widget, GdkEventButton * ev,
static gboolean client_event_cb (GtkWidget * widget, GdkEventClient * ev, gpointer data);
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;
typedef struct _XfwmButtonClickData XfwmButtonClickData;
struct _XfwmButtonClickData
{
    DisplayInfo *display_info;
    Window w;
    guint button;
    gboolean allow_double_click;
    guint clicks;
    gint x;
    gint y;
    gint xcurrent;
    gint ycurrent;
    guint timeout;
};

static gboolean
typeOfClick_break (gpointer data)
{
    XfwmButtonClickData *passdata = (XfwmButtonClickData *) data;
    if (passdata->timeout)
    {
        g_source_remove (passdata->timeout);
        passdata->timeout = 0;
    }

    gtk_main_quit ();

    return (TRUE);
}

static XfceFilterStatus
typeOfClick_event_filter (XEvent * xevent, gpointer data)
{
    gboolean keep_going = TRUE;
    XfceFilterStatus status = XEV_FILTER_STOP;
    XfwmButtonClickData *passdata = (XfwmButtonClickData *) data;
    
    /* Update the display time */
    myDisplayUpdateCurentTime (passdata->display_info, xevent);

    if ((xevent->type == ButtonRelease) || (xevent->type == ButtonPress))
    {
        if (xevent->xbutton.button == passdata->button)
        {
            passdata->clicks++;
        }
        if (((XfwmButtonClickType) passdata->clicks == XFWM_BUTTON_DOUBLE_CLICK)
            || (!(passdata->allow_double_click) && 
                 (XfwmButtonClickType) passdata->clicks == XFWM_BUTTON_CLICK))
        {
            keep_going = FALSE;
        }
    }
    else if (xevent->type == MotionNotify)
    {
        passdata->xcurrent = xevent->xmotion.x_root;
        passdata->ycurrent = xevent->xmotion.y_root;
    }
    else if ((xevent->type == DestroyNotify) || (xevent->type == UnmapNotify))
    {
        if (xevent->xany.window == passdata->w)
        {
            /* Discard, mark the click as undefined */
            passdata->clicks = (guint) XFWM_BUTTON_UNDEFINED;
            keep_going = FALSE;
        }
        status = XEV_FILTER_CONTINUE;
    }
    else
    {
        status = XEV_FILTER_CONTINUE;
    }

    if ((ABS (passdata->x - passdata->xcurrent) > 1) || 
        (ABS (passdata->y - passdata->ycurrent) > 1) ||
        (!keep_going))
    {
        TRACE ("event loop now finished");
        typeOfClick_break (data);
    }

    return status;
}

static XfwmButtonClickType
typeOfClick (ScreenInfo *screen_info, Window w, XEvent * ev, gboolean allow_double_click)
    DisplayInfo *display_info = NULL;
    gboolean g;
    g_return_val_if_fail (screen_info != NULL, XFWM_BUTTON_UNDEFINED);
    g_return_val_if_fail (ev != NULL, XFWM_BUTTON_UNDEFINED);
    g_return_val_if_fail (w != None, XFWM_BUTTON_UNDEFINED);
    display_info = screen_info->display_info;    
    XFlush (display_info->dpy);
    g = myScreenGrabPointer (screen_info, DBL_CLICK_GRAB, None, ev->xbutton.time);

    if (!g)
        TRACE ("grab failed in typeOfClick");
        gdk_beep ();
        return XFWM_BUTTON_UNDEFINED;
    passdata.display_info = display_info;
    passdata.button = ev->xbutton.button;
    passdata.w = w;
    passdata.x = ev->xbutton.x_root;
    passdata.y = ev->xbutton.y_root;
    passdata.xcurrent = passdata.x;
    passdata.ycurrent = passdata.y;
    passdata.clicks = 1;
    passdata.allow_double_click = allow_double_click;
    passdata.timeout = g_timeout_add_full (0, display_info->dbl_click_time, 
                                              (GtkFunction) typeOfClick_break, 
                                              (gpointer) &passdata, NULL);

    TRACE ("entering typeOfClick loop");
    xfce_push_event_filter (display_info->xfilter, typeOfClick_event_filter, &passdata);
    gtk_main ();
    xfce_pop_event_filter (display_info->xfilter);
    TRACE ("leaving typeOfClick loop");

    myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info));
    XFlush (display_info->dpy);
    return (XfwmButtonClickType) passdata.clicks;
static gboolean
check_button_time (XButtonEvent *ev)
{
    static Time last_button_time = (Time) 0;
    
    if (last_button_time > ev->time)
    {
        return FALSE;
    }

    last_button_time = ev->time;
    return TRUE;
}
static void
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        g_source_remove (raise_timeout);
        raise_timeout = 0;
static gboolean
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering raise_cb");
Olivier Fourdan's avatar
Olivier Fourdan committed

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

static void
reset_timeout (ScreenInfo *screen_info)
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, screen_info->params->raise_delay, (GtkFunction) raise_cb, NULL, NULL);
static void
moveRequest (Client * c, XEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MOVE)
        && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
static void
resizeRequest (Client * c, int corner, XEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (FLAG_TEST_ALL (c->xfwm_flags,
            XFWM_FLAG_HAS_RESIZE | XFWM_FLAG_IS_RESIZABLE))
        clientResize (c, corner, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MOVE)
        && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
static void
spawn_shortcut (ScreenInfo *screen_info, int i)
    if ((i >= NB_KEY_SHORTCUTS) || (!screen_info->params->shortcut_exec[i])
        || !strlen (screen_info->params->shortcut_exec[i]))
    if (!xfce_gdk_spawn_command_line_on_screen (screen_info->gscr, screen_info->params->shortcut_exec[i], &error))
Olivier Fourdan's avatar
Olivier Fourdan committed
            g_warning ("%s", error->message);
static void
toggle_show_desktop (ScreenInfo *screen_info)
{
    long visible = 0;

Olivier Fourdan's avatar
Olivier Fourdan committed
    getHint (screen_info->display_info, screen_info->xroot, 
             NET_SHOWING_DESKTOP, &visible);
    sendRootMessage (screen_info, NET_SHOWING_DESKTOP, !visible, 
                     myDisplayGetCurrentTime (screen_info->display_info));
}

static void
handleMotionNotify (DisplayInfo *display_info, XMotionEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleMotionNotify");

    if (display_info->nb_screens > 1)
    {
        /* Wrap workspace/wrap windows is disabled with multiscreen */
        return;
    }
    
    /* Get the screen structure from the root of the event */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    }
    
    if (screen_info->workspace_count && screen_info->params->wrap_workspaces
        && screen_info->params->wrap_resistance)
    {
        msx = ev->x_root;
        msy = ev->y_root;
        maxx = gdk_screen_get_width (screen_info->gscr) - 1;
        maxy = gdk_screen_get_height (screen_info->gscr) - 1;
        {
            edge_scroll_x++;
        }
        else
        {
            edge_scroll_x = 0;
        }
        if ((msy == 0) || (msy == maxy))
        {
            edge_scroll_y++;
        }
        else
        {
            edge_scroll_y = 0;
        }

        if (edge_scroll_x > screen_info->params->wrap_resistance)
        {
            edge_scroll_x = 0;
            if (msx == 0)
            {
                if (workspaceMove (screen_info, 0, -1, NULL))
                {
                    XWarpPointer (display_info->dpy, None, screen_info->xroot, 0, 0, 0, 0, maxx - 10, msy);
                }
            }
            else if (msx == maxx)
            {
                if (workspaceMove (screen_info, 0, 1, NULL))
                {
                    XWarpPointer (display_info->dpy, None, screen_info->xroot, 0, 0, 0, 0, 10, msy);
                }
            }
            while (XCheckWindowEvent(display_info->dpy, ev->window, PointerMotionMask, (XEvent *) ev))
            {
                /* Update the display time */
                myDisplayUpdateCurentTime (display_info, (XEvent *) ev);
            }
        }
        if (edge_scroll_y > screen_info->params->wrap_resistance)
        {
            edge_scroll_y = 0;
            if (msy == 0)
            {
                if (workspaceMove (screen_info, -1, 0, NULL))
                {
                    XWarpPointer (display_info->dpy, None, screen_info->xroot, 0, 0, 0, 0, msx, maxy - 10);
                }
                if (workspaceMove (screen_info, 1, 0, NULL))
                {
                    XWarpPointer (display_info->dpy, None, screen_info->xroot, 0, 0, 0, 0, msx, 10);
                }
            while (XCheckWindowEvent(display_info->dpy, ev->window, PointerMotionMask, (XEvent *) ev))
            {
                /* Update the display time */
                myDisplayUpdateCurentTime (display_info, (XEvent *) ev);
            }
static int
getKeyPressed (ScreenInfo *screen_info, XKeyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    int key, state;
    state = ev->state & MODIFIER_MASK;
    for (key = 0; key < KEY_COUNT; key++)
    {
        if ((screen_info->params->keys[key].keycode == ev->keycode)
            && (screen_info->params->keys[key].modifier == state))
static void
handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev)
{
    ScreenInfo *screen_info = NULL;
    Client *c = NULL;
    int key;

    TRACE ("entering handleKeyEvent");

    c = clientGetFocus ();
        screen_info = c->screen_info;
        key = getKeyPressed (screen_info, ev);
        switch (key)
        {
            case KEY_MOVE_UP:
            case KEY_MOVE_DOWN:
            case KEY_MOVE_LEFT:
            case KEY_MOVE_RIGHT:
                moveRequest (c, (XEvent *) ev);
                break;
            case KEY_RESIZE_UP:
            case KEY_RESIZE_DOWN:
            case KEY_RESIZE_LEFT:
            case KEY_RESIZE_RIGHT:
Olivier Fourdan's avatar
Olivier Fourdan committed
                if (FLAG_TEST_ALL (c->xfwm_flags,
                        XFWM_FLAG_HAS_RESIZE | XFWM_FLAG_IS_RESIZABLE))
                {
                    clientResize (c, CORNER_BOTTOM_RIGHT, (XEvent *) ev);
                }
                break;
            case KEY_CYCLE_WINDOWS:
                clientCycle (c, (XEvent *) ev);
                break;
            case KEY_CLOSE_WINDOW:
                clientClose (c);
                break;
            case KEY_HIDE_WINDOW:
Olivier Fourdan's avatar
Olivier Fourdan committed
                if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER) && CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientHide (c, c->win_workspace, TRUE);
                }
                break;
            case KEY_MAXIMIZE_WINDOW:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
                break;
            case KEY_MAXIMIZE_VERT:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED_VERT);
                break;
            case KEY_MAXIMIZE_HORIZ:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED_HORIZ);
                break;
            case KEY_SHADE_WINDOW:
                clientToggleShaded (c);
                break;
            case KEY_STICK_WINDOW:
Olivier Fourdan's avatar
Olivier Fourdan committed
                if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER) && CLIENT_CAN_STICK_WINDOW(c))
                {
                    clientToggleSticky (c, TRUE);
                    frameDraw (c, FALSE, FALSE);
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            case KEY_RAISE_WINDOW:
                clientRaise (c);
                break;
            case KEY_LOWER_WINDOW:
                clientLower (c);
                break;
            case KEY_TOGGLE_FULLSCREEN:
                clientToggleFullscreen (c);
                break;
            case KEY_MOVE_NEXT_WORKSPACE:
                workspaceSwitch (screen_info, screen_info->current_ws + 1, c);
                break;
            case KEY_MOVE_PREV_WORKSPACE:
                workspaceSwitch (screen_info, screen_info->current_ws - 1, c);
            case KEY_MOVE_UP_WORKSPACE:
                workspaceMove (screen_info, -1, 0, c);
                break;
            case KEY_MOVE_DOWN_WORKSPACE:
                workspaceMove (screen_info, 1, 0, c);
                break;
            case KEY_MOVE_LEFT_WORKSPACE:
                workspaceMove (screen_info, 0, -1, c);
                break;
            case KEY_MOVE_RIGHT_WORKSPACE:
                workspaceMove (screen_info, 0, 1, c);
                break;
            case KEY_MOVE_WORKSPACE_1:
            case KEY_MOVE_WORKSPACE_2:
            case KEY_MOVE_WORKSPACE_3:
            case KEY_MOVE_WORKSPACE_4:
            case KEY_MOVE_WORKSPACE_5:
            case KEY_MOVE_WORKSPACE_6:
            case KEY_MOVE_WORKSPACE_7:
            case KEY_MOVE_WORKSPACE_8:
            case KEY_MOVE_WORKSPACE_9:
            case KEY_MOVE_WORKSPACE_10:
            case KEY_MOVE_WORKSPACE_11:
            case KEY_MOVE_WORKSPACE_12:
                clientRaise (c);
                workspaceSwitch (screen_info, key - KEY_MOVE_WORKSPACE_1, c);
        screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
        if (!screen_info)
        {
            return;
        }
        
        key = getKeyPressed (screen_info, ev);
        switch (key)
        {
            case KEY_CYCLE_WINDOWS:
                if (screen_info->clients)
                    clientCycle (screen_info->clients->prev, (XEvent *) ev);
    /* 
       Here we know that "screen_info" is defined, otherwise, we would 
       already have returned...
     */
        case KEY_NEXT_WORKSPACE:
            workspaceSwitch (screen_info, screen_info->current_ws + 1, NULL);
            break;
        case KEY_PREV_WORKSPACE:
            workspaceSwitch (screen_info, screen_info->current_ws - 1, NULL);
        case KEY_UP_WORKSPACE:
            workspaceMove(screen_info, -1, 0, NULL);
            break;
        case KEY_DOWN_WORKSPACE:
            workspaceMove(screen_info, 1, 0, NULL);
            break;
        case KEY_LEFT_WORKSPACE:
            workspaceMove(screen_info, 0, -1, NULL);
            break;
        case KEY_RIGHT_WORKSPACE:
            workspaceMove(screen_info, 0, 1, NULL);
            break;
        case KEY_ADD_WORKSPACE:
            workspaceSetCount (screen_info, screen_info->workspace_count + 1);
            break;
        case KEY_DEL_WORKSPACE:
            workspaceSetCount (screen_info, screen_info->workspace_count - 1);
            break;
        case KEY_WORKSPACE_1:
        case KEY_WORKSPACE_2:
        case KEY_WORKSPACE_3:
        case KEY_WORKSPACE_4:
        case KEY_WORKSPACE_5:
        case KEY_WORKSPACE_6:
        case KEY_WORKSPACE_7:
        case KEY_WORKSPACE_8:
        case KEY_WORKSPACE_9:
        case KEY_WORKSPACE_10:
        case KEY_WORKSPACE_11:
        case KEY_WORKSPACE_12:
            workspaceSwitch (screen_info, key - KEY_WORKSPACE_1, NULL);
            break;
        case KEY_SHORTCUT_1:
        case KEY_SHORTCUT_2:
        case KEY_SHORTCUT_3:
        case KEY_SHORTCUT_4:
        case KEY_SHORTCUT_5:
        case KEY_SHORTCUT_6:
        case KEY_SHORTCUT_7:
        case KEY_SHORTCUT_8:
        case KEY_SHORTCUT_9:
        case KEY_SHORTCUT_10:
        case KEY_SHORTCUT_11:
        case KEY_SHORTCUT_12:
            spawn_shortcut (screen_info, key - KEY_SHORTCUT_1);
        case KEY_SHOW_DESKTOP:
            toggle_show_desktop (screen_info);
            break;
/* User has clicked on an edge or corner.
 * Button 1 : Raise and resize
 * Button 2 : Move
 * Button 3 : Resize
 */
static void
edgeButton (Client * c, int part, XButtonEvent * ev)
    if (ev->button == Button2)
        XfwmButtonClickType tclick;
        ScreenInfo *screen_info = c->screen_info;
        tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, FALSE);
        if (tclick == XFWM_BUTTON_CLICK)
        {
            clientLower (c);
        }
        else if (tclick != XFWM_BUTTON_UNDEFINED)
        {
            moveRequest (c, (XEvent *) ev);
        }
        if (ev->button == Button1)
        {
            if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
            {
                clientSetFocus (c->screen_info, c, ev->time, NO_FOCUS_FLAG);
            clientRaise (c);
        }
        if ((ev->button == Button1) || (ev->button == Button3))
        {
            resizeRequest (c, part, (XEvent *) ev);
        }
static void
button1Action (Client * c, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    DisplayInfo *display_info = NULL;
    XEvent copy_event;
    XfwmButtonClickType tclick;

    g_return_if_fail (c != NULL);
    g_return_if_fail (ev != NULL);
    screen_info = c->screen_info;
    display_info = screen_info->display_info;

    if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
    {
        clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    memcpy(&copy_event, ev, sizeof(XEvent));
    tclick = typeOfClick (screen_info, c->window, &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 (screen_info->params->double_click_action)
        {
            case ACTION_MAXIMIZE:
                clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
                break;
            case ACTION_SHADE:
                clientToggleShaded (c);
                break;
            case ACTION_HIDE:
                if (CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientHide (c, c->win_workspace, TRUE);
                }
static void
titleButton (Client * c, int state, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    DisplayInfo *display_info = NULL;
    g_return_if_fail (c != NULL);
    g_return_if_fail (ev != NULL);

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

        XEvent copy_event;
        XfwmButtonClickType tclick;

        memcpy(&copy_event, ev, sizeof(XEvent));
        tclick = typeOfClick (screen_info, c->window, &copy_event, FALSE);

        if (tclick == XFWM_BUTTON_DRAG)
        {
            moveRequest (c, (XEvent *) ev);
        }
        else if (tclick != XFWM_BUTTON_UNDEFINED)
            if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
            {
                clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
            }
            if (screen_info->params->raise_on_click)
            {
                clientRaise (c);
            }
            ev->window = ev->root;
            if (screen_info->button_handler_id)
                g_signal_handler_disconnect (GTK_OBJECT (myScreenGetGtkWidget (screen_info)), screen_info->button_handler_id);
            screen_info->button_handler_id = g_signal_connect (GTK_OBJECT (myScreenGetGtkWidget (screen_info)),
                                                      "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 (state == AltMask)
        {
            clientIncOpacity(c);
        }
        else if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
    else if (ev->button == Button5)
        /* Mouse wheel scroll down */

        if (state == AltMask)
        {
            clientDecOpacity(c);
        }
        else if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
static void
rootScrollButton (DisplayInfo *display_info, XButtonEvent * ev)
{
    static Time lastscroll = (Time) 0;
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
        /* Too many events in too little time, drop this event... */
        return;
    
    /* Get the screen structure from the root of the event */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    }

        workspaceSwitch (screen_info, screen_info->current_ws - 1, NULL);
        workspaceSwitch (screen_info, screen_info->current_ws + 1, NULL);
static void
handleButtonPress (DisplayInfo *display_info, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    Window win;
Olivier Fourdan's avatar
Olivier Fourdan committed

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

    /* Avoid treating the same event twice */
    if (!check_button_time (ev))
    {
        TRACE ("ignoring ButtonPress event because it has been already handled");
        return;
    }
    c = myDisplayGetClientFromWindow (display_info, ev->window, ANY);
        state = ev->state & MODIFIER_MASK;
        screen_info = c->screen_info;
        if ((ev->button == Button1) && (state == AltMask) && (screen_info->params->easy_click))
        else if ((ev->button == Button2) && (state == AltMask) && (screen_info->params->easy_click))
        else if ((ev->button == Button3) && (state == AltMask) && (screen_info->params->easy_click))
            if ((ev->x < c->width / 2) && (ev->y < c->height / 2))
            {
                edgeButton (c, CORNER_TOP_LEFT, ev);
            }
            else if ((ev->x < c->width / 2) && (ev->y > c->height / 2))
            {
                edgeButton (c, CORNER_BOTTOM_LEFT, ev);
            }
            else if ((ev->x > c->width / 2) && (ev->y < c->height / 2))
            {
                edgeButton (c, CORNER_TOP_RIGHT, ev);
            }
            else
            {
                edgeButton (c, CORNER_BOTTOM_RIGHT, ev);
            }
        }
        else if (WIN_IS_BUTTON (win))
        {
            if (ev->button <= Button3)
            {
                if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
                {
                    clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
                }
                if (screen_info->params->raise_on_click)
                    /* Clear timeout */
                    clear_timeout ();
                    clientRaise (c);
                }
                clientButtonPress (c, win, ev);
            }
        }
        else if (win == MYWINDOW_XWINDOW (c->title))
        {
            titleButton (c, state, ev);
        }
        else if (win == MYWINDOW_XWINDOW (c->buttons[MENU_BUTTON]))
        {
            if (ev->button == Button1)
            {
                /*
                   We need to copy the event to keep the original event untouched
                   for gtk to handle it (in case we open up the menu)
                 */

Olivier Fourdan's avatar
Olivier Fourdan committed
                XEvent copy_event;
                XfwmButtonClickType tclick;

Olivier Fourdan's avatar
Olivier Fourdan committed
                memcpy(&copy_event, ev, sizeof(XEvent));
                tclick = typeOfClick (screen_info, c->window, &copy_event, TRUE);

                if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
                {
                    clientClose (c);
                }
                else if (tclick != XFWM_BUTTON_UNDEFINED)
                    if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
                    {
                        clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
                    }
                    if (screen_info->params->raise_on_click)
                        clientRaise (c);
                    }
                    ev->window = ev->root;
                    if (screen_info->button_handler_id)
                        g_signal_handler_disconnect (GTK_OBJECT (myScreenGetGtkWidget (screen_info)), screen_info->button_handler_id);
                    screen_info->button_handler_id = g_signal_connect (GTK_OBJECT (myScreenGetGtkWidget (screen_info)),
                                                              "button_press_event", GTK_SIGNAL_FUNC (show_popup_cb), (gpointer) c);
                    /* Let GTK handle this for us. */
                }
            }
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_TOP_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_TOP_RIGHT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_BOTTOM_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_BOTTOM_RIGHT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_BOTTOM, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, 4 + SIDE_RIGHT, ev);
        }
            clientPassGrabMouseButton (c);
            if ((screen_info->params->raise_with_any_button) || (ev->button == Button1))
                if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
                {
                    clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
                }
                if ((screen_info->params->raise_on_click) || 
                    !FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER))
                    /* Clear timeout */
                    clear_timeout ();
            XAllowEvents (display_info->dpy, ReplayPointer, ev->time);
            XAllowEvents (display_info->dpy, SyncPointer, ev->time);

        return;
    }

    /* 
       The event did not occur in one of our known good client...
       Get the screen structure from the root of the event.
     */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    if ((ev->window == screen_info->xroot) && (screen_info->params->scroll_workspaces)
            && ((ev->button == Button4) || (ev->button == Button5)))
        rootScrollButton (display_info, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else
    {
        XUngrabPointer (display_info->dpy, CurrentTime);
        XSendEvent (display_info->dpy, screen_info->gnome_win, FALSE, SubstructureNotifyMask, (XEvent *) ev);
static void
handleButtonRelease (DisplayInfo *display_info, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleButtonRelease");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Avoid treating the same event twice */
    if (!check_button_time (ev))
    {
        TRACE ("ignoring ButtonRelease event because it has been already handled");
        return;
    }
    /* Get the screen structure from the root of the event */
    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    }

    XSendEvent (display_info->dpy, screen_info->gnome_win, FALSE, SubstructureNotifyMask, (XEvent *) ev);
static void
handleDestroyNotify (DisplayInfo *display_info, XDestroyWindowEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleDestroyNotify");
    TRACE ("DestroyNotify on window (0x%lx)", ev->window);
    screen_info = myDisplayGetScreenFromSystray (display_info, ev->window);
    if  (screen_info)
        /* systray window is gone */
        screen_info->systray = None;
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        TRACE ("DestroyNotify for \"%s\" (0x%lx)", c->name, c->window);
        clientPassFocus (c->screen_info, c, c);
        clientUnframe (c, FALSE);
static void
handleMapRequest (DisplayInfo *display_info, XMapRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

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

Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("Mapping None ???");
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        ScreenInfo *screen_info = c->screen_info;

Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientShow");
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
        {
            TRACE ("Ignoring MapRequest on window (0x%lx)", ev->window);
            return;
        }
        if (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY) ||
            (c->win_workspace == screen_info->current_ws))
Olivier Fourdan's avatar
Olivier Fourdan committed
        {
            clientFocusNew(c);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("handleMapRequest: clientFrame");
        clientFrame (display_info, ev->window, FALSE);
static void
handleMapNotify (DisplayInfo *display_info, XMapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleMapNotify");
    TRACE ("MapNotify on window (0x%lx)", ev->window);
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (c)
    {
        TRACE ("MapNotify for \"%s\" (0x%lx)", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
Olivier Fourdan's avatar
Olivier Fourdan committed
            FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_MAP_PENDING);
        compositorMapWindow (display_info, c->frame);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else if (myDisplayGetScreenFromRoot (display_info, ev->event))
    {
        compositorMapWindow (display_info, ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
static void
handleUnmapNotify (DisplayInfo *display_info, XUnmapEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    Client *c = NULL;

    TRACE ("entering handleUnmapNotify");
    TRACE ("UnmapNotify on window (0x%lx)", ev->window);
        TRACE ("Ignoring UnmapNotify caused by parent's resize");
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (screen_info && (ev->event != ev->window) && (ev->event != screen_info->xroot || !ev->send_event))
        TRACE ("handleUnmapNotify (): Event ignored");
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
    if (c)
    {
        TRACE ("UnmapNotify for \"%s\" (0x%lx)", c->name, c->window);
        TRACE ("ignore_unmap for \"%s\" is %i", c->name, c->ignore_unmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_MAP_PENDING))
             * This UnmapNotify event is caused by reparenting
             * so we just ignore it, so the window won't return 
             * to withdrawn state by mistake.
             */
            TRACE ("Client \"%s\" is not mapped, event ignored", c->name);
Olivier Fourdan's avatar
Olivier Fourdan committed
        screen_info = c->screen_info;
        clientPassFocus (screen_info, c, c);
        compositorUnmapWindow (display_info, c->frame);
        
        /*
         * ICCCM spec states that a client wishing to switch
         * to WithdrawnState should send a synthetic UnmapNotify 
         * with the event field set to root if the client window 
         * is already unmapped.
         * Therefore, bypass the ignore_unmap counter and
         * unframe the client.
         */
        if ((ev->event == screen_info->xroot) && (ev->send_event))
        {
            TRACE ("ICCCM UnmapNotify for \"%s\"", c->name);
            clientUnframe (c, FALSE);
            return;
        }
        if (c->ignore_unmap)
        {
            c->ignore_unmap--;
            TRACE ("ignore_unmap for \"%s\" is now %i", 
Olivier Fourdan's avatar
Olivier Fourdan committed
            TRACE ("unmapping \"%s\" as ignore_unmap is %i", 
                 c->name, c->ignore_unmap);
            clientUnframe (c, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
    else
    {
        compositorUnmapWindow (display_info, ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
static void
handleConfigureNotify (DisplayInfo *display_info, XConfigureEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    TRACE ("entering handleConfigureNotify");

    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (!screen_info)
    {
        return;
    }
    
    if (ev->window == screen_info->xroot)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("ConfigureNotify on the screen_info->xroot win (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
#ifdef HAVE_RANDR
        XRRUpdateConfiguration (ev);
#else
        screen_info->xscreen->width   = ev->width;
        screen_info->xscreen->height  = ev->height;
Olivier Fourdan's avatar
Olivier Fourdan committed
#endif
        placeSidewalks (screen_info, screen_info->params->wrap_workspaces);
        clientScreenResize (screen_info);
static void
handleConfigureRequest (DisplayInfo *display_info, XConfigureRequestEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    XWindowChanges wc;
Olivier Fourdan's avatar
Olivier Fourdan committed
    XEvent otherEvent;
Olivier Fourdan's avatar
Olivier Fourdan committed

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

Olivier Fourdan's avatar
Olivier Fourdan committed
    /* Compress events - logic taken from kwin */
    while (XCheckTypedWindowEvent (display_info->dpy, ev->window, ConfigureRequest, &otherEvent))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        /* Update the display time */
        myDisplayUpdateCurentTime (display_info, &otherEvent);

        if (otherEvent.xconfigurerequest.value_mask == ev->value_mask)
        {
            ev = &otherEvent.xconfigurerequest;
        }
        else
        {
            XPutBackEvent (display_info->dpy, &otherEvent);
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 = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        /* Some app tend or try to manipulate the wm frame to achieve fullscreen mode */
        c = myDisplayGetClientFromWindow (display_info, ev->window, FRAME);
            TRACE ("client %s (0x%lx) is attempting to manipulate its frame!", c->name, c->window);
            if (ev->value_mask & CWX)
            {
                wc.x += frameLeft (c);
            }
            if (ev->value_mask & CWY)
            {
                wc.y += frameTop (c);
            }
            if (ev->value_mask & CWWidth)
            {
                wc.width -= frameLeft (c) + frameRight (c);
            }
            if (ev->value_mask & CWHeight)
            {
                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);
        }
        gboolean constrained = FALSE;
        ScreenInfo *screen_info = c->screen_info;
        TRACE ("handleConfigureRequest managed window \"%s\" (0x%lx)", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (FLAG_TEST (c->xfwm_flags, XFWM_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 (FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
        {
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            int cx, cy;

            /* size request from fullscreen windows get fullscreen */
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            cx = frameX (c) + (frameWidth (c) / 2);
            cy = frameY (c) + (frameHeight (c) / 2);

            monitor_nbr = find_monitor_at_point (screen_info->gscr, cx, cy);
            gdk_screen_get_monitor_geometry (screen_info->gscr, monitor_nbr, &rect);

            wc.x = rect.x;
            wc.y = rect.y;
            wc.width = rect.width;
            wc.height = rect.height;
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed

            ev->value_mask |= (CWX | CWY | CWWidth | CWHeight);
        }
        /* Clean up buggy requests that set all flags */
        if ((ev->value_mask & CWX) && (wc.x == c->x))
        {
            ev->value_mask &= ~CWX;
        }
        if ((ev->value_mask & CWY) && (wc.y == c->y))
        {
            ev->value_mask &= ~CWY;
        }
        if ((ev->value_mask & CWWidth) && (wc.width == c->width))
        {
            ev->value_mask &= ~CWWidth;
        }
        if ((ev->value_mask & CWHeight) && (wc.height == c->height))
        {
            ev->value_mask &= ~CWHeight;
        }
        /* Still a move/resize after cleanup? */
        if (ev->value_mask & (CWX | CWY | CWWidth | CWHeight))
        {
            if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
            {
                clientRemoveMaximizeFlag (c);
            }
            constrained = TRUE;
        }
        if (ev->value_mask & CWStackMode)
        {
        /* 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))
        {
            if ((c->win_workspace == screen_info->current_ws) || 
                (FLAG_TEST (c->flags, CLIENT_FLAG_STICKY)))
                if (FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED))
        clientConfigure (c, &wc, ev->value_mask, (constrained ? CFG_CONSTRAINED : 0) | CFG_REQUEST);
        TRACE ("unmanaged configure request for win 0x%lx", ev->window);
        XConfigureWindow (display_info->dpy, ev->window, ev->value_mask, &wc);
static void
handleEnterNotify (DisplayInfo *display_info, XCrossingEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

    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 ("EnterNotify on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = myDisplayGetClientFromWindow (display_info, ev->window, FRAME);
    if (c)
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
        ScreenInfo *screen_info = NULL;
        
        screen_info = c->screen_info;
        
        if (!(screen_info->params->click_to_focus) && clientAcceptFocus (c))
            TRACE ("EnterNotify window is \"%s\"", c->name);
            if (!(c->type & (WINDOW_DOCK | WINDOW_DESKTOP)))
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientSetFocus (c->screen_info, c, ev->time, NO_FOCUS_FLAG);
static void
handleLeaveNotify (DisplayInfo *display_info, XCrossingEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    TRACE ("entering handleLeaveNotify");
    if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab)
        || (ev->detail > NotifyNonlinearVirtual))
    {
        /* We're not interested in such notifications */
        return;
    }

    screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!screen_info)
    {
        return;
    }
    
    if ((ev->window == MYWINDOW_XWINDOW (screen_info->sidewalk[0])) || 
        (ev->window == MYWINDOW_XWINDOW (screen_info->sidewalk[1])) ||
        (ev->window == MYWINDOW_XWINDOW (screen_info->sidewalk[2])) ||
        (ev->window == MYWINDOW_XWINDOW (screen_info->sidewalk[3])))
        TRACE ("Reset edge_scroll_x and edge_scroll_y");
static void
handleFocusIn (DisplayInfo *display_info, XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
    Client *last_raised = NULL;
        
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleFocusIn");
    TRACE ("handleFocusIn (0x%lx) mode = %s",
Olivier Fourdan's avatar
Olivier Fourdan committed
                ev->window,
                (ev->mode == NotifyNormal) ?
                "NotifyNormal" :
                (ev->mode == NotifyWhileGrabbed) ?
                "NotifyWhileGrabbed" :
                "(unknown)");
    TRACE ("handleFocusIn (0x%lx) detail = %s",
Olivier Fourdan's avatar
Olivier Fourdan committed
                ev->window,
                (ev->detail == NotifyAncestor) ?
                "NotifyAncestor" :
                (ev->detail == NotifyVirtual) ?
                "NotifyVirtual" :
                (ev->detail == NotifyInferior) ?
                "NotifyInferior" :
                (ev->detail == NotifyNonlinear) ?
                "NotifyNonlinear" :
                (ev->detail == NotifyNonlinearVirtual) ?
                "NotifyNonlinearVirtual" :
                (ev->detail == NotifyPointer) ?
                "NotifyPointer" :
                (ev->detail == NotifyPointerRoot) ?
                "NotifyPointerRoot" :
                (ev->detail == NotifyDetailNone) ?
                "NotifyDetailNone" :
                "(unknown)");
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (screen_info && (ev->window == screen_info->xroot) && (ev->mode == NotifyNormal) && 
        /* Handle focus transition to root (means that an unknown
           window has vanished and the focus is returned to the root
            clientSetFocus (c->screen_info, c, myDisplayGetCurrentTime (display_info), FOCUS_FORCE);
    
    if ((ev->mode == NotifyGrab) || (ev->mode == NotifyUngrab) ||
        /* We're not interested in such notifications */
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
    TRACE ("FocusIn on window (0x%lx)", ev->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("focus set to \"%s\" (0x%lx)", c->name, c->window);
        screen_info = c->screen_info;
        clientUpdateFocus (screen_info, c, FOCUS_SORT);
        last_raised = clientGetLastRaise (screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed
        if ((screen_info->params->click_to_focus) && 
            (screen_info->params->raise_on_click) && 
            (last_raised != NULL) && (c != last_raised))
        if (screen_info->params->raise_on_focus)
            reset_timeout (screen_info);
static void
handleFocusOut (DisplayInfo *display_info, XFocusChangeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering handleFocusOut");
Olivier Fourdan's avatar
Olivier Fourdan committed
    TRACE ("handleFocusOut (0x%lx) mode = %s",
                ev->window,
                (ev->mode == NotifyNormal) ?
                "NotifyNormal" :
                (ev->mode == NotifyWhileGrabbed) ?
                "NotifyWhileGrabbed" :
                "(unknown)");
    TRACE ("handleFocusOut (0x%lx) detail = %s",
                ev->window,
                (ev->detail == NotifyAncestor) ?
                "NotifyAncestor" :
                (ev->detail == NotifyVirtual) ?
                "NotifyVirtual" :
                (ev->detail == NotifyInferior) ?
                "NotifyInferior" :
                (ev->detail == NotifyNonlinear) ?
                "NotifyNonlinear" :
                (ev->detail == NotifyNonlinearVirtual) ?
                "NotifyNonlinearVirtual" :
                (ev->detail == NotifyPointer) ?
                "NotifyPointer" :
                (ev->detail == NotifyPointerRoot) ?
                "NotifyPointerRoot" :
                (ev->detail == NotifyDetailNone) ?
                "NotifyDetailNone" :
                "(unknown)");
    if ((ev->mode == NotifyNormal)
        && ((ev->detail == NotifyNonlinear) 
            || (ev->detail == NotifyNonlinearVirtual)))
        c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        TRACE ("FocusOut on window (0x%lx)", ev->window);
        {
            TRACE ("focus lost from \"%s\" (0x%lx)", c->name, c->window);
            clientUpdateFocus (c->screen_info, NULL, NO_FOCUS_FLAG);
            /* Clear timeout */
            clear_timeout ();
        }
static void
handlePropertyNotify (DisplayInfo *display_info, XPropertyEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handlePropertyNotify");

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        if (ev->atom == XA_WM_NORMAL_HINTS)
        {
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_NORMAL_HINTS notify", c->name, c->window);
            clientGetWMNormalHints (c, TRUE);
        else if ((ev->atom == XA_WM_NAME) || (ev->atom == display_info->atoms[NET_WM_NAME]))
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_NAME notify", c->name, c->window);
            getWindowName (display_info, c->window, &c->name);
            FLAG_SET (c->flags, CLIENT_FLAG_NAME_CHANGED);
            frameDraw (c, TRUE, FALSE);
        }
        else if (ev->atom == display_info->atoms[MOTIF_WM_HINTS])
            TRACE ("client \"%s\" (0x%lx) has received a motif_wm_hints notify", c->name, c->window);
            clientGetMWMHints (c, TRUE);
        }
        else if (ev->atom == XA_WM_HINTS)
        {
            TRACE ("client \"%s\" (0x%lx) has received a XA_WM_HINTS notify", c->name, c->window);
            c->wmhints = XGetWMHints (display_info->dpy, c->window);
                if (c->wmhints->flags & WindowGroupHint)
                {
                    c->group_leader = c->wmhints->window_group;
                }
            clientUpdateUrgency (c);
        else if (ev->atom == display_info->atoms[WM_PROTOCOLS])
            TRACE ("client \"%s\" (0x%lx) has received a wm_protocols notify", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientGetWMProtocols (c);
        }
        else if (ev->atom == display_info->atoms[WM_TRANSIENT_FOR])
        {
            TRACE ("client \"%s\" (0x%lx) has received a wm_transient_for notify", c->name, c->window);
            getTransientFor (display_info, c->screen_info->xroot, c->window, &w);
            if (clientCheckTransientWindow (c, w))
            {
                c->transient_for = w;
                clientRaise (c);
            }
        }
        else if (ev->atom == display_info->atoms[WIN_HINTS])
            TRACE ("client \"%s\" (0x%lx) has received a win_hints notify", c->name, c->window);
            getHint (display_info, c->window, WIN_HINTS, &c->win_hints);
        else if (ev->atom == display_info->atoms[NET_WM_WINDOW_TYPE])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_window_type notify", c->name, c->window);
            clientGetNetWmType (c);
            frameDraw (c, TRUE, FALSE);
        }
        else if ((ev->atom == display_info->atoms[NET_WM_STRUT]) || 
                 (ev->atom == display_info->atoms[NET_WM_STRUT_PARTIAL]))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_strut notify", c->name, c->window);
        else if (ev->atom == display_info->atoms[WM_COLORMAP_WINDOWS])
            TRACE ("client \"%s\" (0x%lx) has received a wm_colormap_windows notify", c->name, c->window);
            clientUpdateColormaps (c);
            if (c == clientGetFocus ())
            {
                clientInstallColormaps (c);
            }
        }
        else if (ev->atom == display_info->atoms[NET_WM_USER_TIME])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_user_time notify", c->name, c->window);
            if (getNetWMUserTime (display_info, c->window, &c->user_time))
                FLAG_SET (c->flags, CLIENT_FLAG_HAS_USER_TIME);
        else if (ev->atom == display_info->atoms[NET_WM_WINDOW_OPACITY])
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_opacity notify", c->name, c->window);
            if (!getOpacity (display_info, c->window, &c->opacity))
                c->opacity =  NET_WM_OPAQUE;
            compositorWindowSetOpacity (display_info, c->frame, c->opacity);
#ifdef HAVE_STARTUP_NOTIFICATION
        else if (ev->atom == display_info->atoms[NET_STARTUP_ID])
        {
            if (c->startup_id)
            {
                free (c->startup_id);
                c->startup_id = NULL;
            }
            getWindowStartupId (display_info, c->window, &c->startup_id);
        return;
    }
    
    screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
    if (!screen_info)
    {
        return;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    if (ev->atom == display_info->atoms[NET_DESKTOP_NAMES])
    {
        TRACE ("root has received a net_desktop_names notify");
        if (getUTF8String (display_info, screen_info->xroot, NET_DESKTOP_NAMES, &names, &length))
            workspaceSetNames (screen_info, names, length);
    else if (ev->atom == display_info->atoms[GNOME_PANEL_DESKTOP_AREA])
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        TRACE ("root has received a gnome_panel_desktop_area notify");
        getGnomeDesktopMargins (display_info, screen_info->xroot, screen_info->gnome_margins);
        workspaceUpdateArea (screen_info);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
    else if (ev->atom == display_info->atoms[NET_DESKTOP_LAYOUT])
    {
        TRACE ("root has received a net_desktop_layout notify");
        getDesktopLayout(display_info, screen_info->xroot, screen_info->workspace_count, &screen_info->desktop_layout);
static void
handleClientMessage (DisplayInfo *display_info, XClientMessageEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    ScreenInfo *screen_info = NULL;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean is_transient = FALSE;
Olivier Fourdan's avatar
Olivier Fourdan committed

    TRACE ("entering handleClientMessage");

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
        screen_info = c->screen_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
        is_transient = clientIsValidTransientOrModal (c);
        if ((ev->message_type == display_info->atoms[WM_CHANGE_STATE]) && (ev->format == 32) && (ev->data.l[0] == IconicState))
            TRACE ("client \"%s\" (0x%lx) has received a wm_change_state event", c->name, c->window);
            if (!FLAG_TEST (c->flags, CLIENT_FLAG_ICONIFIED) &&  CLIENT_CAN_HIDE_WINDOW (c))
            {
                clientHide (c, c->win_workspace, TRUE);
            }
        }
        else if ((ev->message_type == display_info->atoms[WIN_STATE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_state event", c->name, c->window);
            clientUpdateWinState (c, ev);
        }
        else if ((ev->message_type == display_info->atoms[WIN_LAYER]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_layer event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if ((ev->data.l[0] != c->win_layer) && !is_transient)
            {
                clientSetLayer (c, ev->data.l[0]);
            }
        }
        else if ((ev->message_type == display_info->atoms[WIN_WORKSPACE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a win_workspace event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if ((ev->data.l[0] != c->win_workspace) && !is_transient)
            {
                clientSetWorkspace (c, ev->data.l[0], TRUE);
            }
        }
        else if ((ev->message_type == display_info->atoms[NET_WM_DESKTOP]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_desktop event", c->name, c->window);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (!is_transient)
            {
                if (ev->data.l[0] == ALL_WORKSPACES)
                {
                    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK) && !FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
                    {
                        clientStick (c, TRUE);
                        frameDraw (c, FALSE, FALSE);
                    }
                }
                else
                {
                    if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_STICK) && FLAG_TEST (c->flags, CLIENT_FLAG_STICKY))
                    {
                        clientUnstick (c, TRUE);
                        frameDraw (c, FALSE, FALSE);
                    }
                    if (ev->data.l[0] != c->win_workspace)
                    {
                        clientSetWorkspace (c, ev->data.l[0], TRUE);
                    }
                }
            }
        }
        else if ((ev->message_type == display_info->atoms[NET_CLOSE_WINDOW]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_close_window event", c->name, c->window);
        else if ((ev->message_type == display_info->atoms[NET_WM_STATE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_state event", c->name, c->window);
            clientUpdateNetState (c, ev);
        }
        else if ((ev->message_type == display_info->atoms[NET_WM_MOVERESIZE]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_wm_moveresize event", c->name, c->window);
            g_warning ("Operation not supported (yet)");
        else if ((ev->message_type == display_info->atoms[NET_ACTIVE_WINDOW]) && (ev->format == 32))
            TRACE ("client \"%s\" (0x%lx) has received a net_active_window event", c->name, c->window);
            clientSetWorkspace (c, screen_info->current_ws, TRUE);
            clientShow (c, TRUE);
            clientRaise (c);
            if (ev->data.l[0] != 0)
            {
                clientSetFocus (screen_info, c, (Time) ev->data.l[1], NO_FOCUS_FLAG);
            }
            else
            {
                clientSetFocus (screen_info, c, CurrentTime, NO_FOCUS_FLAG);
            }
        else if (ev->message_type == display_info->atoms[NET_REQUEST_FRAME_EXTENTS])
        {
            TRACE ("client \"%s\" (0x%lx) has received a net_request_frame_extents event", c->name, c->window);
            setNetFrameExtents (display_info, c->window, frameTop (c), frameLeft (c),
                                                         frameRight (c), frameBottom (c)); 
        screen_info = myDisplayGetScreenFromWindow (display_info, ev->window);
        if (!screen_info)
        {
            return;
        }
        
        if (((ev->message_type == display_info->atoms[WIN_WORKSPACE]) || 
             (ev->message_type == display_info->atoms[NET_CURRENT_DESKTOP])) && (ev->format == 32))
            TRACE ("root has received a win_workspace or a net_current_desktop event");
            if (ev->data.l[0] != screen_info->current_ws)
                workspaceSwitch (screen_info, ev->data.l[0], NULL);
        else if (((ev->message_type == display_info->atoms[WIN_WORKSPACE_COUNT]) || 
                  (ev->message_type == display_info->atoms[NET_NUMBER_OF_DESKTOPS])) && (ev->format == 32))
        {
            TRACE ("root has received a win_workspace_count event");
            if (ev->data.l[0] != screen_info->workspace_count)
                workspaceSetCount (screen_info, ev->data.l[0]);
                getDesktopLayout(display_info, screen_info->xroot, screen_info->workspace_count, &screen_info->desktop_layout);
        else if ((ev->message_type == display_info->atoms[MANAGER]) && (ev->data.l[1] == screen_info->net_system_tray_selection) && (ev->format == 32))
        {
            TRACE ("root has received a net_system_tray_manager event");
            screen_info->systray = getSystrayWindow (display_info, screen_info->net_system_tray_selection);
        else if ((ev->message_type == display_info->atoms[NET_SHOWING_DESKTOP]) && (ev->format == 32))
        {
            TRACE ("root has received a net_showing_desktop event");
            clientToggleShowDesktop (screen_info, ev->data.l[0]);
            setHint (display_info, screen_info->xroot, NET_SHOWING_DESKTOP, ev->data.l[0]);
        else if (ev->message_type == display_info->atoms[NET_REQUEST_FRAME_EXTENTS])
        {
            TRACE ("window (0x%lx) has received a net_request_frame_extents event", c->name, ev->window);
            /* Size estimate from the decoration extents */
            setNetFrameExtents (display_info, ev->window, 
                                frameDecorationTop (screen_info),
                                frameDecorationLeft (screen_info),
                                frameDecorationRight (screen_info),
                                frameDecorationBottom (screen_info));
        }
            TRACE ("unidentified client message for window 0x%lx", ev->window);
static void
handleShape (DisplayInfo *display_info, XShapeEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed

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

    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        frameDraw (c, FALSE, TRUE);
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    compositorUpdateWindow (display_info, ev->window, 
                                          ev->width + ev->x, 
                                          ev->height + ev->y, 
                                          (ev->kind == ShapeBounding));
static void
handleColormapNotify (DisplayInfo *display_info, XColormapEvent * ev)
    TRACE ("entering handleColormapNotify");
    c = myDisplayGetClientFromWindow (display_info, ev->window, WINDOW);
    if ((c) && (ev->window == c->window) && (ev->new))
        if (c == clientGetFocus ())
        {
            clientInstallColormaps (c);
        }
handleEvent (DisplayInfo *display_info, XEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    TRACE ("entering handleEvent");
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Update the display time */
    myDisplayUpdateCurentTime (display_info, ev);

Olivier Fourdan's avatar
Olivier Fourdan committed
    compositorHandleEvent (display_info, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
    switch (ev->type)
    {
            handleMotionNotify (display_info, (XMotionEvent *) ev);
            handleKeyPress (display_info, (XKeyEvent *) ev);
            handleButtonPress (display_info, (XButtonEvent *) ev);
            handleButtonRelease (display_info, (XButtonEvent *) ev);
            handleDestroyNotify (display_info, (XDestroyWindowEvent *) ev);
            handleUnmapNotify (display_info, (XUnmapEvent *) ev);
            handleMapRequest (display_info, (XMapRequestEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
        case MapNotify:
            handleMapNotify (display_info, (XMapEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
            break;
Olivier Fourdan's avatar
Olivier Fourdan committed
        case ConfigureNotify:
            handleConfigureNotify (display_info, (XConfigureEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
            break;
            handleConfigureRequest (display_info, (XConfigureRequestEvent *) ev);
            handleEnterNotify (display_info, (XCrossingEvent *) ev);
            handleLeaveNotify (display_info, (XCrossingEvent *) ev);
            handleFocusIn (display_info, (XFocusChangeEvent *) ev);
            handleFocusOut (display_info, (XFocusChangeEvent *) ev);
            handlePropertyNotify (display_info, (XPropertyEvent *) ev);
            handleClientMessage (display_info, (XClientMessageEvent *) ev);
            handleColormapNotify (display_info, (XColormapEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (display_info->have_shape && (ev->type == display_info->shape_event_base))
                handleShape (display_info, (XShapeEvent *) ev);
    if (!gdk_events_pending () && !XPending (display_info->dpy))
            reloadSettings (display_info, UPDATE_ALL);
xfwm4_event_filter (XEvent * xevent, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    DisplayInfo *display_info = (DisplayInfo *) data;
    g_assert (display_info);
    TRACE ("entering xfwm4_event_filter");
    handleEvent (display_info, xevent);
    TRACE ("leaving xfwm4_event_filter");
Olivier Fourdan's avatar
Olivier Fourdan committed
    return XEV_FILTER_STOP;
}

Olivier Fourdan's avatar
Olivier Fourdan committed

menu_callback (Menu * menu, MenuOp op, Window xid, gpointer menu_data, gpointer item_data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c = NULL;
    TRACE ("entering menu_callback");
    if (!xfwmWindowDeleted(&menu_event_window))
        xfwmWindowDelete (&menu_event_window);
    if ((menu_data != NULL) && (xid != None))
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
        ScreenInfo *screen_info = (ScreenInfo *) menu_data;
        c = clientGetFromWindow (screen_info, xid, WINDOW);
    }

    if (c)
    {
        c->button_pressed[MENU_BUTTON] = FALSE;

        switch (op)
            case MENU_OP_QUIT:
                gtk_main_quit ();
                break;
            case MENU_OP_MAXIMIZE:
            case MENU_OP_UNMAXIMIZE:
                if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
                {
                    clientToggleMaximized (c, WIN_STATE_MAXIMIZED);
                }
                break;
            case MENU_OP_MINIMIZE:
                if (CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientHide (c, c->win_workspace, TRUE);
                }
                frameDraw (c, FALSE, FALSE);
                break;
            case MENU_OP_MINIMIZE_ALL:
                clientHideAll (c, c->win_workspace);
                frameDraw (c, FALSE, FALSE);
                break;
            case MENU_OP_UNMINIMIZE:
                clientShow (c, TRUE);
                break;
            case MENU_OP_SHADE:
            case MENU_OP_UNSHADE:
                clientToggleShaded (c);
                break;
            case MENU_OP_STICK:
            case MENU_OP_UNSTICK:
                clientToggleSticky (c, TRUE);
                frameDraw (c, FALSE, FALSE);
                break;
            case MENU_OP_WORKSPACES:
                clientSetWorkspace (c, GPOINTER_TO_INT (item_data), TRUE);
                frameDraw (c, FALSE, FALSE);
                break;
            case MENU_OP_DELETE:
                frameDraw (c, FALSE, FALSE);
                clientClose (c);
                break;
            case MENU_OP_CONTEXT_HELP:
                clientEnterContextMenuState (c);
                frameDraw (c, FALSE, FALSE);
                break;
            case MENU_OP_ABOVE:
            case MENU_OP_NORMAL:
                clientToggleAbove (c);
                /* Fall thru */
            default:
                frameDraw (c, FALSE, FALSE);
                break;
Olivier Fourdan's avatar
Olivier Fourdan committed
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
    {
    xfwmWindowInit (&menu_event_window);
static gboolean
show_popup_cb (GtkWidget * widget, GdkEventButton * ev, gpointer data)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
    ScreenInfo *screen_info = NULL;
    DisplayInfo *display_info = NULL;
    Client *c = (Client *) data;
    TRACE ("entering show_popup_cb");

    if ((c) && ((ev->button == 1) || (ev->button == 3)))
        c->button_pressed[MENU_BUTTON] = TRUE;
        frameDraw (c, FALSE, FALSE);
        y = c->y;
Olivier Fourdan's avatar
Olivier Fourdan committed
        ops = MENU_OP_DELETE | MENU_OP_MINIMIZE_ALL | MENU_OP_WORKSPACES;
Olivier Fourdan's avatar
Olivier Fourdan committed
        if (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE))
        if (FLAG_TEST (c->flags, CLIENT_FLAG_MAXIMIZED))
        {
            ops |= MENU_OP_UNMAXIMIZE;
            if (!CLIENT_CAN_MAXIMIZE_WINDOW (c))
            {
                insensitive |= MENU_OP_UNMAXIMIZE;
            }
        }
        else
        {
Loading
Loading full blame...