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.
xfwm4 - (c) 2002-2006 Olivier Fourdan
#include <config.h>
#include <string.h>
Olivier Fourdan
committed
#include <X11/X.h>
#include <X11/Xatom.h>
#include <glib.h>
#include <gtk/gtk.h>
#ifdef HAVE_RANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <libxfce4util/libxfce4util.h>
#include "stacking.h"
Olivier Fourdan
committed
#include "transients.h"
#include "focus.h"
#include "netwm.h"
#include "startup_notification.h"
#include "events.h"
#include "event_filter.h"
Olivier Fourdan
committed
#ifndef CHECK_BUTTON_TIME
#define CHECK_BUTTON_TIME 0
#endif
Olivier Fourdan
committed
#define WIN_IS_BUTTON(win) ((win == MYWINDOW_XWINDOW(c->buttons[HIDE_BUTTON])) || \
(win == MYWINDOW_XWINDOW(c->buttons[CLOSE_BUTTON])) || \
(win == MYWINDOW_XWINDOW(c->buttons[MAXIMIZE_BUTTON])) || \
(win == MYWINDOW_XWINDOW(c->buttons[SHADE_BUTTON])) || \
(win == MYWINDOW_XWINDOW(c->buttons[STICK_BUTTON])))
#define DBL_CLICK_GRAB (ButtonMotionMask | \
PointerMotionMask | \
ButtonPressMask | \
ButtonReleaseMask)
#define MODIFIER_MASK (ShiftMask | \
ControlMask | \
AltMask | \
MetaMask | \
SuperMask | \
HyperMask)
Olivier Fourdan
committed
static int edge_scroll_x = 0;
Olivier Fourdan
committed
static int edge_scroll_y = 0;
Olivier Fourdan
committed
/* Forward decl. */
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
committed
XFWM_BUTTON_UNDEFINED = 0,
XFWM_BUTTON_DRAG = 1,
XFWM_BUTTON_CLICK = 2,
XFWM_BUTTON_CLICK_AND_DRAG = 3,
XFWM_BUTTON_DOUBLE_CLICK = 4
}
XfwmButtonClickType;
Olivier Fourdan
committed
typedef struct _XfwmButtonClickData XfwmButtonClickData;
struct _XfwmButtonClickData
{
Olivier Fourdan
committed
Window w;
guint button;
guint clicks;
Olivier Fourdan
committed
gint x;
gint y;
gint xcurrent;
gint ycurrent;
Olivier Fourdan
committed
};
static gboolean
typeOfClick_break (gpointer data)
{
XfwmButtonClickData *passdata;
passdata = (XfwmButtonClickData *) data;
Olivier Fourdan
committed
if (passdata->timeout)
{
g_source_remove (passdata->timeout);
passdata->timeout = 0;
}
gtk_main_quit ();
return (TRUE);
}
Olivier Fourdan
committed
typeOfClick_event_filter (XEvent * xevent, gpointer data)
{
XfwmButtonClickData *passdata;
eventFilterStatus status;
gboolean keep_going;
keep_going = TRUE;
passdata = (XfwmButtonClickData *) data;
status = EVENT_FILTER_STOP;
myDisplayUpdateCurrentTime (passdata->display_info, xevent);
Olivier Fourdan
committed
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) &&
Olivier Fourdan
committed
(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;
}
Olivier Fourdan
committed
}
else
{
Olivier Fourdan
committed
}
if ((ABS (passdata->x - passdata->xcurrent) > 1) ||
Olivier Fourdan
committed
(ABS (passdata->y - passdata->ycurrent) > 1) ||
(!keep_going))
{
TRACE ("event loop now finished");
typeOfClick_break (data);
}
return status;
}
Olivier Fourdan
committed
typeOfClick (ScreenInfo *screen_info, Window w, XEvent * ev, gboolean allow_double_click)
Olivier Fourdan
committed
{
Olivier Fourdan
committed
XfwmButtonClickData passdata;
Olivier Fourdan
committed
Olivier Fourdan
committed
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, DBL_CLICK_GRAB, None, ev->xbutton.time);
if (!g)
Olivier Fourdan
committed
{
TRACE ("grab failed in typeOfClick");
gdk_beep ();
myScreenUngrabPointer (screen_info);
return XFWM_BUTTON_UNDEFINED;
Olivier Fourdan
committed
}
Olivier Fourdan
committed
passdata.display_info = display_info;
Olivier Fourdan
committed
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;
Olivier Fourdan
committed
passdata.timeout = g_timeout_add_full (G_PRIORITY_DEFAULT,
display_info->dbl_click_time,
Olivier Fourdan
committed
(gpointer) &passdata, NULL);
Olivier Fourdan
committed
TRACE ("entering typeOfClick loop");
eventFilterPush (display_info->xfilter, typeOfClick_event_filter, &passdata);
Olivier Fourdan
committed
gtk_main ();
eventFilterPop (display_info->xfilter);
Olivier Fourdan
committed
TRACE ("leaving typeOfClick loop");
myScreenUngrabPointer (screen_info);
Olivier Fourdan
committed
return (XfwmButtonClickType) passdata.clicks;
Olivier Fourdan
committed
}
Olivier Fourdan
committed
#if CHECK_BUTTON_TIME
Olivier Fourdan
committed
static gboolean
check_button_time (XButtonEvent *ev)
{
Olivier Fourdan
committed
static Time last_button_time = (Time) CurrentTime;
Olivier Fourdan
committed
if (last_button_time > ev->time)
{
return FALSE;
}
last_button_time = ev->time;
return TRUE;
}
Olivier Fourdan
committed
#endif
moveRequest (Client * c, XEvent * ev)
if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MOVE)
&& !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
clientMove (c, ev);
resizeRequest (Client * c, int corner, XEvent * ev)
if (!FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
if (FLAG_TEST_ALL (c->xfwm_flags,
XFWM_FLAG_HAS_RESIZE | XFWM_FLAG_IS_RESIZABLE))
{
clientResize (c, corner, ev);
}
else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MOVE))
{
clientMove (c, ev);
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,
sendRootMessage (screen_info, NET_SHOWING_DESKTOP, screen_info->show_desktop,
myDisplayGetCurrentTime (screen_info->display_info));
static eventFilterStatus
handleMotionNotify (DisplayInfo *display_info, XMotionEvent * ev)
Olivier Fourdan
committed
{
TRACE ("entering handleMotionNotify");
return EVENT_FILTER_REMOVE;
Olivier Fourdan
committed
}
static int
getKeyPressed (ScreenInfo *screen_info, XKeyEvent * ev)
state = ev->state & MODIFIER_MASK;
for (key = 0; key < KEY_LAST; key++)
if ((screen_info->params->keys[key].keycode == ev->keycode)
&& (screen_info->params->keys[key].modifier == state))
{
break;
}
static eventFilterStatus
handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev)
{
eventFilterStatus status;
ScreenInfo *ev_screen_info;
int key;
TRACE ("entering handleKeyEvent");
status = EVENT_FILTER_PASS;
ev_screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
if (!ev_screen_info)
{
return status;
}
key = getKeyPressed (screen_info, ev);
status = EVENT_FILTER_REMOVE;
Olivier Fourdan
committed
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
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:
{
clientHide (c, c->win_workspace, TRUE);
}
break;
case KEY_MAXIMIZE_WINDOW:
clientToggleMaximized (c, WIN_STATE_MAXIMIZED, TRUE);
break;
case KEY_MAXIMIZE_VERT:
clientToggleMaximized (c, WIN_STATE_MAXIMIZED_VERT, TRUE);
break;
case KEY_MAXIMIZE_HORIZ:
clientToggleMaximized (c, WIN_STATE_MAXIMIZED_HORIZ, TRUE);
break;
case KEY_SHADE_WINDOW:
clientToggleShaded (c);
break;
case KEY_STICK_WINDOW:
{
clientToggleSticky (c, TRUE);
Olivier Fourdan
committed
frameDraw (c, FALSE);
Olivier Fourdan
committed
}
Olivier Fourdan
committed
clientRaise (c, None);
Olivier Fourdan
committed
clientLower (c, None);
case KEY_TOGGLE_FULLSCREEN:
clientToggleFullscreen (c);
break;
case KEY_MOVE_NEXT_WORKSPACE:
Olivier Fourdan
committed
workspaceSwitch (screen_info, screen_info->current_ws + 1, c, TRUE, ev->time);
break;
case KEY_MOVE_PREV_WORKSPACE:
Olivier Fourdan
committed
workspaceSwitch (screen_info, screen_info->current_ws - 1, c, TRUE, ev->time);
Olivier Fourdan
committed
case KEY_MOVE_UP_WORKSPACE:
Olivier Fourdan
committed
workspaceMove (screen_info, -1, 0, c, ev->time);
Olivier Fourdan
committed
break;
case KEY_MOVE_DOWN_WORKSPACE:
Olivier Fourdan
committed
workspaceMove (screen_info, 1, 0, c, ev->time);
Olivier Fourdan
committed
break;
case KEY_MOVE_LEFT_WORKSPACE:
Olivier Fourdan
committed
workspaceMove (screen_info, 0, -1, c, ev->time);
Olivier Fourdan
committed
break;
case KEY_MOVE_RIGHT_WORKSPACE:
Olivier Fourdan
committed
workspaceMove (screen_info, 0, 1, c, ev->time);
Olivier Fourdan
committed
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:
Olivier Fourdan
committed
if (key - KEY_MOVE_WORKSPACE_1 < screen_info->workspace_count)
Olivier Fourdan
committed
{
clientRaise (c, None);
Olivier Fourdan
committed
workspaceSwitch (screen_info, key - KEY_MOVE_WORKSPACE_1, c, TRUE, ev->time);
Olivier Fourdan
committed
}
Olivier Fourdan
committed
case KEY_POPUP_MENU:
/*
We need to release the events here prior to grabbing
the keyboard in gtk menu otherwise we end with a dead lock...
*/
XAllowEvents (display_info->dpy, AsyncKeyboard, CurrentTime);
show_window_menu (c, frameX (c) + frameLeft (c),
frameY (c) + frameTop (c),
Button1, GDK_CURRENT_TIME);
/* 'nuff for now */
return EVENT_FILTER_REMOVE;
Olivier Fourdan
committed
break;
default:
break;
}
Olivier Fourdan
committed
}
else
{
key = getKeyPressed (ev_screen_info, ev);
switch (key)
{
case KEY_CYCLE_WINDOWS:
status = EVENT_FILTER_REMOVE;
if (ev_screen_info->clients)
clientCycle (ev_screen_info->clients->prev, (XEvent *) ev);
Olivier Fourdan
committed
case KEY_CLOSE_WINDOW:
status = EVENT_FILTER_REMOVE;
Olivier Fourdan
committed
if (display_info->session)
{
logout_session (display_info->session);
}
break;
default:
break;
}
Olivier Fourdan
committed
}
Olivier Fourdan
committed
switch (key)
{
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);
Olivier Fourdan
committed
case KEY_UP_WORKSPACE:
status = EVENT_FILTER_REMOVE;
workspaceMove(ev_screen_info, -1, 0, NULL, ev->time);
Olivier Fourdan
committed
break;
case KEY_DOWN_WORKSPACE:
status = EVENT_FILTER_REMOVE;
workspaceMove(ev_screen_info, 1, 0, NULL, ev->time);
Olivier Fourdan
committed
break;
case KEY_LEFT_WORKSPACE:
status = EVENT_FILTER_REMOVE;
workspaceMove(ev_screen_info, 0, -1, NULL, ev->time);
Olivier Fourdan
committed
break;
case KEY_RIGHT_WORKSPACE:
status = EVENT_FILTER_REMOVE;
workspaceMove(ev_screen_info, 0, 1, NULL, ev->time);
Olivier Fourdan
committed
break;
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);
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 (key - KEY_WORKSPACE_1 < ev_screen_info->workspace_count)
Olivier Fourdan
committed
{
workspaceSwitch (ev_screen_info, key - KEY_WORKSPACE_1, NULL, TRUE, ev->time);
Olivier Fourdan
committed
}
case KEY_SHOW_DESKTOP:
status = EVENT_FILTER_REMOVE;
toggle_show_desktop (ev_screen_info);
default:
break;
Olivier Fourdan
committed
XAllowEvents (display_info->dpy, AsyncKeyboard, CurrentTime);
return status;
/* User has clicked on an edge or corner.
* Button 1 : Raise and resize
* Button 2 : Move
* Button 3 : Resize
*/
edgeButton (Client * c, int part, XButtonEvent * ev)
Olivier Fourdan
committed
ScreenInfo *screen_info;
int state;
screen_info = c->screen_info;
state = ev->state & MODIFIER_MASK;
if (ev->button == Button2)
XfwmButtonClickType tclick;
Olivier Fourdan
committed
Olivier Fourdan
committed
tclick = typeOfClick (screen_info, c->window, (XEvent *) ev, FALSE);
if (tclick == XFWM_BUTTON_CLICK)
{
Olivier Fourdan
committed
clientLower (c, None);
Olivier Fourdan
committed
else if (tclick != XFWM_BUTTON_UNDEFINED)
{
moveRequest (c, (XEvent *) ev);
}
Olivier Fourdan
committed
else if ((ev->button == Button1) || (ev->button == Button3))
Olivier Fourdan
committed
if ((ev->button == Button1) ||
((screen_info->params->easy_click) && (state == screen_info->params->easy_click)))
if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
{
Olivier Fourdan
committed
clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
}
Olivier Fourdan
committed
clientRaise (c, None);
Olivier Fourdan
committed
resizeRequest (c, part, (XEvent *) ev);
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
static int
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;
}
button1Action (Client * c, XButtonEvent * ev)
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
committed
clientRaise (c, None);
Olivier Fourdan
committed
tclick = typeOfClick (screen_info, c->window, ©_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)
Olivier Fourdan
committed
case DBL_CLICK_ACTION_MAXIMIZE:
clientToggleMaximized (c, WIN_STATE_MAXIMIZED, TRUE);
Olivier Fourdan
committed
case DBL_CLICK_ACTION_SHADE:
clientToggleShaded (c);
break;
Olivier Fourdan
committed
case DBL_CLICK_ACTION_HIDE:
if (CLIENT_CAN_HIDE_WINDOW (c))
{
clientHide (c, c->win_workspace, TRUE);
}
titleButton (Client * c, int state, XButtonEvent * ev)
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;
if (ev->button == Button1)
{
button1Action (c, ev);
}
else if (ev->button == Button2)
{
Olivier Fourdan
committed
clientLower (c, None);
}
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)
*/
XfwmButtonClickType tclick;
memcpy(©_event, ev, sizeof(XEvent));
Olivier Fourdan
committed
tclick = typeOfClick (screen_info, c->window, ©_event, FALSE);
if (tclick == XFWM_BUTTON_DRAG)
{
moveRequest (c, (XEvent *) ev);
}
Olivier Fourdan
committed
else if (tclick != XFWM_BUTTON_UNDEFINED)
if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
{
clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
}
Olivier Fourdan
committed
clientRaise (c, None);
}
ev->window = ev->root;
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))
{
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))
{
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);
}
rootScrollButton (DisplayInfo *display_info, XButtonEvent * ev)
Olivier Fourdan
committed
static Time lastscroll = (Time) CurrentTime;
Olivier Fourdan
committed
if ((ev->time - lastscroll) < 25) /* ms */
/* Too many events in too little time, drop this event... */
return;
}
lastscroll = ev->time;
/* Get the screen structure from the root of the event */
screen_info = myDisplayGetScreenFromRoot (display_info, ev->root);
if (!screen_info)
{
return;
}
if (ev->button == Button4)
{
Olivier Fourdan
committed
workspaceSwitch (screen_info, screen_info->current_ws - 1, NULL, TRUE, ev->time);
}
else if (ev->button == Button5)
{
Olivier Fourdan
committed
workspaceSwitch (screen_info, screen_info->current_ws + 1, NULL, TRUE, ev->time);
}
}
static eventFilterStatus
handleButtonPress (DisplayInfo *display_info, XButtonEvent * ev)
TRACE ("entering handleButtonPress");
Olivier Fourdan
committed
#if CHECK_BUTTON_TIME
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 EVENT_FILTER_REMOVE;
Olivier Fourdan
committed
}
Olivier Fourdan
committed
#endif
c = myDisplayGetClientFromWindow (display_info, ev->window, ANY);
win = ev->subwindow;
Olivier Fourdan
committed
if ((ev->button == Button1) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
{
button1Action (c, ev);
}
Olivier Fourdan
committed
else if ((ev->button == Button2) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
Olivier Fourdan
committed
clientLower (c, None);
Olivier Fourdan
committed
else if ((ev->button == Button3) && (screen_info->params->easy_click) && (state == screen_info->params->easy_click))
Olivier Fourdan
committed
edgeButton (c, part, 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);
}
Olivier Fourdan
committed
clientRaise (c, None);
}
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)
*/
XfwmButtonClickType tclick;
Olivier Fourdan
committed
tclick = typeOfClick (screen_info, c->window, ©_event, TRUE);
if (tclick == XFWM_BUTTON_DOUBLE_CLICK)
{
clientClose (c);
}
Olivier Fourdan
committed
else if (tclick != XFWM_BUTTON_UNDEFINED)
if (!(c->type & WINDOW_TYPE_DONT_FOCUS))
{
clientSetFocus (screen_info, c, ev->time, NO_FOCUS_FLAG);
}
Olivier Fourdan
committed
clientRaise (c, None);
}
ev->window = ev->root;
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);
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
/* 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_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
committed
else if (ev->window == c->window)
clientPassGrabMouseButton (c);
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) ||
Olivier Fourdan
committed
!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER))
Olivier Fourdan
committed
clientRaise (c, None);