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