📄 magnifier.c
字号:
/* * AT-SPI - Assistive Technology Service Provider Interface * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) * * Copyright 2001 Sun Microsystems Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include "config.h"#include "magnifier.h"#include "magnifier-private.h"#include "zoom-region.h"#include "zoom-region-private.h"#include "gmag-events.h"#include "GNOME_Magnifier.h"#include <stdlib.h>#include <string.h>#include <strings.h>#include <X11/Xatom.h>#ifdef HAVE_XFIXES#include <X11/extensions/Xfixes.h>#ifdef HAVE_COMPOSITE#include <X11/extensions/shape.h>#include <X11/extensions/Xcomposite.h>#endif /* HAVE_COMPOSITE */#endif /* HAVE_XFIXES */#include <libbonobo.h>#include <login-helper/login-helper.h>#include <gdk-pixbuf/gdk-pixbuf-io.h>#include <gdk/gdkx.h>#include <gdk/gdk.h>#include <gtk/gtk.h>/* if you #define this, don't forget to set MAG_CLIENT_DEBUG env variable */#define DEBUG_CLIENT_CALLS#ifdef DEBUG_CLIENT_CALLSstatic gboolean client_debug = FALSE;#define DBG(a) if (client_debug) { (a); }#else#define DBG(a)#endiftypedef struct{ LoginHelper parent; Magnifier *mag;} MagLoginHelper;typedef struct { LoginHelperClass parent_class;} MagLoginHelperClass;static GObjectClass *parent_class = NULL;enum { STRUT_LEFT = 0, STRUT_RIGHT = 1, STRUT_TOP = 2, STRUT_BOTTOM = 3, STRUT_LEFT_START = 4, STRUT_LEFT_END = 5, STRUT_RIGHT_START = 6, STRUT_RIGHT_END = 7, STRUT_TOP_START = 8, STRUT_TOP_END = 9, STRUT_BOTTOM_START = 10, STRUT_BOTTOM_END = 11};enum { MAGNIFIER_SOURCE_DISPLAY_PROP, MAGNIFIER_TARGET_DISPLAY_PROP, MAGNIFIER_SOURCE_SIZE_PROP, MAGNIFIER_TARGET_SIZE_PROP, MAGNIFIER_CURSOR_SET_PROP, MAGNIFIER_CURSOR_SIZE_PROP, MAGNIFIER_CURSOR_ZOOM_PROP, MAGNIFIER_CURSOR_COLOR_PROP, MAGNIFIER_CURSOR_HOTSPOT_PROP, MAGNIFIER_CURSOR_DEFAULT_SIZE_PROP, MAGNIFIER_CROSSWIRE_SIZE_PROP, MAGNIFIER_CROSSWIRE_CLIP_PROP, MAGNIFIER_CROSSWIRE_COLOR_PROP} PropIdx;typedef struct{ GNOME_Magnifier_RectBounds rectbounds; GNOME_Magnifier_RectBounds viewport; gboolean is_managed; gint scroll_policy; gfloat contrast; gfloat zx; gfloat zy; gint32 xalign; gint32 yalign; guint32 border_color; gint32 border_size; gchar *smoothing_type; gboolean inverse;} MagnifierZoomRegionSaveProps;#ifdef DEBUG_CLIENT_CALLSgchar* mag_prop_names[MAGNIFIER_CROSSWIRE_COLOR_PROP + 1] = { "SOURCE_DISPLAY", "TARGET_DISPLAY", "SOURCE_SIZE", "TARGET_SIZE", "CURSOR_SET", "CURSOR_SIZE", "CURSOR_ZOOM", "CURSOR_COLOR", "CURSOR_HOTSPOT", "CURSOR_DEFAULT_SIZE", "CROSSWIRE_SIZE", "CROSSWIRE_CLIP", "CROSSWIRE_COLOR"};#endifstatic int _x_error = 0;static Magnifier *_this_magnifier = NULL;extern gint fixes_event_base;static void magnifier_init_cursor_set (Magnifier *magnifier, gchar *cursor_set);static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);static gboolean magnifier_check_set_struts (Magnifier *magnifier);static gboolean magnifier_reset_struts_at_idle (gpointer data);static void magnifier_init_window (Magnifier *magnifier, GdkScreen *screen);static void magnifier_adjust_source_size (Magnifier *magnifier);static gboolean _is_override_redirect = FALSE;static Window*mag_login_helper_get_raise_windows (LoginHelper *helper){ Window *mainwin = NULL; MagLoginHelper *mag_helper = (MagLoginHelper *) helper; Magnifier *magnifier = MAGNIFIER (mag_helper->mag); if (magnifier && magnifier->priv && magnifier->priv->w) { mainwin = g_new0 (Window, 2); mainwin[0] = GDK_WINDOW_XWINDOW (magnifier->priv->w->window); mainwin[1] = None; } return mainwin;}static LoginHelperDeviceReqFlagsmag_login_helper_get_device_reqs (LoginHelper *helper){ /* means "don't grab the xserver or core pointer", and "we need to raise windows" */ return LOGIN_HELPER_GUI_EVENTS | LOGIN_HELPER_POST_WINDOWS | LOGIN_HELPER_CORE_POINTER;}static gbooleanmag_login_helper_set_safe (LoginHelper *helper, gboolean ignored){ return TRUE;}static voidmag_login_helper_class_init (MagLoginHelperClass *klass){ LoginHelperClass *login_helper_class = LOGIN_HELPER_CLASS(klass); login_helper_class->get_raise_windows = mag_login_helper_get_raise_windows; login_helper_class->get_device_reqs = mag_login_helper_get_device_reqs; login_helper_class->set_safe = mag_login_helper_set_safe;}static voidmag_login_helper_init (MagLoginHelper *helper){ helper->mag = NULL; /* we set this with mag_login_helper_set_magnifier */}static voidmag_login_helper_set_magnifier (MagLoginHelper *helper, Magnifier *mag){ if (helper) helper->mag = mag;}BONOBO_TYPE_FUNC (MagLoginHelper, LOGIN_HELPER_TYPE, mag_login_helper)gbooleanmagnifier_error_check (void){ if (_x_error) { _x_error = 0; return TRUE; } return FALSE;}static intmagnifier_x_error_handler (Display *display, XErrorEvent *error){ if (error->error_code == BadAlloc) { _x_error = error->error_code; } else { return -1; } return 0;}static gbooleancan_open_display (gchar *display_name){ Display *d; if ((d = XOpenDisplay (display_name))) { XCloseDisplay (d); return TRUE; } return FALSE;}static voidmagnifier_warp_cursor_to_screen (Magnifier *magnifier){ int x, y, unused_x, unused_y; unsigned int mask; Window root_return, child_return; if (magnifier->source_display) { if (!XQueryPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display), GDK_WINDOW_XWINDOW (magnifier->priv->root), &root_return, &child_return, &x, &y, &unused_x, &unused_y, &mask)) { XWarpPointer (GDK_DISPLAY_XDISPLAY (magnifier->source_display), None, GDK_WINDOW_XWINDOW (magnifier->priv->root), 0, 0, 0, 0, x, y); XSync (GDK_DISPLAY_XDISPLAY (magnifier->source_display), FALSE); } }}static voidmagnifier_zoom_regions_mark_dirty (Magnifier *magnifier, GNOME_Magnifier_RectBounds rect_bounds){ GList *list; g_assert (magnifier); list = magnifier->zoom_regions; while (list) { /* propagate the expose events to the zoom regions */ GNOME_Magnifier_ZoomRegion zoom_region; CORBA_Environment ev; zoom_region = list->data; CORBA_exception_init (&ev); if (zoom_region) GNOME_Magnifier_ZoomRegion_markDirty (CORBA_Object_duplicate (zoom_region, &ev), &rect_bounds, &ev); list = g_list_next (list); }}voidmagnifier_set_cursor_from_pixbuf (Magnifier *magnifier, GdkPixbuf *cursor_pixbuf){ GdkPixmap *pixmap, *mask; gint width, height; GdkGC *gc; GdkDrawable *drawable = magnifier->priv->w->window; if (magnifier->priv->cursor) { g_object_unref (magnifier->priv->cursor); magnifier->priv->cursor = NULL; } if (drawable && cursor_pixbuf) { const gchar *xhot_string = NULL, *yhot_string = NULL; width = gdk_pixbuf_get_width (cursor_pixbuf); height = gdk_pixbuf_get_height (cursor_pixbuf); pixmap = gdk_pixmap_new (drawable, width, height, -1); gc = gdk_gc_new (pixmap); if (GDK_IS_DRAWABLE (pixmap)) gdk_draw_pixbuf (pixmap, gc, cursor_pixbuf, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); else DBG (g_warning ("empty cursor pixmap created.")); mask = gdk_pixmap_new (drawable, width, height, 1); gdk_pixbuf_render_threshold_alpha (cursor_pixbuf, mask, 0, 0, 0, 0, width, height, 200); g_object_unref (gc); magnifier->priv->cursor = pixmap; magnifier->priv->cursor_mask = mask; xhot_string = gdk_pixbuf_get_option (cursor_pixbuf,"x_hot"); yhot_string = gdk_pixbuf_get_option (cursor_pixbuf,"y_hot"); if (xhot_string) magnifier->cursor_hotspot.x = atoi (xhot_string); if (yhot_string) magnifier->cursor_hotspot.y = atoi (yhot_string); if (pixmap) { gdk_drawable_get_size (pixmap, &magnifier->priv->cursor_default_size_x, &magnifier->priv->cursor_default_size_y); magnifier->priv->cursor_hotspot_x = magnifier->cursor_hotspot.x; magnifier->priv->cursor_hotspot_y = magnifier->cursor_hotspot.y; } }}GdkPixbuf *magnifier_get_pixbuf_for_name (Magnifier *magnifier, const gchar *cursor_name){ GdkPixbuf *retval = NULL; if (magnifier->priv->cursorlist) retval = g_hash_table_lookup (magnifier->priv->cursorlist, cursor_name); if (retval) g_object_ref (retval); return retval;}voidmagnifier_set_cursor_pixmap_by_name (Magnifier *magnifier, const gchar *cursor_name, gboolean source_fallback){ GdkPixbuf *pixbuf; /* search local table; if not found, use source screen's cursor if source_fallback is TRUE */ if ((pixbuf = magnifier_get_pixbuf_for_name (magnifier, cursor_name)) == NULL) {#ifndef HAVE_XFIXES source_fallback = FALSE;#endif if (source_fallback == TRUE) { pixbuf = gmag_events_get_source_pixbuf (magnifier); } else { pixbuf = magnifier_get_pixbuf_for_name (magnifier, "default"); } } magnifier_set_cursor_from_pixbuf (magnifier, pixbuf); if (pixbuf) g_object_unref (pixbuf);}voidmagnifier_notify_damage (Magnifier *magnifier, XRectangle *rect){ GNOME_Magnifier_RectBounds rect_bounds; rect_bounds.x1 = rect->x; rect_bounds.y1 = rect->y; rect_bounds.x2 = rect->x + rect->width; rect_bounds.y2 = rect->y + rect->height;#undef DEBUG_DAMAGE#ifdef DEBUG_DAMAGE g_message ("damage"); g_message ("dirty %d, %d to %d, %d", rect_bounds.x1, rect_bounds.y1, rect_bounds.x2, rect_bounds.y2);#endif magnifier_zoom_regions_mark_dirty (magnifier, rect_bounds);}static voidmagnifier_set_extension_listeners (Magnifier *magnifier, GdkWindow *root){ gmag_events_client_init (magnifier); magnifier->source_initialized = TRUE;}static voidmagnifier_size_allocate (GtkWidget *widget){ magnifier_check_set_struts (_this_magnifier);}static voidmagnifier_realize (GtkWidget *widget){ XWMHints wm_hints; Atom wm_window_protocols[2]; Atom wm_type_atoms[1]; Atom net_wm_window_type; GdkDisplay *target_display = gdk_drawable_get_display (widget->window); static gboolean initialized = FALSE;#ifndef MAG_WINDOW_OVERRIDE_REDIRECT if (!initialized) { wm_window_protocols[0] = gdk_x11_get_xatom_by_name_for_display (target_display, "WM_DELETE_WINDOW"); wm_window_protocols[1] = gdk_x11_get_xatom_by_name_for_display (target_display, "_NET_WM_PING"); /* use DOCK until Metacity RFE for new window type goes in */ wm_type_atoms[0] = gdk_x11_get_xatom_by_name_for_display (target_display, "_NET_WM_WINDOW_TYPE_DOCK"); } wm_hints.flags = InputHint; wm_hints.input = False; XSetWMHints (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XWINDOW (widget->window), &wm_hints); XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2); net_wm_window_type = gdk_x11_get_xatom_by_name_for_display (target_display, "_NET_WM_WINDOW_TYPE"); if (net_wm_window_type && wm_type_atoms[0]) XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XWINDOW (widget->window), net_wm_window_type, XA_ATOM, 32, PropModeReplace, (guchar *)wm_type_atoms, 1);#else#endif /* TODO: make sure this works/is reset if the DISPLAY * (as well as the SCREEN) changes. */ XSetErrorHandler (magnifier_x_error_handler);}GdkWindow*magnifier_get_root (Magnifier *magnifier){ if (!magnifier->priv->root && magnifier->source_display) { magnifier->priv->root = gdk_screen_get_root_window ( gdk_display_get_screen (magnifier->source_display, magnifier->source_screen_num)); } return magnifier->priv->root;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -