Skip to content
Snippets Groups Projects
events.c 91.7 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
Olivier Fourdan's avatar
Olivier Fourdan committed
        Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
        MA 02110-1301, USA.

Olivier Fourdan's avatar
Olivier Fourdan committed
        oroborus - (c) 2001 Ken Lynch
Olivier Fourdan's avatar
Olivier Fourdan committed
        xfwm4    - (c) 2002-2011 Olivier Fourdan
Olivier Fourdan's avatar
Olivier Fourdan committed
 */

#ifdef HAVE_CONFIG_H
Olivier Fourdan's avatar
Olivier Fourdan committed
#include "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>
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"
#include "moveresize.h"
#include "cycle.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 DOUBLE_CLICK_GRAB       (ButtonMotionMask | \
                                 PointerMotionMask | \
                                 ButtonPressMask | \
                                 ButtonReleaseMask)
Olivier Fourdan's avatar
Olivier Fourdan committed
static GdkAtom atom_rcfiles = GDK_NONE;
static xfwmWindow menu_event_window;
Olivier Fourdan's avatar
Olivier Fourdan committed

static eventFilterStatus handleEvent (DisplayInfo *display_info,
                                      XEvent * ev);
static void menu_callback            (Menu * menu,
                                      MenuOp op,
                                      Window xid,
                                      gpointer menu_data,
                                      gpointer item_data);
static void show_window_menu         (Client *c,
                                      gint px,
                                      gint py,
                                      guint button,
                                      guint32 time);
static gboolean show_popup_cb        (GtkWidget * widget,
                                      GdkEventButton * ev,
                                      gpointer data);
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;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gint  x0;
    gint  y0;
    guint t0;
    gint  xcurrent;
    gint  ycurrent;
    guint tcurrent;
    gint  double_click_time;
    gint  double_click_distance;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean allow_double_click;
static gboolean
typeOfClick_end (gpointer data)
{
    XfwmButtonClickData *passdata;

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

    gtk_main_quit ();

    return (FALSE);
}

static eventFilterStatus
typeOfClick_event_filter (XEvent * xevent, gpointer data)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    XfwmButtonClickData *passdata;
    eventFilterStatus status;
Olivier Fourdan's avatar
Olivier Fourdan committed
    guint32 timestamp;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean keep_going;

    keep_going = TRUE;
    passdata = (XfwmButtonClickData *) data;
Olivier Fourdan's avatar
Olivier Fourdan committed

    /* Update the display time */
Olivier Fourdan's avatar
Olivier Fourdan committed
    timestamp = myDisplayUpdateCurrentTime (passdata->display_info, xevent);
Olivier Fourdan's avatar
Olivier Fourdan committed
    if (timestamp)
Olivier Fourdan's avatar
Olivier Fourdan committed
        passdata->tcurrent = timestamp;
        if (((gint) passdata->tcurrent - (gint) passdata->t0) > passdata->double_click_time)
        {
            keep_going = FALSE;
        }
    }
    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;

        if ((ABS (passdata->x0 - passdata->xcurrent) > passdata->double_click_distance) ||
            (ABS (passdata->y0 - passdata->ycurrent) > passdata->double_click_distance))
        {
            keep_going = FALSE;
        }
        status = EVENT_FILTER_STOP;
    }
    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;
        }
    }

Olivier Fourdan's avatar
Olivier Fourdan committed
        TRACE ("click type=%u", passdata->clicks);
        TRACE ("time=%ims (timeout=%ims)", (gint) passdata->tcurrent - (gint) passdata->t0, passdata->double_click_time);
        TRACE ("dist x=%i (max=%i)", ABS (passdata->x0 - passdata->xcurrent), passdata->double_click_distance);
        TRACE ("dist y=%i (max=%i)", ABS (passdata->y0 - passdata->ycurrent), passdata->double_click_distance);
static XfwmButtonClickType
typeOfClick (ScreenInfo *screen_info, Window w, XEvent * ev, gboolean allow_double_click)
Olivier Fourdan's avatar
Olivier Fourdan committed
    DisplayInfo *display_info;
    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;
    g = myScreenGrabPointer (screen_info, DOUBLE_CLICK_GRAB, None, ev->xbutton.time);

    if (!g)
    {
        TRACE ("grab failed in typeOfClick");
        gdk_beep ();
        myScreenUngrabPointer (screen_info, ev->xbutton.time);
        return XFWM_BUTTON_UNDEFINED;
    }

    passdata.display_info = display_info;
    passdata.button = ev->xbutton.button;
    passdata.w = w;
Olivier Fourdan's avatar
Olivier Fourdan committed
    passdata.x0 = ev->xbutton.x_root;
    passdata.y0 = ev->xbutton.y_root;
    passdata.t0 = ev->xbutton.time;
    passdata.xcurrent = passdata.x0;
    passdata.ycurrent = passdata.y0;
    passdata.tcurrent = passdata.t0;
    passdata.clicks = 1;
    passdata.allow_double_click = allow_double_click;
Olivier Fourdan's avatar
Olivier Fourdan committed
    passdata.double_click_time = display_info->double_click_time;
    passdata.double_click_distance = display_info->double_click_distance;
    TRACE ("Double click time= %i, distance=%i\n", display_info->double_click_time,
                                                   display_info->double_click_distance);
    passdata.timeout = g_timeout_add_full (G_PRIORITY_HIGH,
                                           display_info->double_click_time,
                                           (GSourceFunc) typeOfClick_end,
                                           (gpointer) &passdata, NULL);

    eventFilterPush (display_info->xfilter, typeOfClick_event_filter, &passdata);
    eventFilterPop (display_info->xfilter);
    myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info));

    return (XfwmButtonClickType) passdata.clicks;
static void
toggle_show_desktop (ScreenInfo *screen_info)
{
    screen_info->show_desktop = !screen_info->show_desktop;
    setHint (screen_info->display_info, screen_info->xroot, NET_SHOWING_DESKTOP,
             screen_info->show_desktop);
    sendRootMessage (screen_info, NET_SHOWING_DESKTOP, screen_info->show_desktop,
                     myDisplayGetCurrentTime (screen_info->display_info));
handleMotionNotify (DisplayInfo *display_info, XMotionEvent * ev)
    TRACE ("entering handleMotionNotify");
handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
    Client *c;
    ev_screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
    if (!ev_screen_info)
    {
        return EVENT_FILTER_PASS;
    status = EVENT_FILTER_PASS;
    c = clientGetFocus ();
        screen_info = c->screen_info;
        key = myScreenGetKeyPressed (screen_info, ev);
        status = EVENT_FILTER_REMOVE;
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientMove (c, (XEvent *) ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
                clientResize (c, CORNER_BOTTOM_RIGHT, (XEvent *) ev);
                break;
            case KEY_CYCLE_WINDOWS:
                clientCycle (c, ev);
                break;
            case KEY_CLOSE_WINDOW:
                clientClose (c);
                break;
            case KEY_HIDE_WINDOW:
Olivier Fourdan's avatar
Olivier Fourdan committed
                if (CLIENT_CAN_HIDE_WINDOW (c))
                    clientWithdraw (c, c->win_workspace, TRUE);
                break;
            case KEY_MAXIMIZE_WINDOW:
                clientToggleMaximized (c, CLIENT_FLAG_MAXIMIZED, TRUE);
                break;
            case KEY_MAXIMIZE_VERT:
                clientToggleMaximized (c, CLIENT_FLAG_MAXIMIZED_VERT, TRUE);
                break;
            case KEY_MAXIMIZE_HORIZ:
                clientToggleMaximized (c, CLIENT_FLAG_MAXIMIZED_HORIZ, TRUE);
                break;
            case KEY_SHADE_WINDOW:
                clientToggleShaded (c);
                break;
            case KEY_STICK_WINDOW:
                if (FLAG_TEST(c->xfwm_flags, XFWM_FLAG_HAS_STICK))
                {
                    clientToggleSticky (c, TRUE);
                    frameQueueDraw (c, FALSE);
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
            case KEY_RAISE_WINDOW:
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
                break;
            case KEY_LOWER_WINDOW:
Jasper Huijsmans's avatar
 
Jasper Huijsmans committed
                break;
            case KEY_RAISELOWER_WINDOW:
                if (clientIsTopMost (c))
                {
                    clientLower (c, None);
                }
                else
                {
                    clientRaise (c, None);
                }
                break;
            case KEY_TOGGLE_ABOVE:
            case KEY_TOGGLE_FULLSCREEN:
                clientToggleFullscreen (c);
                break;
            case KEY_MOVE_NEXT_WORKSPACE:
                workspaceSwitch (screen_info, screen_info->current_ws + 1, c, TRUE, ev->time);
                break;
            case KEY_MOVE_PREV_WORKSPACE:
                workspaceSwitch (screen_info, screen_info->current_ws - 1, c, TRUE, ev->time);
                workspaceMove (screen_info, -1, 0, c, ev->time);
                workspaceMove (screen_info, 1, 0, c, ev->time);
                workspaceMove (screen_info, 0, -1, c, ev->time);
                workspaceMove (screen_info, 0, 1, c, ev->time);
            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:
                if ((guint) (key - KEY_MOVE_WORKSPACE_1) < screen_info->workspace_count)
                    workspaceSwitch (screen_info, key - KEY_MOVE_WORKSPACE_1, c, TRUE, ev->time);
                show_window_menu (c, frameX (c) + frameLeft (c),
                                     frameY (c) + frameTop (c),
            case KEY_FILL_WINDOW:
                clientFill (c, CLIENT_FILL);
                break;
            case KEY_FILL_VERT:
                clientFill (c, CLIENT_FILL_VERT);
                break;
            case KEY_FILL_HORIZ:
        key = myScreenGetKeyPressed (ev_screen_info, ev);
        switch (key)
        {
            case KEY_CYCLE_WINDOWS:
                status = EVENT_FILTER_REMOVE;
                    clientCycle (ev_screen_info->clients->prev, ev);
                status = EVENT_FILTER_REMOVE;
                    xfce_sm_client_request_shutdown(display_info->session, XFCE_SM_CLIENT_SHUTDOWN_HINT_LOGOUT);
        case KEY_SWITCH_WINDOW:
            clientSwitchWindow ();
            break;
        case KEY_SWITCH_APPLICATION:
            clientSwitchApp ();
            break;
        case KEY_NEXT_WORKSPACE:
            status = EVENT_FILTER_REMOVE;
            workspaceSwitch (ev_screen_info, ev_screen_info->current_ws + 1, NULL, TRUE, ev->time);
            break;
        case KEY_PREV_WORKSPACE:
            status = EVENT_FILTER_REMOVE;
            workspaceSwitch (ev_screen_info, ev_screen_info->current_ws - 1, NULL, TRUE, ev->time);
            status = EVENT_FILTER_REMOVE;
            workspaceMove(ev_screen_info, -1, 0, NULL, ev->time);
            status = EVENT_FILTER_REMOVE;
            workspaceMove(ev_screen_info, 1, 0, NULL, ev->time);
            status = EVENT_FILTER_REMOVE;
            workspaceMove(ev_screen_info, 0, -1, NULL, ev->time);
            status = EVENT_FILTER_REMOVE;
            workspaceMove(ev_screen_info, 0, 1, NULL, ev->time);
        case KEY_ADD_WORKSPACE:
            status = EVENT_FILTER_REMOVE;
            workspaceSetCount (ev_screen_info, ev_screen_info->workspace_count + 1);
            break;
        case KEY_DEL_WORKSPACE:
            status = EVENT_FILTER_REMOVE;
            workspaceSetCount (ev_screen_info, ev_screen_info->workspace_count - 1);
        case KEY_ADD_ADJACENT_WORKSPACE:
            workspaceInsert (ev_screen_info, ev_screen_info->current_ws + 1);
            break;
        case KEY_DEL_ACTIVE_WORKSPACE:
            workspaceDelete (ev_screen_info, ev_screen_info->current_ws);
            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:
            status = EVENT_FILTER_REMOVE;
            if ((guint) (key - KEY_WORKSPACE_1) < ev_screen_info->workspace_count)
                workspaceSwitch (ev_screen_info, key - KEY_WORKSPACE_1, NULL, TRUE, ev->time);
        case KEY_SHOW_DESKTOP:
            status = EVENT_FILTER_REMOVE;
            toggle_show_desktop (ev_screen_info);
    /* Release pending events */
    XAllowEvents (display_info->dpy, SyncKeyboard, CurrentTime);

static eventFilterStatus
handleKeyRelease (DisplayInfo *display_info, XKeyEvent * ev)
{
    TRACE ("entering handleKeyRelease");
    /* Release pending events */
    XAllowEvents (display_info->dpy, SyncKeyboard, CurrentTime);

/* 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)
    guint state;

    screen_info = c->screen_info;
    state = ev->state & MODIFIER_MASK;

    if (ev->button == Button2)
        tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, FALSE);
        if (tclick == XFWM_BUTTON_CLICK)
        {
        else if (tclick == XFWM_BUTTON_DRAG)
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientMove (c, (XEvent *) ev);
    else if ((ev->button == Button1) || (ev->button == Button3))
        if ((ev->button == Button1) ||
            ((screen_info->params->easy_click) && (state == screen_info->params->easy_click)))
            if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
            {
                clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
        tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, TRUE);
        if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
        {
            switch (part)
            {
                case CORNER_COUNT + SIDE_LEFT:
                case CORNER_COUNT + SIDE_RIGHT:
                    clientFill(c, CLIENT_FILL_HORIZ);
                    break;
                case CORNER_COUNT + SIDE_TOP:
                case CORNER_COUNT + SIDE_BOTTOM:
                    clientFill(c, CLIENT_FILL_VERT);
                    break;
                default:
                    clientFill(c, CLIENT_FILL);
                    break;
            }
        }
        else if (tclick == XFWM_BUTTON_DRAG)
        {
            clientResize (c, part, (XEvent *) ev);
        }
Olivier Fourdan's avatar
Olivier Fourdan committed
edgeGetPart (Client *c, XButtonEvent * ev)
{
    int part, x_corner_pixels, y_corner_pixels, x_distance, y_distance;

    /* Corner is 1/3 of the side */
    x_corner_pixels = MAX(c->width / 3, 50);
    y_corner_pixels = MAX(c->height / 3, 50);

    /* Distance from event to edge of client window */
    x_distance = c->width / 2 - abs(c->width / 2 - ev->x);
    y_distance = c->height / 2 - abs(c->height / 2 - ev->y);

    /* Set a sensible default value */
    part = CORNER_BOTTOM_RIGHT;

    if (x_distance < x_corner_pixels && y_distance < y_corner_pixels)
    {
        /* In a corner */
        if (ev->x < c->width / 2)
        {
            if (ev->y < c->height / 2)
            {
                part = CORNER_TOP_LEFT;
            }
            else
            {
                part = CORNER_BOTTOM_LEFT;
            }
        }
        else
        {
            if (ev->y < c->height / 2)
            {
                part = CORNER_TOP_RIGHT;
            }
            else
            {
                part = CORNER_BOTTOM_RIGHT;
            }
        }
    }
    else
    {
        /* Not a corner - some side */
        if (x_distance / x_corner_pixels < y_distance / y_corner_pixels)
        {
            /* Left or right side */
            if (ev->x < c->width / 2)
            {
                part = CORNER_COUNT + SIDE_LEFT;
            }
            else
            {
                part = CORNER_COUNT + SIDE_RIGHT;
            }
        }
        else
        {
            /* Top or bottom side */
            if (ev->y < c->height / 2)
            {
                part = CORNER_COUNT + SIDE_TOP;
            }
            else
            {
                part = CORNER_COUNT + SIDE_BOTTOM;
            }
        }
    }

    return part;
}
static void
button1Action (Client * c, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    XfwmButtonClickType tclick;

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

    if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
    {
        clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
    }
    tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, TRUE);
    if ((tclick == XFWM_BUTTON_DRAG) || (tclick == XFWM_BUTTON_CLICK_AND_DRAG))
Olivier Fourdan's avatar
Olivier Fourdan committed
        clientMove (c, (XEvent *) ev);
    else if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
        switch (screen_info->params->double_click_action)
            case DOUBLE_CLICK_ACTION_MAXIMIZE:
                clientToggleMaximized (c, CLIENT_FLAG_MAXIMIZED, TRUE);
            case DOUBLE_CLICK_ACTION_SHADE:
                clientToggleShaded (c);
                break;
            case DOUBLE_CLICK_ACTION_FILL:
            case DOUBLE_CLICK_ACTION_HIDE:
                if (CLIENT_CAN_HIDE_WINDOW (c))
                {
                    clientWithdraw (c, c->win_workspace, TRUE);
static void
titleButton (Client * c, guint state, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    g_return_if_fail (c != NULL);
    g_return_if_fail (ev != NULL);

    /* Get Screen data from the client itself */
    screen_info = c->screen_info;
        button1Action (c, ev);
    }
    else if (ev->button == Button2)
    {
    }
    else if (ev->button == Button3)
    {
        XfwmButtonClickType tclick;

        tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, FALSE);
        if (tclick == XFWM_BUTTON_DRAG)
        {
Olivier Fourdan's avatar
Olivier Fourdan committed
            clientMove (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)
            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))
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (screen_info->params->mousewheel_rollup)
            {
                clientShade (c);
            }
    else if (ev->button == Button5)
        /* Mouse wheel scroll down */
        if (state == AltMask)
        {
            clientDecOpacity(c);
        }
        else if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
Olivier Fourdan's avatar
Olivier Fourdan committed
            if (screen_info->params->mousewheel_rollup)
            {
                clientUnshade (c);
            }
    else if (ev->button == Button6)
    {
        /* Mouse wheel scroll left, or left side button */
        clientDecOpacity(c);
    }
    else if (ev->button == Button7)
    {
        /* Mouse wheel scroll right, or right side button */
        clientIncOpacity(c);
    }
static void
rootScrollButton (DisplayInfo *display_info, XButtonEvent * ev)
    static guint32 lastscroll = CurrentTime;
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
        /* 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, TRUE, ev->time);
        workspaceSwitch (screen_info, screen_info->current_ws + 1, NULL, TRUE, ev->time);
handleButtonPress (DisplayInfo *display_info, XButtonEvent * ev)
Olivier Fourdan's avatar
Olivier Fourdan committed
{
Olivier Fourdan's avatar
Olivier Fourdan committed
    ScreenInfo *screen_info;
    Client *c;
Olivier Fourdan's avatar
Olivier Fourdan committed
    Window win;
    guint state, part;
Olivier Fourdan's avatar
Olivier Fourdan committed
    gboolean replay;
Olivier Fourdan's avatar
Olivier Fourdan committed

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

Olivier Fourdan's avatar
Olivier Fourdan committed
    replay = FALSE;
    c = myDisplayGetClientFromWindow (display_info, ev->window, SEARCH_FRAME | SEARCH_WINDOW);
        state = ev->state & MODIFIER_MASK;
        screen_info = c->screen_info;
        if ((ev->button == Button1) && (state) && (state == screen_info->params->easy_click))
        else if ((ev->button == Button2) && (state) && (state == screen_info->params->easy_click))
        else if ((ev->button == Button3) && (state) && (state == screen_info->params->easy_click))
Olivier Fourdan's avatar
Olivier Fourdan committed
            part = edgeGetPart (c, ev);
#if 0   /* Binding the alt+scroll wheel to switch app/window is not handy, disabling for now */
        else if ((ev->button == Button4) && (state) && (state == screen_info->params->easy_click))
        {
            clientSwitchWindow ();
        }
        else if ((ev->button == Button5) && (state) && (state == screen_info->params->easy_click))
        {
            clientSwitchApp ();
        }
#endif
        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)
Olivier Fourdan's avatar
Olivier Fourdan committed
                    clientClearDelayedRaise ();
                }
                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)
            {
                XfwmButtonClickType tclick;

                tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, 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)
Olivier Fourdan's avatar
Olivier Fourdan committed
                        clientClearDelayedRaise ();
                    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, CORNER_COUNT + SIDE_BOTTOM, ev);
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_TOP]))
            && (state == 0))
        {
            edgeButton (c, CORNER_COUNT + SIDE_TOP, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_COUNT + SIDE_LEFT, ev);
        }
        else if ((win == MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]))
            && (state == 0))
        {
            edgeButton (c, CORNER_COUNT + SIDE_RIGHT, ev);
Olivier Fourdan's avatar
Olivier Fourdan committed
            replay = TRUE;
            if (((screen_info->params->raise_with_any_button) && (c->type & WINDOW_REGULAR_FOCUSABLE)) || (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))