mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
Added visual bell feature, fix for 99886.
This commit is contained in:
parent
32a8bf50b7
commit
e7e47a8b85
130
ChangeLog
130
ChangeLog
@ -1,3 +1,133 @@
|
|||||||
|
2002-12-16 Bill Haneman <bill.haneman@sun.com>
|
||||||
|
|
||||||
|
* configure.in:
|
||||||
|
Check for XKB extension.
|
||||||
|
|
||||||
|
* src/Makefile.am:
|
||||||
|
Added bell.c and bell.h to metacity sources.
|
||||||
|
|
||||||
|
* src/common.h:
|
||||||
|
(MetaFrameFlags):
|
||||||
|
Added META_FRAME_IS_FLASHING flag.
|
||||||
|
|
||||||
|
* src/frame.h:
|
||||||
|
(MetaFrame): Added is_flashing field.
|
||||||
|
|
||||||
|
* src/frame.c:
|
||||||
|
(meta_window_ensure_frame):
|
||||||
|
Initialize the is_flashing flag to FALSE.
|
||||||
|
(meta_frame_get_flags):
|
||||||
|
Handle the FRAME_IS_FLASHING flag.
|
||||||
|
(meta_window_destroy_frame):
|
||||||
|
Call meta_bell_notify_frame_destroy.
|
||||||
|
|
||||||
|
* src/prefs.h:
|
||||||
|
(MetaPreference):
|
||||||
|
Added META_PREF_VISUAL_BELL, META_PREF_AUDIBLE_BELL,
|
||||||
|
META_PREF_VISUAL_BELL_TYPE.
|
||||||
|
(MetaVisualBellType): New enum.
|
||||||
|
(meta_prefs_get_visual_bell, meta_prefs_bell_is_audible):
|
||||||
|
(meta_prefs_get_visual_bell_type):
|
||||||
|
New accessor declarations.
|
||||||
|
|
||||||
|
* src/prefs.c:
|
||||||
|
(#includes): Include "display.h", since we now call
|
||||||
|
meta_displays_list() in our update func.
|
||||||
|
(#defines):
|
||||||
|
Define KEY_VISUAL_BELL, KEY_AUDIBLE_BELL,
|
||||||
|
and KEY_VISUAL_BELL_TYPE.
|
||||||
|
(provide_visual_bell, bell_is_audible, visual_bell_type):
|
||||||
|
New static state variables.
|
||||||
|
(update_visual_bell): New method to update visual-bell
|
||||||
|
boolean settings from keys "visual_bell" and "audible_bell".
|
||||||
|
(update_visual_bell_type):
|
||||||
|
New method to update visual-bell type setting.
|
||||||
|
(visual_bell_type_from_string) :
|
||||||
|
New method to convert from gconf string to visual-bell
|
||||||
|
type enum. Only currently recognized values are "fullscreen"
|
||||||
|
and "frame_flash".
|
||||||
|
(change_notify):
|
||||||
|
Handle changes to visual and audible bell properties.
|
||||||
|
(meta_prefs_get_visual_bell, meta_prefs_bell_is_audible):
|
||||||
|
(meta_prefs_get_visual_bell_type):
|
||||||
|
New accessor definitions.
|
||||||
|
(meta_prefs_init): Added a second call to notify_add,
|
||||||
|
listens to "/desktop/gnome/interface" as well as "apps/metacity".
|
||||||
|
Also call the update funcs for the new visual-bell gconf keys.
|
||||||
|
(meta_preference_to_string):
|
||||||
|
Handle the visual/audible bell cases.
|
||||||
|
|
||||||
|
* src/bell.h:
|
||||||
|
(meta_bell_notify);
|
||||||
|
New method, calls a visual notifucation
|
||||||
|
method based on the visual-bell-type, or none if the type
|
||||||
|
is unrecognized or invalid.
|
||||||
|
(meta_bell_set_audible):
|
||||||
|
New public method for setting the audible bell setting,
|
||||||
|
used in updater for new gconf key "audible_bell".
|
||||||
|
(meta_bell_init):
|
||||||
|
Initialize the bell notification for a display.
|
||||||
|
(meta_bell_shutdown):
|
||||||
|
Shutdown the bell notification for a display.
|
||||||
|
(meta_bell_notify_frame_destroy):
|
||||||
|
Remove pending idle handlers on notification.
|
||||||
|
|
||||||
|
* src/bell.c:
|
||||||
|
Include "bell.h", and conditionally include <Xll/Xkblib.h>.
|
||||||
|
(meta_bell_set_audible):
|
||||||
|
If XKB is present, enable/disable the audible system
|
||||||
|
bell based on the gconf key /desktop/gnome/interface/audible_bell.
|
||||||
|
(meta_bell_init):
|
||||||
|
Query and initialize XKB if present, register for notification
|
||||||
|
on the bell, and set audible bell according to gconf settings.
|
||||||
|
(meta_bell_flash_screen):
|
||||||
|
Maps and unmaps a fullscreen X window (painted white, then
|
||||||
|
black), which causes a fullscreen 'flash' transient.
|
||||||
|
(meta_bell_flash_window_frame):
|
||||||
|
Flashes the titlebar of a specified window.
|
||||||
|
(meta_bell_flash_frame):
|
||||||
|
Calls meta_bell_flash_window_frame on the window which
|
||||||
|
was the source of the current bell event, or the currently
|
||||||
|
focussed window if the event source cannot be determined.
|
||||||
|
(meta_bell_unflash_frame):
|
||||||
|
Restore the frame's appearance to normal.
|
||||||
|
(meta_bell_flash_fullscreen):
|
||||||
|
Call meta_bell_flash_fullscreen for all screens.
|
||||||
|
(meta_bell_shutdown):
|
||||||
|
New method.
|
||||||
|
(meta_bell_notify_frame_destroy):
|
||||||
|
Remove pending idle handlers on notification,
|
||||||
|
testing for frame->is_flashing first.
|
||||||
|
|
||||||
|
* src/display.h:
|
||||||
|
(MetaDisplay): Added xkb_base_event_type field.
|
||||||
|
|
||||||
|
* src/display.c:
|
||||||
|
Check for XKB and include "X11/XKBlib.h" if present.
|
||||||
|
(meta_display_open): Call meta_bell_init.
|
||||||
|
(event_callback): Call meta_bell_notify
|
||||||
|
when event comes from XKB and is XkbBellNotify
|
||||||
|
(prefs_changed_callback):
|
||||||
|
Handle META_PREF_AUDIBLE_BELL notification.
|
||||||
|
|
||||||
|
* src/screen.h:
|
||||||
|
(MetaScreen): Add flash_window field.
|
||||||
|
|
||||||
|
* src/screen.c:
|
||||||
|
(meta_screen_new):
|
||||||
|
Initialize flash_window field.
|
||||||
|
|
||||||
|
* src/theme.c:
|
||||||
|
(theme_get_style):
|
||||||
|
New heuristic for focus-style, to invert sense of focus
|
||||||
|
flag when META_FRAME_IS_FLASHING flag is set.
|
||||||
|
|
||||||
|
* src/metacity.schemas.in:
|
||||||
|
Added scheme information for
|
||||||
|
/apps/metacity/general/visual_bell,
|
||||||
|
/apps/metacity/general/audible_bell, and
|
||||||
|
/apps/metacity/general/visual_bell_type.
|
||||||
|
|
||||||
2002-12-16 Havoc Pennington <hp@pobox.com>
|
2002-12-16 Havoc Pennington <hp@pobox.com>
|
||||||
|
|
||||||
* src/window-props.c (init_wm_name): argh, screwed that up. get
|
* src/window-props.c (init_wm_name): argh, screwed that up. get
|
||||||
|
11
configure.in
11
configure.in
@ -221,6 +221,17 @@ if test "x$found_shape" = "xyes"; then
|
|||||||
AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library])
|
AC_DEFINE(HAVE_SHAPE, , [Have the shape extension library])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
found_xkb=no
|
||||||
|
AC_CHECK_LIB(X11, XkbQueryExtension,
|
||||||
|
[AC_CHECK_HEADER(X11/XKBlib.h,
|
||||||
|
found_xkb=yes)],
|
||||||
|
, $ALL_X_LIBS)
|
||||||
|
|
||||||
|
if test "x$found_xkb" = "xyes"; then
|
||||||
|
AC_DEFINE(HAVE_XKB, , [Have keyboard extension library])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
RANDR_LIBS=
|
RANDR_LIBS=
|
||||||
found_randr=no
|
found_randr=no
|
||||||
AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
|
AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
|
||||||
|
@ -11,6 +11,8 @@ EGGFILES= \
|
|||||||
metacity_SOURCES= \
|
metacity_SOURCES= \
|
||||||
async-getprop.c \
|
async-getprop.c \
|
||||||
async-getprop.h \
|
async-getprop.h \
|
||||||
|
bell.h \
|
||||||
|
bell.c \
|
||||||
common.h \
|
common.h \
|
||||||
core.c \
|
core.c \
|
||||||
core.h \
|
core.h \
|
||||||
|
250
src/bell.c
Normal file
250
src/bell.c
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/* Metacity visual bell */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Sun Microsystems Inc.
|
||||||
|
*
|
||||||
|
* 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 of the
|
||||||
|
* License, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include "bell.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "prefs.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_bell_flash_screen (MetaDisplay *display,
|
||||||
|
MetaScreen *screen)
|
||||||
|
{
|
||||||
|
Window root = screen->xroot;
|
||||||
|
int width = screen->width;
|
||||||
|
int height = screen->height;
|
||||||
|
|
||||||
|
if (screen->flash_window == None)
|
||||||
|
{
|
||||||
|
Visual *visual = CopyFromParent;
|
||||||
|
XSetWindowAttributes xswa;
|
||||||
|
int depth = CopyFromParent;
|
||||||
|
xswa.save_under = True;
|
||||||
|
xswa.override_redirect = True;
|
||||||
|
/*
|
||||||
|
* TODO: use XGetVisualInfo and determine which is an
|
||||||
|
* overlay, if one is present, and use the Overlay visual
|
||||||
|
* for this window (for performance reasons).
|
||||||
|
* Not sure how to tell this yet...
|
||||||
|
*/
|
||||||
|
screen->flash_window = XCreateWindow (display->xdisplay, root,
|
||||||
|
0, 0, width, height,
|
||||||
|
0, depth,
|
||||||
|
InputOutput,
|
||||||
|
visual,
|
||||||
|
/* note: XSun doesn't like SaveUnder here */
|
||||||
|
CWSaveUnder | CWOverrideRedirect,
|
||||||
|
&xswa);
|
||||||
|
XSelectInput (display->xdisplay, screen->flash_window, ExposureMask);
|
||||||
|
XMapWindow (display->xdisplay, screen->flash_window);
|
||||||
|
XSync (display->xdisplay, False);
|
||||||
|
XFlush (display->xdisplay);
|
||||||
|
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* just draw something in the window */
|
||||||
|
GC gc = XCreateGC (display->xdisplay, screen->flash_window, 0, NULL);
|
||||||
|
XMapWindow (display->xdisplay, screen->flash_window);
|
||||||
|
XSetForeground (display->xdisplay, gc,
|
||||||
|
WhitePixel (display->xdisplay,
|
||||||
|
XScreenNumberOfScreen (screen->xscreen)));
|
||||||
|
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||||
|
0, 0, width, height);
|
||||||
|
XSetForeground (display->xdisplay, gc,
|
||||||
|
BlackPixel (display->xdisplay,
|
||||||
|
XScreenNumberOfScreen (screen->xscreen)));
|
||||||
|
XFillRectangle (display->xdisplay, screen->flash_window, gc,
|
||||||
|
0, 0, width, height);
|
||||||
|
XFlush (display->xdisplay);
|
||||||
|
XSync (display->xdisplay, False);
|
||||||
|
XUnmapWindow (display->xdisplay, screen->flash_window);
|
||||||
|
}
|
||||||
|
XFlush (display->xdisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
static void
|
||||||
|
meta_bell_flash_fullscreen (MetaDisplay *display,
|
||||||
|
XkbAnyEvent *xkb_ev)
|
||||||
|
{
|
||||||
|
XkbBellNotifyEvent *xkb_bell_ev = (XkbBellNotifyEvent *) xkb_ev;
|
||||||
|
MetaScreen *screen;
|
||||||
|
|
||||||
|
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||||
|
if (xkb_bell_ev->window != None)
|
||||||
|
{
|
||||||
|
screen = meta_display_screen_for_xwindow (display, xkb_bell_ev->window);
|
||||||
|
if (screen)
|
||||||
|
meta_bell_flash_screen (display, screen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GSList *screen_list = display->screens;
|
||||||
|
while (screen_list)
|
||||||
|
{
|
||||||
|
screen = (MetaScreen *) screen_list->data;
|
||||||
|
meta_bell_flash_screen (display, screen);
|
||||||
|
screen_list = screen_list->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_bell_unflash_frame (gpointer data)
|
||||||
|
{
|
||||||
|
MetaFrame *frame = (MetaFrame *) data;
|
||||||
|
frame->is_flashing = 0;
|
||||||
|
meta_frame_queue_draw (frame);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_bell_flash_window_frame (MetaWindow *window)
|
||||||
|
{
|
||||||
|
g_assert (window->frame != NULL);
|
||||||
|
window->frame->is_flashing = 1;
|
||||||
|
meta_frame_queue_draw (window->frame);
|
||||||
|
g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 100,
|
||||||
|
meta_bell_unflash_frame, window->frame, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_bell_flash_frame (MetaDisplay *display,
|
||||||
|
XkbAnyEvent *xkb_ev)
|
||||||
|
{
|
||||||
|
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent *) xkb_ev;
|
||||||
|
MetaWindow *window;
|
||||||
|
|
||||||
|
g_assert (xkb_ev->xkb_type == XkbBellNotify);
|
||||||
|
window = meta_display_lookup_x_window (display, xkb_bell_event->window);
|
||||||
|
if (!window && (display->focus_window->frame))
|
||||||
|
{
|
||||||
|
window = display->focus_window;
|
||||||
|
}
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
meta_bell_flash_window_frame (window);
|
||||||
|
}
|
||||||
|
else /* revert to fullscreen flash if there's no focussed window */
|
||||||
|
{
|
||||||
|
meta_bell_flash_fullscreen (display, xkb_ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_bell_visual_notify (MetaDisplay *display,
|
||||||
|
XkbAnyEvent *xkb_ev)
|
||||||
|
{
|
||||||
|
switch (meta_prefs_get_visual_bell_type ())
|
||||||
|
{
|
||||||
|
case META_VISUAL_BELL_FULLSCREEN_FLASH:
|
||||||
|
meta_bell_flash_fullscreen (display, xkb_ev);
|
||||||
|
break;
|
||||||
|
case META_VISUAL_BELL_FRAME_FLASH:
|
||||||
|
meta_bell_flash_frame (display, xkb_ev); /* does nothing yet */
|
||||||
|
break;
|
||||||
|
case META_VISUAL_BELL_INVALID:
|
||||||
|
/* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_bell_notify (MetaDisplay *display,
|
||||||
|
XkbAnyEvent *xkb_ev)
|
||||||
|
{
|
||||||
|
/* flash something */
|
||||||
|
if (meta_prefs_get_visual_bell ())
|
||||||
|
meta_bell_visual_notify (display, xkb_ev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_bell_set_audible (MetaDisplay *display, gboolean audible)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
XkbChangeEnabledControls (display->xdisplay,
|
||||||
|
XkbUseCoreKbd,
|
||||||
|
XkbAudibleBellMask,
|
||||||
|
audible ? XkbAudibleBellMask : 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_bell_init (MetaDisplay *display)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
int xkb_base_error_type, xkb_opcode;
|
||||||
|
|
||||||
|
if (!XkbQueryExtension (display->xdisplay, &xkb_opcode,
|
||||||
|
&display->xkb_base_event_type,
|
||||||
|
&xkb_base_error_type,
|
||||||
|
NULL, NULL))
|
||||||
|
{
|
||||||
|
display->xkb_base_event_type = -1;
|
||||||
|
g_message ("could not find XKB extension.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int mask = XkbBellNotifyMask;
|
||||||
|
gboolean visual_bell_auto_reset = FALSE;
|
||||||
|
/* TRUE if and when non-broken version is available */
|
||||||
|
XkbSelectEvents (display->xdisplay,
|
||||||
|
XkbUseCoreKbd,
|
||||||
|
XkbBellNotifyMask,
|
||||||
|
XkbBellNotifyMask);
|
||||||
|
XkbChangeEnabledControls (display->xdisplay,
|
||||||
|
XkbUseCoreKbd,
|
||||||
|
XkbAudibleBellMask,
|
||||||
|
meta_prefs_bell_is_audible ()
|
||||||
|
? XkbAudibleBellMask : 0);
|
||||||
|
if (visual_bell_auto_reset) {
|
||||||
|
XkbSetAutoResetControls (display->xdisplay,
|
||||||
|
XkbAudibleBellMask,
|
||||||
|
&mask,
|
||||||
|
&mask);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_bell_shutdown (MetaDisplay *display)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
/* TODO: persist initial bell state in display, reset here */
|
||||||
|
XkbChangeEnabledControls (display->xdisplay,
|
||||||
|
XkbUseCoreKbd,
|
||||||
|
XkbAudibleBellMask,
|
||||||
|
XkbAudibleBellMask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_bell_notify_frame_destroy (MetaFrame *frame)
|
||||||
|
{
|
||||||
|
if (frame->is_flashing)
|
||||||
|
g_idle_remove_by_data (frame);
|
||||||
|
}
|
34
src/bell.h
Normal file
34
src/bell.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* Metacity visual bell */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002 Sun Microsystems Inc.
|
||||||
|
*
|
||||||
|
* 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 of the
|
||||||
|
* License, 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., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
#endif
|
||||||
|
#include "display.h"
|
||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
void meta_bell_notify (MetaDisplay *display, XkbAnyEvent *xkb_ev);
|
||||||
|
#endif
|
||||||
|
void meta_bell_set_audible (MetaDisplay *display, gboolean audible);
|
||||||
|
gboolean meta_bell_init (MetaDisplay *display);
|
||||||
|
void meta_bell_shutdown (MetaDisplay *display);
|
||||||
|
void meta_bell_notify_frame_destroy (MetaFrame *frame);
|
@ -42,7 +42,8 @@ typedef enum
|
|||||||
META_FRAME_MAXIMIZED = 1 << 9,
|
META_FRAME_MAXIMIZED = 1 << 9,
|
||||||
META_FRAME_ALLOWS_SHADE = 1 << 10,
|
META_FRAME_ALLOWS_SHADE = 1 << 10,
|
||||||
META_FRAME_ALLOWS_MOVE = 1 << 11,
|
META_FRAME_ALLOWS_MOVE = 1 << 11,
|
||||||
META_FRAME_FULLSCREEN = 1 << 12
|
META_FRAME_FULLSCREEN = 1 << 12,
|
||||||
|
META_FRAME_IS_FLASHING = 1 << 13
|
||||||
} MetaFrameFlags;
|
} MetaFrameFlags;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "prefs.h"
|
#include "prefs.h"
|
||||||
#include "resizepopup.h"
|
#include "resizepopup.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
|
#include "bell.h"
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/cursorfont.h>
|
#include <X11/cursorfont.h>
|
||||||
#ifdef HAVE_SOLARIS_XINERAMA
|
#ifdef HAVE_SOLARIS_XINERAMA
|
||||||
@ -42,6 +43,9 @@
|
|||||||
#ifdef HAVE_XFREE_XINERAMA
|
#ifdef HAVE_XFREE_XINERAMA
|
||||||
#include <X11/extensions/Xinerama.h>
|
#include <X11/extensions/Xinerama.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
#endif
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define USE_GDK_DISPLAY
|
#define USE_GDK_DISPLAY
|
||||||
@ -305,6 +309,8 @@ meta_display_open (const char *name)
|
|||||||
/* we have to go ahead and do this so error handlers work */
|
/* we have to go ahead and do this so error handlers work */
|
||||||
all_displays = g_slist_prepend (all_displays, display);
|
all_displays = g_slist_prepend (all_displays, display);
|
||||||
|
|
||||||
|
meta_bell_init (display);
|
||||||
|
|
||||||
meta_display_init_keys (display);
|
meta_display_init_keys (display);
|
||||||
|
|
||||||
update_window_grab_modifiers (display);
|
update_window_grab_modifiers (display);
|
||||||
@ -1822,6 +1828,19 @@ event_callback (XEvent *event,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
if (event->type == display->xkb_base_event_type)
|
||||||
|
{
|
||||||
|
XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
|
||||||
|
|
||||||
|
switch (xkb_ev->xkb_type)
|
||||||
|
{
|
||||||
|
case XkbBellNotify:
|
||||||
|
meta_bell_notify (display, xkb_ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3846,4 +3865,9 @@ prefs_changed_callback (MetaPreference pref,
|
|||||||
|
|
||||||
g_slist_free (windows);
|
g_slist_free (windows);
|
||||||
}
|
}
|
||||||
|
else if (pref == META_PREF_AUDIBLE_BELL)
|
||||||
|
{
|
||||||
|
MetaDisplay *display = data;
|
||||||
|
meta_bell_set_audible (display, meta_prefs_bell_is_audible ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,6 +245,9 @@ struct _MetaDisplay
|
|||||||
MetaRectangle grab_current_window_pos;
|
MetaRectangle grab_current_window_pos;
|
||||||
MetaResizePopup *grab_resize_popup;
|
MetaResizePopup *grab_resize_popup;
|
||||||
GTimeVal grab_last_moveresize_time;
|
GTimeVal grab_last_moveresize_time;
|
||||||
|
#ifdef HAVE_XKB
|
||||||
|
int xkb_base_event_type;
|
||||||
|
#endif
|
||||||
#ifdef HAVE_XSYNC
|
#ifdef HAVE_XSYNC
|
||||||
/* alarm monitoring client's _METACITY_UPDATE_COUNTER */
|
/* alarm monitoring client's _METACITY_UPDATE_COUNTER */
|
||||||
XSyncAlarm grab_update_alarm;
|
XSyncAlarm grab_update_alarm;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
|
#include "bell.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "keybindings.h"
|
#include "keybindings.h"
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ meta_window_ensure_frame (MetaWindow *window)
|
|||||||
frame->current_cursor = 0;
|
frame->current_cursor = 0;
|
||||||
|
|
||||||
frame->mapped = FALSE;
|
frame->mapped = FALSE;
|
||||||
|
frame->is_flashing = FALSE;
|
||||||
|
|
||||||
attrs.event_mask = EVENT_MASK;
|
attrs.event_mask = EVENT_MASK;
|
||||||
|
|
||||||
@ -159,6 +161,7 @@ meta_window_destroy_frame (MetaWindow *window)
|
|||||||
|
|
||||||
frame = window->frame;
|
frame = window->frame;
|
||||||
|
|
||||||
|
meta_bell_notify_frame_destroy (frame);
|
||||||
meta_ui_remove_frame (window->screen->ui, frame->xwindow);
|
meta_ui_remove_frame (window->screen->ui, frame->xwindow);
|
||||||
|
|
||||||
/* Unparent the client window; it may be destroyed,
|
/* Unparent the client window; it may be destroyed,
|
||||||
@ -255,6 +258,9 @@ meta_frame_get_flags (MetaFrame *frame)
|
|||||||
if (frame->window->fullscreen)
|
if (frame->window->fullscreen)
|
||||||
flags |= META_FRAME_FULLSCREEN;
|
flags |= META_FRAME_FULLSCREEN;
|
||||||
|
|
||||||
|
if (frame->is_flashing)
|
||||||
|
flags |= META_FRAME_IS_FLASHING;
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ struct _MetaFrame
|
|||||||
int bottom_height;
|
int bottom_height;
|
||||||
|
|
||||||
guint mapped : 1;
|
guint mapped : 1;
|
||||||
|
guint is_flashing : 1; /* used by the visual bell flash */
|
||||||
};
|
};
|
||||||
|
|
||||||
void meta_window_ensure_frame (MetaWindow *window);
|
void meta_window_ensure_frame (MetaWindow *window);
|
||||||
|
@ -177,6 +177,57 @@
|
|||||||
</locale>
|
</locale>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
|
<schema>
|
||||||
|
<key>/apps/metacity/visual_bell</key>
|
||||||
|
<applyto>/apps/metacity/general/visual_bell</applyto>
|
||||||
|
<owner>metacity</owner>
|
||||||
|
<type>bool</type>
|
||||||
|
<default>false</default>
|
||||||
|
<locale name="C">
|
||||||
|
<short>Enable Visual Bell</short>
|
||||||
|
<long>Turns on a visual indication when an application or the system
|
||||||
|
issues a 'bell' or 'beep'; useful for the hard-of-hearing and for use
|
||||||
|
in noisy environments, or when 'audible bell' is off.
|
||||||
|
</long>
|
||||||
|
</locale>
|
||||||
|
</schema>
|
||||||
|
|
||||||
|
<schema>
|
||||||
|
<key>/schemas/apps/metacity/general/audible_bell</key>
|
||||||
|
<applyto>/apps/metacity/general/audible_bell</applyto>
|
||||||
|
<owner>metacity</owner>
|
||||||
|
<type>bool</type>
|
||||||
|
<default>true</default>
|
||||||
|
<locale name="C">
|
||||||
|
<short>System Bell is Audible</short>
|
||||||
|
<long>Determines whether applications or the system can generate audible
|
||||||
|
'beeps'; may be used in conjunction with 'visual bell' to
|
||||||
|
allow silent 'beeps'.
|
||||||
|
</long>
|
||||||
|
</locale>
|
||||||
|
</schema>
|
||||||
|
|
||||||
|
<schema>
|
||||||
|
<key>/schemas/apps/metacity/general/visual_bell_type</key>
|
||||||
|
<applyto>/apps/metacity/general/visual_bell_type</applyto>
|
||||||
|
<owner>metacity</owner>
|
||||||
|
<type>string</type>
|
||||||
|
<default>fullscreen</default>
|
||||||
|
<locale name="C">
|
||||||
|
<short>Visual Bell Type</short>
|
||||||
|
<long>
|
||||||
|
Tells Metacity how to implement the visual indication that
|
||||||
|
the system bell or another application 'bell' indicator has
|
||||||
|
been rung. Currently there are two valid values, "fullscreen",
|
||||||
|
which causes a fullscreen white-black flash, and "frame_flash" which
|
||||||
|
causes the titlebar of the application which sent the bell signal to
|
||||||
|
flash. If the application which sent the bell is unknown (as is
|
||||||
|
usually the case for the default "system beep"), the currently
|
||||||
|
focussed window's titlebar is flashed.
|
||||||
|
</long>
|
||||||
|
</locale>
|
||||||
|
</schema>
|
||||||
|
|
||||||
<schema>
|
<schema>
|
||||||
<key>/schemas/apps/metacity/workspace_names/name</key>
|
<key>/schemas/apps/metacity/workspace_names/name</key>
|
||||||
<applyto>/apps/metacity/workspace_names/name_1</applyto>
|
<applyto>/apps/metacity/workspace_names/name_1</applyto>
|
||||||
|
126
src/prefs.c
126
src/prefs.c
@ -54,6 +54,10 @@
|
|||||||
|
|
||||||
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
|
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
|
||||||
|
|
||||||
|
#define KEY_VISUAL_BELL "/apps/metacity/general/visual_bell"
|
||||||
|
#define KEY_AUDIBLE_BELL "/apps/metacity/general/audible_bell"
|
||||||
|
#define KEY_VISUAL_BELL_TYPE "/apps/metacity/general/visual_bell_type"
|
||||||
|
|
||||||
#ifdef HAVE_GCONF
|
#ifdef HAVE_GCONF
|
||||||
static GConfClient *default_client = NULL;
|
static GConfClient *default_client = NULL;
|
||||||
static GList *changes = NULL;
|
static GList *changes = NULL;
|
||||||
@ -73,6 +77,9 @@ static gboolean application_based = FALSE;
|
|||||||
static gboolean disable_workarounds = FALSE;
|
static gboolean disable_workarounds = FALSE;
|
||||||
static gboolean auto_raise = FALSE;
|
static gboolean auto_raise = FALSE;
|
||||||
static gboolean auto_raise_delay = 500;
|
static gboolean auto_raise_delay = 500;
|
||||||
|
static gboolean provide_visual_bell = TRUE;
|
||||||
|
static gboolean bell_is_audible = TRUE;
|
||||||
|
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_INVALID;
|
||||||
static MetaButtonLayout button_layout = {
|
static MetaButtonLayout button_layout = {
|
||||||
{
|
{
|
||||||
META_BUTTON_FUNCTION_MENU,
|
META_BUTTON_FUNCTION_MENU,
|
||||||
@ -98,6 +105,8 @@ static gboolean update_titlebar_font (const char *value);
|
|||||||
static gboolean update_mouse_button_mods (const char *value);
|
static gboolean update_mouse_button_mods (const char *value);
|
||||||
static gboolean update_focus_mode (const char *value);
|
static gboolean update_focus_mode (const char *value);
|
||||||
static gboolean update_theme (const char *value);
|
static gboolean update_theme (const char *value);
|
||||||
|
static gboolean update_visual_bell (gboolean v1, gboolean v2);
|
||||||
|
static gboolean update_visual_bell_type (const char *value);
|
||||||
static gboolean update_num_workspaces (int value);
|
static gboolean update_num_workspaces (int value);
|
||||||
static gboolean update_application_based (gboolean value);
|
static gboolean update_application_based (gboolean value);
|
||||||
static gboolean update_disable_workarounds (gboolean value);
|
static gboolean update_disable_workarounds (gboolean value);
|
||||||
@ -273,7 +282,7 @@ meta_prefs_init (void)
|
|||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
char *str_val;
|
char *str_val;
|
||||||
int int_val;
|
int int_val;
|
||||||
gboolean bool_val;
|
gboolean bool_val, bool_val_2;
|
||||||
|
|
||||||
if (default_client != NULL)
|
if (default_client != NULL)
|
||||||
return;
|
return;
|
||||||
@ -360,6 +369,20 @@ meta_prefs_init (void)
|
|||||||
g_free (str_val);
|
g_free (str_val);
|
||||||
#endif /* HAVE_GCONF */
|
#endif /* HAVE_GCONF */
|
||||||
|
|
||||||
|
bool_val = gconf_client_get_bool (default_client, KEY_VISUAL_BELL,
|
||||||
|
&err);
|
||||||
|
cleanup_error (&err);
|
||||||
|
bool_val_2 = gconf_client_get_bool (default_client, KEY_AUDIBLE_BELL,
|
||||||
|
&err);
|
||||||
|
cleanup_error (&err);
|
||||||
|
update_visual_bell (bool_val, bool_val_2);
|
||||||
|
|
||||||
|
str_val = gconf_client_get_string (default_client, KEY_VISUAL_BELL_TYPE,
|
||||||
|
&err);
|
||||||
|
cleanup_error (&err);
|
||||||
|
update_visual_bell_type (str_val);
|
||||||
|
g_free (str_val);
|
||||||
|
|
||||||
/* Load keybindings prefs */
|
/* Load keybindings prefs */
|
||||||
init_bindings ();
|
init_bindings ();
|
||||||
|
|
||||||
@ -674,6 +697,37 @@ change_notify (GConfClient *client,
|
|||||||
if (update_button_layout (str))
|
if (update_button_layout (str))
|
||||||
queue_changed (META_PREF_BUTTON_LAYOUT);
|
queue_changed (META_PREF_BUTTON_LAYOUT);
|
||||||
}
|
}
|
||||||
|
else if (strcmp (key, KEY_VISUAL_BELL) == 0)
|
||||||
|
{
|
||||||
|
gboolean b;
|
||||||
|
|
||||||
|
b = value ? gconf_value_get_bool (value) : provide_visual_bell;
|
||||||
|
if (update_visual_bell (b, bell_is_audible))
|
||||||
|
queue_changed (META_PREF_VISUAL_BELL);
|
||||||
|
}
|
||||||
|
else if (strcmp (key, KEY_AUDIBLE_BELL) == 0)
|
||||||
|
{
|
||||||
|
gboolean b;
|
||||||
|
|
||||||
|
b = value ? gconf_value_get_bool (value) : bell_is_audible;
|
||||||
|
if (update_visual_bell (provide_visual_bell, b))
|
||||||
|
queue_changed (META_PREF_AUDIBLE_BELL);
|
||||||
|
}
|
||||||
|
else if (strcmp (key, KEY_VISUAL_BELL_TYPE) == 0)
|
||||||
|
{
|
||||||
|
const char * str;
|
||||||
|
|
||||||
|
if (value && value->type != GCONF_VALUE_STRING)
|
||||||
|
{
|
||||||
|
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
|
||||||
|
KEY_VISUAL_BELL_TYPE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = value ? gconf_value_get_string (value) : NULL;
|
||||||
|
if (update_visual_bell_type (str))
|
||||||
|
queue_changed (META_PREF_VISUAL_BELL_TYPE);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
|
meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
|
||||||
@ -803,8 +857,48 @@ update_use_system_font (gboolean value)
|
|||||||
|
|
||||||
return old != value;
|
return old != value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MetaVisualBellType
|
||||||
|
visual_bell_type_from_string (const char *value)
|
||||||
|
{
|
||||||
|
if (!strcmp (value, "fullscreen"))
|
||||||
|
{
|
||||||
|
return META_VISUAL_BELL_FULLSCREEN_FLASH;
|
||||||
|
}
|
||||||
|
else if (!strcmp (value, "frame_flash"))
|
||||||
|
{
|
||||||
|
return META_VISUAL_BELL_FRAME_FLASH;
|
||||||
|
}
|
||||||
|
return META_VISUAL_BELL_FULLSCREEN_FLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
update_visual_bell_type (const char *value)
|
||||||
|
{
|
||||||
|
MetaVisualBellType old_bell_type;
|
||||||
|
|
||||||
|
old_bell_type = visual_bell_type;
|
||||||
|
visual_bell_type = visual_bell_type_from_string (value);
|
||||||
|
|
||||||
|
return (visual_bell_type != old_bell_type);
|
||||||
|
}
|
||||||
#endif /* HAVE_GCONF */
|
#endif /* HAVE_GCONF */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
update_visual_bell (gboolean visual_bell, gboolean audible_bell)
|
||||||
|
{
|
||||||
|
gboolean old_visual = provide_visual_bell;
|
||||||
|
gboolean old_audible = bell_is_audible;
|
||||||
|
gboolean has_changed;
|
||||||
|
|
||||||
|
provide_visual_bell = visual_bell;
|
||||||
|
bell_is_audible = audible_bell;
|
||||||
|
has_changed = (old_visual != provide_visual_bell) ||
|
||||||
|
(old_audible != bell_is_audible);
|
||||||
|
|
||||||
|
return has_changed;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GCONF
|
#ifdef HAVE_GCONF
|
||||||
static gboolean
|
static gboolean
|
||||||
update_titlebar_font (const char *value)
|
update_titlebar_font (const char *value)
|
||||||
@ -1186,6 +1280,18 @@ meta_preference_to_string (MetaPreference pref)
|
|||||||
case META_PREF_WORKSPACE_NAMES:
|
case META_PREF_WORKSPACE_NAMES:
|
||||||
return "WORKSPACE_NAMES";
|
return "WORKSPACE_NAMES";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case META_PREF_VISUAL_BELL:
|
||||||
|
return "VISUAL_BELL";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case META_PREF_AUDIBLE_BELL:
|
||||||
|
return "AUDIBLE_BELL";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case META_PREF_VISUAL_BELL_TYPE:
|
||||||
|
return "VISUAL_BELL_TYPE";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "(unknown)";
|
return "(unknown)";
|
||||||
@ -1750,6 +1856,24 @@ meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
|
|||||||
*button_layout_p = button_layout;
|
*button_layout_p = button_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_prefs_get_visual_bell ()
|
||||||
|
{
|
||||||
|
return provide_visual_bell;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_prefs_bell_is_audible ()
|
||||||
|
{
|
||||||
|
return bell_is_audible;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaVisualBellType
|
||||||
|
meta_prefs_get_visual_bell_type ()
|
||||||
|
{
|
||||||
|
return visual_bell_type;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_prefs_get_screen_bindings (const MetaKeyPref **bindings,
|
meta_prefs_get_screen_bindings (const MetaKeyPref **bindings,
|
||||||
int *n_bindings)
|
int *n_bindings)
|
||||||
|
17
src/prefs.h
17
src/prefs.h
@ -42,7 +42,10 @@ typedef enum
|
|||||||
META_PREF_DISABLE_WORKAROUNDS,
|
META_PREF_DISABLE_WORKAROUNDS,
|
||||||
META_PREF_COMMANDS,
|
META_PREF_COMMANDS,
|
||||||
META_PREF_BUTTON_LAYOUT,
|
META_PREF_BUTTON_LAYOUT,
|
||||||
META_PREF_WORKSPACE_NAMES
|
META_PREF_WORKSPACE_NAMES,
|
||||||
|
META_PREF_VISUAL_BELL,
|
||||||
|
META_PREF_AUDIBLE_BELL,
|
||||||
|
META_PREF_VISUAL_BELL_TYPE
|
||||||
} MetaPreference;
|
} MetaPreference;
|
||||||
|
|
||||||
typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
|
typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
|
||||||
@ -213,6 +216,18 @@ void meta_prefs_get_window_binding (const char *name,
|
|||||||
unsigned int *keysym,
|
unsigned int *keysym,
|
||||||
MetaVirtualModifier *modifiers);
|
MetaVirtualModifier *modifiers);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
META_VISUAL_BELL_INVALID = 0,
|
||||||
|
META_VISUAL_BELL_FULLSCREEN_FLASH,
|
||||||
|
META_VISUAL_BELL_FRAME_FLASH
|
||||||
|
|
||||||
|
} MetaVisualBellType;
|
||||||
|
|
||||||
|
gboolean meta_prefs_get_visual_bell (void);
|
||||||
|
gboolean meta_prefs_bell_is_audible (void);
|
||||||
|
MetaVisualBellType meta_prefs_get_visual_bell_type (void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -523,6 +523,7 @@ meta_screen_new (MetaDisplay *display,
|
|||||||
screen->current_cursor = -1; /* invalid/unset */
|
screen->current_cursor = -1; /* invalid/unset */
|
||||||
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
|
screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
|
||||||
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
|
screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
|
||||||
|
screen->flash_window = None;
|
||||||
|
|
||||||
screen->wm_sn_selection_window = new_wm_sn_owner;
|
screen->wm_sn_selection_window = new_wm_sn_owner;
|
||||||
screen->wm_sn_atom = wm_sn_atom;
|
screen->wm_sn_atom = wm_sn_atom;
|
||||||
|
@ -70,6 +70,8 @@ struct _MetaScreen
|
|||||||
|
|
||||||
MetaCursor current_cursor;
|
MetaCursor current_cursor;
|
||||||
|
|
||||||
|
Window flash_window;
|
||||||
|
|
||||||
Window wm_sn_selection_window;
|
Window wm_sn_selection_window;
|
||||||
Atom wm_sn_atom;
|
Atom wm_sn_atom;
|
||||||
Time wm_sn_timestamp;
|
Time wm_sn_timestamp;
|
||||||
|
@ -4761,7 +4761,9 @@ theme_get_style (MetaTheme *theme,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & META_FRAME_HAS_FOCUS)
|
/* re invert the styles used for focus/unfocussed while flashing a frame */
|
||||||
|
if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
|
||||||
|
|| (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
|
||||||
focus = META_FRAME_FOCUS_YES;
|
focus = META_FRAME_FOCUS_YES;
|
||||||
else
|
else
|
||||||
focus = META_FRAME_FOCUS_NO;
|
focus = META_FRAME_FOCUS_NO;
|
||||||
|
Loading…
Reference in New Issue
Block a user