00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "magnifier.h"
00026 #include "magnifier-private.h"
00027 #include "gmag-events.h"
00028
00029 #include <stdlib.h>
00030
00031 #include <X11/Xlib.h>
00032 #include <X11/extensions/Xfixes.h>
00033 #include <X11/extensions/Xdamage.h>
00034 #ifdef HAVE_COMPOSITE
00035 #include <X11/extensions/Xrender.h>
00036 #include <X11/extensions/Xcomposite.h>
00037 #endif
00038
00039 #include <glib.h>
00040
00041 #include <gdk/gdkx.h>
00042 #include <gtk/gtk.h>
00043
00044 static Display *dpy_conn = NULL;
00045 static guint dpy_gsource = 0;
00046 static Window root_window, mag_window;
00047
00048 static gboolean use_damage, use_composite;
00049
00050 gint fixes_event_base = 0, fixes_error_base;
00051 static gint damage_event_base, damage_error_base;
00052 static Damage root_window_damage;
00053 static XserverRegion gmag_events_tmp_region;
00054 #ifdef HAVE_COMPOSITE
00055 static GQueue *mag_windows_list;
00056 static Damage off_screen_damage;
00057 static Picture off_screen_picture;
00058 static XserverRegion off_screen_region;
00059 static XserverRegion tmp_region, new_region, old_region, exp_region;
00060 #endif
00061
00062 #define EVENTS_DEBUG
00063 #undef EVENTS_DEBUG
00064
00065 #ifdef EVENTS_DEBUG
00066
00067 #define DAMAGE_DEBUG
00068 #undef DAMAGE_DEBUG
00069
00070 #ifdef HAVE_COMPOSITE
00071 #define COMPOSITE_DEBUG
00072 #undef COMPOSITE_DEBUG
00073 #endif
00074
00075 #define CURSOR_DEBUG
00076 #undef CURSOR_DEBUG
00077 #define XFIXES_DEBUG
00078 #undef XFIXES_DEBUG
00079
00080 #endif
00081
00082 #ifdef HAVE_COMPOSITE
00083
00084
00085
00086
00087
00088 static gint
00089 gmag_events_g_compare_func (GmagWinPtr pgmag_win, Window xwin)
00090 {
00091 if (pgmag_win->xwin == xwin)
00092 return 0;
00093
00094 return 1;
00095 }
00096
00097
00098
00099
00100 static void
00101 gmag_events_calculate_windows_clip ()
00102 {
00103 GList *elem = NULL;
00104 XserverRegion clipSum;
00105
00106 clipSum = XFixesCreateRegion (dpy_conn, 0, 0);
00107 elem = g_queue_peek_tail_link (mag_windows_list);
00108 if (!elem) {
00109 XFixesDestroyRegion (dpy_conn, clipSum);
00110 return;
00111 }
00112 do {
00113 GmagWinPtr pgmag_win = (GmagWinPtr) elem->data;
00114 if (pgmag_win->pic)
00115 if (pgmag_win->attr.map_state == IsViewable) {
00116 XFixesCopyRegion (
00117 dpy_conn,
00118 pgmag_win->clip,
00119 XFixesCreateRegionFromWindow (
00120 dpy_conn,
00121 pgmag_win->xwin,
00122 WindowRegionBounding));
00123 XFixesTranslateRegion (
00124 dpy_conn,
00125 pgmag_win->clip, pgmag_win->attr.x,
00126 pgmag_win->attr.y);
00127 XFixesCopyRegion (
00128 dpy_conn,
00129 pgmag_win->win_region,
00130 pgmag_win->clip);
00131 XFixesSubtractRegion (
00132 dpy_conn,
00133 pgmag_win->clip, pgmag_win->clip,
00134 clipSum);
00135 XFixesUnionRegion (
00136 dpy_conn,
00137 clipSum, clipSum,
00138 pgmag_win->win_region);
00139 }
00140 } while ((elem = g_list_previous (elem)));
00141 XFixesDestroyRegion (dpy_conn, clipSum);
00142 }
00143
00144
00145
00146
00147 static void
00148 gmag_events_calculate_window_clip (GmagWinPtr pgmag_win_newclip)
00149 {
00150 GList *elem = NULL;
00151 XserverRegion clipSum;
00152
00153 clipSum = XFixesCreateRegion (dpy_conn, 0, 0);
00154 elem = g_queue_peek_tail_link (mag_windows_list);
00155 if (!elem) {
00156 XFixesDestroyRegion (dpy_conn, clipSum);
00157 return;
00158 }
00159 do {
00160 GmagWinPtr pgmag_win = (GmagWinPtr) elem->data;
00161 if (pgmag_win->xwin == pgmag_win_newclip->xwin) {
00162
00163 XFixesCopyRegion (
00164 dpy_conn,
00165 pgmag_win->clip,
00166 XFixesCreateRegionFromWindow (
00167 dpy_conn,
00168 pgmag_win->xwin,
00169 WindowRegionBounding));
00170 XFixesTranslateRegion (dpy_conn,
00171 pgmag_win->clip,
00172 pgmag_win->attr.x,
00173 pgmag_win->attr.y);
00174 XFixesCopyRegion (dpy_conn,
00175 pgmag_win->win_region,
00176 pgmag_win->clip);
00177 XFixesSubtractRegion (dpy_conn,
00178 pgmag_win->clip, pgmag_win->clip,
00179 clipSum);
00180 break;
00181 }
00182 if (pgmag_win->pic)
00183 if (pgmag_win->attr.map_state == IsViewable) {
00184 XFixesUnionRegion (
00185 dpy_conn,
00186 clipSum, clipSum,
00187 pgmag_win->win_region);
00188 }
00189 } while ((elem = g_list_previous (elem)));
00190 XFixesDestroyRegion (dpy_conn, clipSum);
00191 }
00192
00193
00194
00195
00196
00197 static void
00198 gmag_events_paint_window (GmagWinPtr pgmag_win, XserverRegion region)
00199 {
00200 static XserverRegion final_clip = None;
00201
00202 if (!pgmag_win->damaged && !region)
00203 return;
00204 if (!pgmag_win->pic)
00205 return;
00206 if (pgmag_win->attr.map_state != IsViewable)
00207 return;
00208
00209 if (!final_clip)
00210 final_clip = XFixesCreateRegion (
00211 dpy_conn, 0, 0);
00212
00213 XFixesSetRegion (dpy_conn, final_clip, 0, 0);
00214
00215 if (region) {
00216 XFixesIntersectRegion (dpy_conn,
00217 final_clip, region, pgmag_win->clip);
00218 XFixesSetPictureClipRegion (dpy_conn,
00219 pgmag_win->pic,
00220 -(pgmag_win->attr.x),
00221 -(pgmag_win->attr.y), final_clip);
00222 } else
00223 XFixesSetPictureClipRegion (dpy_conn,
00224 pgmag_win->pic,
00225 -(pgmag_win->attr.x),
00226 -(pgmag_win->attr.y),
00227 pgmag_win->clip);
00228 XRenderComposite (dpy_conn, PictOpSrc,
00229 pgmag_win->pic, None, off_screen_picture,
00230 0, 0, 0, 0, pgmag_win->attr.x, pgmag_win->attr.y,
00231 pgmag_win->attr.width, pgmag_win->attr.height);
00232 }
00233
00234
00235
00236
00237
00238 static void
00239 gmag_events_paint_windows (XserverRegion exposedRegion)
00240 {
00241 GList *elem;
00242 GmagWinPtr pgmag_win;
00243
00244 elem = g_queue_peek_head_link (mag_windows_list);
00245
00246 while (elem) {
00247 pgmag_win = (GmagWinPtr) elem->data;
00248 gmag_events_paint_window (pgmag_win, exposedRegion);
00249 elem = g_list_next (elem);
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 static void
00260 gmag_events_set_default_window_attributes (XWindowAttributes *wa)
00261 {
00262 wa->x = 0;
00263 wa->y = 0;
00264 wa->width = 1;
00265 wa->height = 1;
00266 wa->border_width = 0;
00267 wa->depth = 0;
00268 wa->visual = NULL;
00269 wa->root = None;
00270 wa->class = InputOnly;
00271 wa->bit_gravity = NorthWestGravity;
00272 wa->win_gravity = NorthWestGravity;
00273 wa->backing_store = NotUseful;
00274 wa->backing_planes = 0;
00275 wa->backing_pixel = 0;
00276 wa->save_under = FALSE;
00277 wa->colormap = None;
00278 wa->map_installed = FALSE;
00279 wa->map_state = IsUnviewable;
00280 wa->all_event_masks = 0;
00281 wa->your_event_mask = 0;
00282 wa->do_not_propagate_mask = 0;
00283 wa->override_redirect = TRUE;
00284 wa->screen = NULL;
00285 }
00286
00287
00288
00289
00290
00291 static void
00292 gmag_events_add_window (Window xwin)
00293 {
00294 GmagWinPtr new;
00295 XRenderPictureAttributes pic_attr;
00296 XRenderPictFormat *format;
00297
00298 new = (GmagWinPtr) malloc (sizeof (GmagWin));
00299 if (!new)
00300 g_error ("can't allocate GmagWin (struct _GmagWin)");
00301
00302 if (!XGetWindowAttributes (dpy_conn, xwin,
00303 &new->attr))
00304 gmag_events_set_default_window_attributes (&new->attr);
00305
00306 new->xwin = xwin;
00307
00308 if (new->attr.class == InputOnly) {
00309 new->pic = None;
00310 new->damage = None;
00311 new->damaged = FALSE;
00312 new->damaged_region = None;
00313 } else {
00314 format = XRenderFindVisualFormat (
00315 dpy_conn, new->attr.visual);
00316 pic_attr.subwindow_mode = IncludeInferiors;
00317 new->pic = XRenderCreatePicture (
00318 dpy_conn, xwin, format,
00319 CPSubwindowMode, &pic_attr);
00320 new->damage = XDamageCreate (dpy_conn, xwin,
00321 XDamageReportDeltaRectangles);
00322 new->damaged = TRUE;
00323 new->damaged_region = XFixesCreateRegion (dpy_conn, 0, 0);
00324 new->clip = XFixesCreateRegion (dpy_conn, 0, 0);
00325 new->win_region = XFixesCreateRegion (dpy_conn, 0, 0);
00326 }
00327
00328 g_queue_push_tail (mag_windows_list, new);
00329 }
00330
00331
00332
00333
00334
00335 static void
00336 gmag_events_create_windows_list ()
00337 {
00338 Window root_return, parent_return, *children;
00339 guint nchildren;
00340 gint i;
00341
00342 if (!mag_windows_list)
00343 mag_windows_list = g_queue_new ();
00344
00345 XGrabServer (dpy_conn);
00346 XSelectInput (dpy_conn, root_window,
00347 SubstructureNotifyMask);
00348 XQueryTree (dpy_conn, root_window,
00349 &root_return, &parent_return, &children, &nchildren);
00350 for (i = 0; i < nchildren; i++)
00351 gmag_events_add_window (children[i]);
00352 XFree (children);
00353 XUngrabServer (dpy_conn);
00354 }
00355
00356
00357
00358
00359
00360 static void
00361 gmag_events_remove_window (Window xwin)
00362 {
00363 GList *elem = NULL;
00364 GmagWinPtr pgmag_win;
00365
00366 elem = g_queue_find_custom (mag_windows_list,
00367 (gconstpointer) xwin,
00368 (GCompareFunc) gmag_events_g_compare_func);
00369 if (elem) {
00370 pgmag_win = (GmagWinPtr) elem->data;
00371 g_queue_remove (mag_windows_list, pgmag_win);
00372 XFixesDestroyRegion (dpy_conn,
00373 pgmag_win->clip);
00374 XFixesDestroyRegion (dpy_conn,
00375 pgmag_win->win_region);
00376 free (pgmag_win);
00377 }
00378 }
00379
00380
00381
00382
00383
00384 static void
00385 gmag_events_add_win_damaged_region (Window xwin, XserverRegion region)
00386 {
00387 GList *elem;
00388 GmagWinPtr pgmag_win;
00389
00390 elem = g_queue_find_custom (mag_windows_list,
00391 (gconstpointer) xwin,
00392 (GCompareFunc) gmag_events_g_compare_func);
00393 if (elem) {
00394 pgmag_win = (GmagWinPtr) elem->data;
00395 XFixesTranslateRegion (dpy_conn, region,
00396 pgmag_win->attr.x, pgmag_win->attr.y);
00397 XFixesUnionRegion (dpy_conn,
00398 pgmag_win->damaged_region,
00399 pgmag_win->damaged_region, region);
00400 pgmag_win->damaged = TRUE;
00401 }
00402 }
00403
00404
00405
00406
00407 static void
00408 gmag_events_paint_damaged_windows ()
00409 {
00410 GList *elem;
00411 GmagWinPtr pgmag_win;
00412
00413 elem = g_queue_peek_head_link (mag_windows_list);
00414 while (elem) {
00415 pgmag_win = (GmagWinPtr) elem->data;
00416 if (pgmag_win->damaged) {
00417 gmag_events_paint_window (pgmag_win,
00418 pgmag_win->damaged_region);
00419 XFixesSetRegion (dpy_conn,
00420 pgmag_win->damaged_region, 0, 0);
00421 pgmag_win->damaged = FALSE;
00422 }
00423
00424 elem = g_list_next (elem);
00425 }
00426 }
00427
00428 static void
00429 gmag_events_circulate_notify_handler (XEvent *ev)
00430 {
00431 GList *elem;
00432 GmagWinPtr pgmag_win;
00433
00434 #ifdef COMPOSITE_DEBUG
00435 printf ("Received CirculateNotify event: 0x%x\n",
00436 (guint) ev->xcirculate.window);
00437 #endif
00438 if (ev->xcirculate.window == mag_window) {
00439 #ifdef HAVE_OVERLAY
00440 #ifdef COMPOSITE_DEBUG
00441 printf ("Overlay window = 0x%x\n",
00442 (guint) gmag_events_overlay_window);
00443 #endif
00444 #endif
00445 return;
00446 }
00447 elem = g_queue_find_custom (mag_windows_list,
00448 (gconstpointer) ev->xcirculate.window,
00449 (GCompareFunc) gmag_events_g_compare_func);
00450 if (elem) {
00451 pgmag_win = (GmagWinPtr) elem->data;
00452 g_queue_remove (mag_windows_list, pgmag_win);
00453 if (ev->xcirculate.place == PlaceOnTop) {
00454 g_queue_push_tail (mag_windows_list,
00455 pgmag_win);
00456 if (pgmag_win->attr.map_state == IsViewable) {
00457 XFixesSubtractRegion (
00458 dpy_conn,
00459 tmp_region, pgmag_win->win_region,
00460 pgmag_win->clip);
00461 XFixesUnionRegion (
00462 dpy_conn,
00463 exp_region, exp_region, tmp_region);
00464 }
00465 } else {
00466 g_queue_push_head (mag_windows_list,
00467 pgmag_win);
00468 if (pgmag_win->attr.map_state == IsViewable)
00469 XFixesUnionRegion (
00470 dpy_conn,
00471 exp_region, exp_region,
00472 pgmag_win->clip);
00473 }
00474 }
00475 }
00476
00477 static void
00478 gmag_events_configure_notify_handler (XEvent *ev)
00479 {
00480 GList *elem;
00481 GmagWinPtr pgmag_win;
00482
00483 #ifdef COMPOSITE_DEBUG
00484 printf ("Received ConfigureNotify event: 0x%x\n",
00485 (guint) ev->xconfigure.window);
00486 #endif
00487 if (ev->xconfigure.window == mag_window) {
00488 #ifdef HAVE_OVERLAY
00489 #ifdef COMPOSITE_DEBUG
00490 printf ("Overlay window = 0x%x\n",
00491 (guint) gmag_events_overlay_window);
00492 #endif
00493 #endif
00494 return;
00495 }
00496 elem = g_queue_find_custom (mag_windows_list,
00497 (gconstpointer) ev->xconfigure.window,
00498 (GCompareFunc) gmag_events_g_compare_func);
00499 if (elem) {
00500 pgmag_win = (GmagWinPtr) elem->data;
00501 if ((pgmag_win->attr.x != ev->xconfigure.x) ||
00502 (pgmag_win->attr.y != ev->xconfigure.y) ||
00503 (pgmag_win->attr.width != ev->xconfigure.width) ||
00504 (pgmag_win->attr.height != ev->xconfigure.height) ||
00505 (pgmag_win->attr.border_width !=
00506 ev->xconfigure.border_width)) {
00507
00508
00509
00510
00511
00512
00513 pgmag_win->attr.x = ev->xconfigure.x;
00514 pgmag_win->attr.y = ev->xconfigure.y;
00515 pgmag_win->attr.width = ev->xconfigure.width;
00516 pgmag_win->attr.height = ev->xconfigure.height;
00517 pgmag_win->attr.border_width =
00518 ev->xconfigure.border_width;
00519
00520 if (pgmag_win->attr.map_state == IsViewable) {
00521 XFixesCopyRegion (
00522 dpy_conn,
00523 old_region, pgmag_win->clip);
00524 gmag_events_calculate_window_clip (pgmag_win);
00525 XFixesCopyRegion (
00526 dpy_conn,
00527 new_region, pgmag_win->clip);
00528 XFixesUnionRegion (
00529 dpy_conn,
00530 exp_region, exp_region, old_region);
00531 XFixesUnionRegion (
00532 dpy_conn,
00533 exp_region, exp_region, new_region);
00534 }
00535 }
00536 if (!ev->xconfigure.above) {
00537 g_queue_remove (mag_windows_list, pgmag_win);
00538 g_queue_push_head (mag_windows_list,
00539 pgmag_win);
00540 if (pgmag_win->attr.map_state == IsViewable) {
00541 XFixesUnionRegion (
00542 dpy_conn,
00543 exp_region, exp_region,
00544 pgmag_win->win_region);
00545 }
00546 } else {
00547 elem = g_queue_find_custom (
00548 mag_windows_list,
00549 (gconstpointer) ev->xconfigure.above,
00550 (GCompareFunc) gmag_events_g_compare_func);
00551 if (elem) {
00552 g_queue_remove (mag_windows_list,
00553 pgmag_win);
00554 g_queue_insert_after (mag_windows_list,
00555 elem, pgmag_win);
00556 if (pgmag_win->attr.map_state == IsViewable) {
00557 XFixesUnionRegion (
00558 dpy_conn,
00559 exp_region, exp_region,
00560 pgmag_win->win_region);
00561 }
00562 }
00563 }
00564 }
00565 }
00566
00567 static void
00568 gmag_events_create_notify_handler (XEvent *ev)
00569 {
00570 GList *elem;
00571 GmagWinPtr pgmag_win;
00572
00573 #ifdef COMPOSITE_DEBUG
00574 printf ("Received CreateNotify event: 0x%x\n",
00575 (guint) ev->xcreatewindow.window);
00576 #endif
00577 if (ev->xcreatewindow.window == mag_window) {
00578 #ifdef HAVE_OVERLAY
00579 #ifdef COMPOSITE_DEBUG
00580 printf ("Overlay window = 0x%x\n",
00581 (guint) gmag_events_overlay_window);
00582 #endif
00583 #endif
00584 return;
00585 }
00586 gmag_events_add_window (ev->xcreatewindow.window);
00587 elem = g_queue_find_custom (mag_windows_list,
00588 (gconstpointer) ev->xcreatewindow.window,
00589 (GCompareFunc) gmag_events_g_compare_func);
00590 if (elem) {
00591 pgmag_win = (GmagWinPtr) elem->data;
00592 if (pgmag_win->attr.map_state == IsViewable) {
00593 gmag_events_calculate_window_clip (pgmag_win);
00594 XFixesUnionRegion (dpy_conn,
00595 exp_region, exp_region,
00596 pgmag_win->clip);
00597 }
00598 }
00599 }
00600
00601 static void
00602 gmag_events_destroy_notify_handler (XEvent *ev)
00603 {
00604 GList *elem;
00605 GmagWinPtr pgmag_win;
00606
00607 #ifdef COMPOSITE_DEBUG
00608 printf ("Received DestroyNotify event: 0x%x\n",
00609 (guint) ev->xdestroywindow.window);
00610 #endif
00611 if (ev->xdestroywindow.window == mag_window) {
00612 #ifdef HAVE_OVERLAY
00613 #ifdef COMPOSITE_DEBUG
00614 printf ("Overlay window = 0x%x\n",
00615 (guint) gmag_events_overlay_window);
00616 #endif
00617 #endif
00618 return;
00619 }
00620 elem = g_queue_find_custom (mag_windows_list,
00621 (gconstpointer) ev->xdestroywindow.window,
00622 (GCompareFunc) gmag_events_g_compare_func);
00623 if (elem) {
00624 pgmag_win = (GmagWinPtr) elem->data;
00625 if (pgmag_win->attr.map_state == IsViewable)
00626 XFixesUnionRegion (dpy_conn,
00627 exp_region, exp_region,
00628 pgmag_win->clip);
00629 gmag_events_remove_window (ev->xdestroywindow.window);
00630 }
00631 }
00632
00633 static void
00634 gmag_events_map_notify_handler (XEvent *ev)
00635 {
00636 GList *elem;
00637 GmagWinPtr pgmag_win;
00638
00639 #ifdef COMPOSITE_DEBUG
00640 printf ("Received MapNotify event: 0x%x\n",
00641 (guint) ev->xmap.window);
00642 #endif
00643 if (ev->xmap.window == mag_window) {
00644 #ifdef HAVE_OVERLAY
00645 #ifdef COMPOSITE_DEBUG
00646 printf ("Overlay window = 0x%x\n",
00647 (guint) gmag_events_overlay_window);
00648 #endif
00649 #endif
00650 return;
00651 }
00652 elem = g_queue_find_custom (mag_windows_list,
00653 (gconstpointer) ev->xmap.window,
00654 (GCompareFunc) gmag_events_g_compare_func);
00655 if (elem) {
00656 pgmag_win = (GmagWinPtr) elem->data;
00657 pgmag_win->attr.map_state = IsViewable;
00658 gmag_events_calculate_window_clip (pgmag_win);
00659 XFixesUnionRegion (dpy_conn, exp_region,
00660 exp_region, pgmag_win->clip);
00661 }
00662 }
00663
00664 static void
00665 gmag_events_unmap_notify_handler (XEvent *ev)
00666 {
00667 GList *elem;
00668 GmagWinPtr pgmag_win;
00669
00670 #ifdef COMPOSITE_DEBUG
00671 printf ("Received UnmapNotify event: 0x%x\n",
00672 (guint) ev->xunmap.window);
00673 #endif
00674 if (ev->xunmap.window == mag_window) {
00675 #ifdef HAVE_OVERLAY
00676 #ifdef COMPOSITE_DEBUG
00677 printf ("Overlay window = 0x%x\n",
00678 (guint) gmag_events_overlay_window);
00679 #endif
00680 #endif
00681 return;
00682 }
00683 elem = g_queue_find_custom (mag_windows_list,
00684 (gconstpointer) ev->xunmap.window,
00685 (GCompareFunc) gmag_events_g_compare_func);
00686 if (elem) {
00687 pgmag_win = (GmagWinPtr) elem->data;
00688 pgmag_win->attr.map_state = IsUnmapped;
00689 XFixesUnionRegion (dpy_conn, exp_region,
00690 exp_region, pgmag_win->clip);
00691 }
00692 }
00693
00694 static void
00695 gmag_events_reparent_notify_handler (XEvent *ev)
00696 {
00697 GList *elem;
00698 GmagWinPtr pgmag_win;
00699
00700 #ifdef COMPOSITE_DEBUG
00701 printf ("Received ReparentNotify event: 0x%x (Window), 0x%x (Parent)\n", (guint) ev->xreparent.window, (guint) ev->xreparent.parent);
00702 #endif
00703 if (ev->xreparent.window == mag_window) {
00704 #ifdef HAVE_OVERLAY
00705 #ifdef COMPOSITE_DEBUG
00706 printf ("Overlay window = 0x%x\n",
00707 (guint) gmag_events_overlay_window);
00708 #endif
00709 #endif
00710 return;
00711 }
00712 if (ev->xreparent.parent != root_window) {
00713 gmag_events_remove_window (ev->xreparent.window);
00714 } else {
00715 gmag_events_add_window (ev->xreparent.window);
00716 elem = g_queue_find_custom (
00717 mag_windows_list,
00718 (gconstpointer) ev->xreparent.window,
00719 (GCompareFunc) gmag_events_g_compare_func);
00720 if (elem) {
00721 pgmag_win = (GmagWinPtr) elem->data;
00722 if (pgmag_win->attr.map_state == IsViewable) {
00723 gmag_events_calculate_window_clip (pgmag_win);
00724 XFixesUnionRegion (
00725 dpy_conn,
00726 exp_region, exp_region,
00727 pgmag_win->clip);
00728 }
00729 }
00730 }
00731 }
00732
00733 #endif
00734
00735 static void
00736 gmag_events_damage_notify_handler (XEvent *ev)
00737 {
00738 XDamageNotifyEvent *dev = (XDamageNotifyEvent *) ev;
00739 #ifdef DAMAGE_DEBUG
00740 g_message ("Damage area %3d, %3d x %3d, %3d",
00741 (int) dev->area.x, (int) dev->area.x + dev->area.width,
00742 (int) dev->area.y, (int) dev->area.y + dev->area.height);
00743 g_message ("Damage geometry %3d, %3d x %3d, %3d",
00744 (int) dev->geometry.x,
00745 (int) dev->geometry.x + dev->geometry.width,
00746 (int) dev->geometry.y,
00747 (int) dev->geometry.y + dev->geometry.height);
00748 #endif
00749
00750 #ifdef HAVE_COMPOSITE
00751 if (use_composite) {
00752 if (dev->damage == off_screen_damage) {
00753 #ifdef DAMAGE_DEBUG
00754 g_message ("off_screen_damage damaged");
00755 #endif
00756 XDamageSubtract (dpy_conn, dev->damage, None,
00757 gmag_events_tmp_region);
00758 XFixesUnionRegion (dpy_conn,
00759 off_screen_region,
00760 off_screen_region,
00761 gmag_events_tmp_region);
00762 } else {
00763 #ifdef DAMAGE_DEBUG
00764 g_message ("Window with damage: 0x%x", dev->drawable);
00765 #endif
00766 XDamageSubtract (dpy_conn, dev->damage, None,
00767 gmag_events_tmp_region);
00768 gmag_events_add_win_damaged_region (
00769 dev->drawable, gmag_events_tmp_region);
00770 }
00771 }
00772 #endif
00773 }
00774
00775 static void
00776 gmag_events_cursor_convert_to_rgba (Magnifier *magnifier,
00777 XFixesCursorImage *cursor_image)
00778 {
00779 int i, count = cursor_image->width * cursor_image->height;
00780 for (i = 0; i < count; ++i) {
00781 guint32 pixval = GUINT_TO_LE (cursor_image->pixels[i]);
00782 cursor_image->pixels[i] = pixval;
00783 }
00784 }
00785
00786 static void
00787 gmag_events_free_cursor_pixels (guchar *pixels, gpointer data)
00788 {
00789
00790 }
00791
00792 GdkPixbuf *
00793 gmag_events_get_source_pixbuf (Magnifier *magnifier)
00794 {
00795 XFixesCursorImage *cursor_image = XFixesGetCursorImage (
00796 dpy_conn);
00797 GdkPixbuf *cursor_pixbuf = NULL;
00798 gchar s[6];
00799 if (cursor_image)
00800 {
00801 gmag_events_cursor_convert_to_rgba (magnifier, cursor_image);
00802 cursor_pixbuf = gdk_pixbuf_new_from_data (
00803 (guchar *) cursor_image->pixels, GDK_COLORSPACE_RGB,
00804 TRUE, 8, cursor_image->width, cursor_image->height,
00805 cursor_image->width * 4,
00806 gmag_events_free_cursor_pixels, cursor_image);
00807 gdk_pixbuf_set_option (cursor_pixbuf, "x_hot",
00808 g_ascii_dtostr (
00809 s, 6,
00810 (gdouble) cursor_image->xhot));
00811 gdk_pixbuf_set_option (cursor_pixbuf, "y_hot",
00812 g_ascii_dtostr (
00813 s, 6,
00814 (gdouble) cursor_image->yhot));
00815 }
00816 return cursor_pixbuf;
00817 }
00818
00819 gboolean
00820 gmag_events_source_has_damage_extension (Magnifier *magnifier)
00821 {
00822 gint event_base, error_base;
00823 Display *dpy;
00824 g_assert (magnifier);
00825 dpy = GDK_DISPLAY_XDISPLAY (magnifier->source_display);
00826 if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
00827 return FALSE;
00828 if (XDamageQueryExtension (dpy, &event_base, &error_base))
00829 return TRUE;
00830 return FALSE;
00831 }
00832
00833 static gboolean
00834 gmag_events_handler (GIOChannel *source, GIOCondition condition, gpointer data)
00835 {
00836 XEvent ev;
00837 XFixesCursorNotifyEvent *cev = NULL;
00838 gboolean cursor_changed = FALSE;
00839 Magnifier *magnifier = (Magnifier *) data;
00840 XRectangle *rectlist;
00841 #ifdef HAVE_COMPOSITE
00842 gboolean calc_clip = FALSE;
00843 #endif
00844
00845 #ifdef HAVE_OVERLAY
00846 if (magnifier->priv->overlay)
00847 mag_window = GDK_WINDOW_XID (magnifier->priv->overlay);
00848 #else
00849 if (magnifier->priv->w && magnifier->priv->w->window)
00850 mag_window = GDK_WINDOW_XID (magnifier->priv->w->window);
00851 #endif
00852
00853 do
00854 {
00855 XNextEvent(dpy_conn, &ev);
00856
00857 #ifdef HAVE_COMPOSITE
00858 if (use_composite) {
00859 switch (ev.type) {
00860 case CirculateNotify:
00861 gmag_events_circulate_notify_handler (&ev);
00862 calc_clip = TRUE;
00863 break;
00864 case ConfigureNotify:
00865 gmag_events_configure_notify_handler (&ev);
00866 calc_clip = TRUE;
00867 break;
00868 case CreateNotify:
00869 gmag_events_create_notify_handler (&ev);
00870 calc_clip = TRUE;
00871 break;
00872 case DestroyNotify:
00873 gmag_events_destroy_notify_handler (&ev);
00874 calc_clip = TRUE;
00875 break;
00876 case MapNotify:
00877 gmag_events_map_notify_handler (&ev);
00878 calc_clip = TRUE;
00879 break;
00880 case UnmapNotify:
00881 gmag_events_unmap_notify_handler (&ev);
00882 calc_clip = TRUE;
00883 break;
00884 case ReparentNotify:
00885 gmag_events_reparent_notify_handler (&ev);
00886 calc_clip = TRUE;
00887 break;
00888 }
00889 }
00890 #endif
00891
00892 if (use_damage) {
00893 if (ev.type == damage_event_base + XDamageNotify) {
00894 gmag_events_damage_notify_handler (&ev);
00895 }
00896 }
00897
00898 if (ev.type == fixes_event_base + XFixesCursorNotify) {
00899 cursor_changed = TRUE;
00900 cev = (XFixesCursorNotifyEvent *) &ev;
00901 }
00902
00903 } while (XPending (dpy_conn));
00904
00905 #ifndef HAVE_OVERLAY
00906 if (use_composite && mag_window) {
00907 XRaiseWindow (dpy_conn, mag_window);
00908 }
00909 #endif
00910
00911 if (!use_composite) {
00912 XDamageSubtract (dpy_conn, root_window_damage, None,
00913 gmag_events_tmp_region);
00914 }
00915
00916 if (use_damage) {
00917 if (magnifier) {
00918 int i, howmany;
00919
00920
00921 #ifdef HAVE_COMPOSITE
00922 if (use_composite) {
00923 rectlist = XFixesFetchRegion (
00924 dpy_conn,
00925 off_screen_region,
00926 &howmany);
00927 } else {
00928 #endif
00929 rectlist = XFixesFetchRegion (
00930 dpy_conn, gmag_events_tmp_region,
00931 &howmany);
00932 #ifdef HAVE_COMPOSITE
00933 }
00934 #endif
00935 if (rectlist == NULL)
00936 return TRUE;
00937 for (i=0; i < howmany; ++i) {
00938 magnifier_notify_damage (magnifier,
00939 &rectlist[i]);
00940 }
00941 XFree (rectlist);
00942 }
00943 }
00944
00945 #ifdef HAVE_COMPOSITE
00946 if (use_composite) {
00947 if (calc_clip) {
00948 gmag_events_calculate_windows_clip ();
00949 gmag_events_paint_windows (exp_region);
00950 }
00951 gmag_events_paint_damaged_windows ();
00952 }
00953 #endif
00954
00955 if (cursor_changed) {
00956 if (magnifier->priv->use_source_cursor) {
00957 GdkPixbuf *cursor_pixbuf =
00958 gmag_events_get_source_pixbuf (magnifier);
00959 magnifier_set_cursor_from_pixbuf (magnifier,
00960 cursor_pixbuf);
00961 if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
00962 } else {
00963 magnifier_set_cursor_pixmap_by_name (magnifier, cev ? gdk_x11_get_xatom_name (cev->cursor_name) : "default", TRUE);
00964 }
00965
00966 magnifier_transform_cursor (magnifier);
00967 #ifdef CURSOR_DEBUG
00968 if (cev)
00969 g_message ("cursor changed: subtype=%d, " \
00970 "cursor_serial=%lu, name=[%x] %s\n",
00971 (int) cev->subtype, cev->cursor_serial,
00972 (int) cev->cursor_name,
00973 gdk_x11_get_xatom_name (cev->cursor_name));
00974 #endif
00975 cursor_changed = FALSE;
00976 }
00977
00978 #ifdef HAVE_COMPOSITE
00979 if (use_composite) {
00980 XFixesSetRegion (dpy_conn, tmp_region, 0, 0);
00981 XFixesSetRegion (dpy_conn, new_region, 0, 0);
00982 XFixesSetRegion (dpy_conn, old_region, 0, 0);
00983 XFixesSetRegion (dpy_conn, exp_region, 0, 0);
00984 XFixesSetRegion (dpy_conn, off_screen_region, 0, 0);
00985 }
00986 #endif
00987
00988 XFlush (dpy_conn);
00989 return TRUE;
00990 }
00991
00992 static gboolean
00993 gmag_events_use_damage ()
00994 {
00995 gint major, event, error;
00996 if (XQueryExtension (dpy_conn, "DAMAGE", &major, &event, &error) &&
00997 !g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
00998 return TRUE;
00999 return FALSE;
01000 }
01001
01002 static gboolean
01003 gmag_events_use_composite ()
01004 {
01005 if (!gmag_events_use_damage ()) {
01006 return FALSE;
01007 }
01008 #ifdef HAVE_COMPOSITE
01009 gint major, event, error;
01010 if (XQueryExtension (dpy_conn, "Composite", &major, &event, &error) &&
01011 !g_getenv ("MAGNIFIER_IGNORE_COMPOSITE"))
01012 return TRUE;
01013 return FALSE;
01014 #else
01015 return FALSE;
01016 #endif
01017 }
01018
01019 void
01020 gmag_events_client_init (Magnifier *magnifier)
01021 {
01022 GIOChannel *ioc;
01023 gint fd;
01024 gint event_base, error_base;
01025 #ifdef HAVE_COMPOSITE
01026 XRenderPictureAttributes pic_attr;
01027 XRenderPictFormat *format;
01028 GdkDisplay *gdk_display_connection;
01029 GdkScreen *gdkscr;
01030 gint scr = 0, root_w, root_h;
01031 #endif
01032
01033 if (dpy_conn) {
01034
01035 if (dpy_gsource)
01036 g_source_remove (dpy_gsource);
01037 XCloseDisplay (dpy_conn);
01038 }
01039
01040 if (magnifier) {
01041
01042
01043 dpy_conn = XOpenDisplay (magnifier->source_display_name);
01044 root_window = GDK_WINDOW_XWINDOW (magnifier->priv->root);
01045 } else {
01046 dpy_conn = XOpenDisplay (NULL);
01047 root_window = RootWindow (dpy_conn, DefaultScreen (dpy_conn));
01048 g_message ("warning - using DefaultScreen for X connection.");
01049 }
01050
01051 #ifdef EVENTS_DEBUG
01052 XSynchronize (dpy_conn, True);
01053 #endif
01054
01055 fd = ConnectionNumber (dpy_conn);
01056 ioc = g_io_channel_unix_new (fd);
01057 dpy_gsource = g_io_add_watch (ioc,
01058 G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR,
01059 gmag_events_handler, magnifier);
01060 g_io_channel_unref (ioc);
01061
01062 use_damage = gmag_events_use_damage ();
01063 use_composite = gmag_events_use_composite ();
01064
01065 if (!XFixesQueryExtension (dpy_conn, &fixes_event_base,
01066 &fixes_error_base)) {
01067 g_warning ("XFixes extension not currently active.\n");
01068 } else {
01069 XFixesSelectCursorInput (dpy_conn, root_window,
01070 XFixesDisplayCursorNotifyMask);
01071 g_message ("added event source to xfixes cursor-notify " \
01072 "connection");
01073 }
01074
01075 if (!XDamageQueryExtension (dpy_conn, &damage_event_base,
01076 &damage_error_base)) {
01077 g_warning ("Damage extension not currently active.\n");
01078 } else if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE")) {
01079 g_warning ("Damage extension being ignored at user request.");
01080 } else {
01081 gmag_events_tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01082 if (!use_composite) {
01083 root_window_damage = XDamageCreate (
01084 dpy_conn, root_window,
01085 XDamageReportDeltaRectangles);
01086
01087
01088
01089
01090
01091 XDamageSubtract (dpy_conn, root_window_damage, None,
01092 None);
01093 }
01094 g_message ("added event source to damage connection");
01095 }
01096
01097 #ifdef HAVE_COMPOSITE
01098 if (!XCompositeQueryExtension (dpy_conn, &event_base, &error_base)) {
01099 g_warning ("Composite extension not currently active.\n");
01100 } else if (g_getenv ("MAGNIFIER_IGNORE_COMPOSITE")) {
01101 g_warning ("Composite extension being ignored at user " \
01102 "request.");
01103 } else if (!use_damage) {
01104 g_setenv ("MAGNIFIER_IGNORE_COMPOSITE", "1", TRUE);
01105 g_warning ("Composite extension being ignored due Damage " \
01106 "is not actived.");
01107 } else {
01108 #ifndef HAVE_OVERLAY
01109 g_warning ("update composite to version 0.3 or higher to " \
01110 "have overlay window support.\n");
01111 #endif
01112
01113 gdk_drawable_get_size (magnifier->priv->root, &root_w,
01114 &root_h);
01115 magnifier->priv->source_drawable = gdk_pixmap_new (
01116 magnifier->priv->root, root_w, root_h, -1);
01117
01118
01119
01120 gdk_flush ();
01121
01122 gdk_display_connection = gdk_drawable_get_display (
01123 magnifier->priv->root);
01124 gdkscr = gdk_display_get_default_screen (
01125 gdk_display_connection);
01126
01127 scr = GDK_SCREEN_XNUMBER (gdkscr);
01128
01129 XCompositeRedirectSubwindows (dpy_conn, root_window,
01130 CompositeRedirectAutomatic);
01131 off_screen_region = XFixesCreateRegion (
01132 dpy_conn, 0, 0);
01133 tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01134 new_region = XFixesCreateRegion (dpy_conn, 0, 0);
01135 old_region = XFixesCreateRegion (dpy_conn, 0, 0);
01136 exp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01137 off_screen_damage = XDamageCreate (
01138 dpy_conn,
01139 GDK_DRAWABLE_XID (
01140 magnifier->priv->source_drawable),
01141 XDamageReportDeltaRectangles);
01142
01143 format = XRenderFindVisualFormat (
01144 dpy_conn,
01145 DefaultVisual (dpy_conn, scr));
01146 pic_attr.subwindow_mode = IncludeInferiors;
01147 off_screen_picture = XRenderCreatePicture (
01148 dpy_conn,
01149 GDK_DRAWABLE_XID (magnifier->priv->source_drawable),
01150 format, CPSubwindowMode, &pic_attr);
01151
01152 gmag_events_create_windows_list (gdk_display_connection,
01153 gdkscr);
01154 gmag_events_calculate_windows_clip ();
01155 g_message ("added event source to composite connection");
01156 }
01157 #else
01158 g_warning ("this copy of gnome-mag was built without composite " \
01159 "extension support.\n");
01160 #endif
01161
01162 XFlush (dpy_conn);
01163 }