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 = FALSE;
00325 new->damaged_region = None;
00326 } else {
00327 format = XRenderFindVisualFormat (
00328 dpy_conn, new->attr.visual);
00329 pic_attr.subwindow_mode = IncludeInferiors;
00330 new->pic = XRenderCreatePicture (
00331 dpy_conn, xwin, format,
00332 CPSubwindowMode, &pic_attr);
00333 new->damage = XDamageCreate (dpy_conn, xwin,
00334 XDamageReportDeltaRectangles);
00335 new->damaged = TRUE;
00336 new->damaged_region = XFixesCreateRegion (dpy_conn, 0, 0);
00337 new->clip = XFixesCreateRegion (dpy_conn, 0, 0);
00338 new->win_region = XFixesCreateRegion (dpy_conn, 0, 0);
00339 }
00340
00341 g_queue_push_tail (mag_windows_list, new);
00342 }
00343
00344
00345
00346
00347
00348 static void
00349 gmag_events_create_windows_list ()
00350 {
00351 Window root_return, parent_return, *children;
00352 guint nchildren;
00353 gint i;
00354
00355 if (!mag_windows_list)
00356 mag_windows_list = g_queue_new ();
00357
00358 XGrabServer (dpy_conn);
00359 XSelectInput (dpy_conn, root_window,
00360 SubstructureNotifyMask);
00361 XQueryTree (dpy_conn, root_window,
00362 &root_return, &parent_return, &children, &nchildren);
00363 for (i = 0; i < nchildren; i++)
00364 gmag_events_add_window (children[i]);
00365 XFree (children);
00366 XUngrabServer (dpy_conn);
00367 }
00368
00369
00370
00371
00372
00373 static void
00374 gmag_events_remove_window (Window xwin)
00375 {
00376 GList *elem = NULL;
00377 GmagWinPtr pgmag_win;
00378
00379 elem = g_queue_find_custom (mag_windows_list,
00380 (gconstpointer) xwin,
00381 (GCompareFunc) gmag_events_g_compare_func);
00382 if (elem) {
00383 pgmag_win = (GmagWinPtr) elem->data;
00384 g_queue_remove (mag_windows_list, pgmag_win);
00385 XFixesDestroyRegion (dpy_conn,
00386 pgmag_win->clip);
00387 XFixesDestroyRegion (dpy_conn,
00388 pgmag_win->win_region);
00389 free (pgmag_win);
00390 }
00391 }
00392
00393
00394
00395
00396
00397 static void
00398 gmag_events_add_win_damaged_region (Window xwin, XserverRegion region)
00399 {
00400 GList *elem;
00401 GmagWinPtr pgmag_win;
00402
00403 elem = g_queue_find_custom (mag_windows_list,
00404 (gconstpointer) xwin,
00405 (GCompareFunc) gmag_events_g_compare_func);
00406 if (elem) {
00407 pgmag_win = (GmagWinPtr) elem->data;
00408 XFixesTranslateRegion (dpy_conn, region,
00409 pgmag_win->attr.x, pgmag_win->attr.y);
00410 XFixesUnionRegion (dpy_conn,
00411 pgmag_win->damaged_region,
00412 pgmag_win->damaged_region, region);
00413 pgmag_win->damaged = TRUE;
00414 }
00415 }
00416
00417
00418
00419
00420 static void
00421 gmag_events_paint_damaged_windows ()
00422 {
00423 GList *elem;
00424 GmagWinPtr pgmag_win;
00425
00426 elem = g_queue_peek_head_link (mag_windows_list);
00427 while (elem) {
00428 pgmag_win = (GmagWinPtr) elem->data;
00429 if (pgmag_win->damaged) {
00430 gmag_events_paint_window (pgmag_win,
00431 pgmag_win->damaged_region);
00432 XFixesSetRegion (dpy_conn,
00433 pgmag_win->damaged_region, 0, 0);
00434 pgmag_win->damaged = FALSE;
00435 }
00436
00437 elem = g_list_next (elem);
00438 }
00439 }
00440
00441 static void
00442 gmag_events_circulate_notify_handler (XEvent *ev)
00443 {
00444 GList *elem;
00445 GmagWinPtr pgmag_win;
00446
00447 #ifdef COMPOSITE_DEBUG
00448 printf ("Received CirculateNotify event: 0x%x\n",
00449 (guint) ev->xcirculate.window);
00450 #endif
00451 if (ev->xcirculate.window == mag_window) {
00452 #ifdef HAVE_OVERLAY
00453 #ifdef COMPOSITE_DEBUG
00454 printf ("Overlay window = 0x%x\n",
00455 (guint) gmag_events_overlay_window);
00456 #endif
00457 #endif
00458 return;
00459 }
00460 elem = g_queue_find_custom (mag_windows_list,
00461 (gconstpointer) ev->xcirculate.window,
00462 (GCompareFunc) gmag_events_g_compare_func);
00463 if (elem) {
00464 pgmag_win = (GmagWinPtr) elem->data;
00465 g_queue_remove (mag_windows_list, pgmag_win);
00466 if (ev->xcirculate.place == PlaceOnTop) {
00467 g_queue_push_tail (mag_windows_list,
00468 pgmag_win);
00469 if (pgmag_win->attr.map_state == IsViewable) {
00470 XFixesSubtractRegion (
00471 dpy_conn,
00472 tmp_region, pgmag_win->win_region,
00473 pgmag_win->clip);
00474 XFixesUnionRegion (
00475 dpy_conn,
00476 exp_region, exp_region, tmp_region);
00477 }
00478 } else {
00479 g_queue_push_head (mag_windows_list,
00480 pgmag_win);
00481 if (pgmag_win->attr.map_state == IsViewable)
00482 XFixesUnionRegion (
00483 dpy_conn,
00484 exp_region, exp_region,
00485 pgmag_win->clip);
00486 }
00487 }
00488 }
00489
00490 static void
00491 gmag_events_configure_notify_handler (XEvent *ev)
00492 {
00493 GList *elem;
00494 GmagWinPtr pgmag_win;
00495
00496 #ifdef COMPOSITE_DEBUG
00497 printf ("Received ConfigureNotify event: 0x%x\n",
00498 (guint) ev->xconfigure.window);
00499 #endif
00500 if (ev->xconfigure.window == mag_window) {
00501 #ifdef HAVE_OVERLAY
00502 #ifdef COMPOSITE_DEBUG
00503 printf ("Overlay window = 0x%x\n",
00504 (guint) gmag_events_overlay_window);
00505 #endif
00506 #endif
00507 return;
00508 }
00509 elem = g_queue_find_custom (mag_windows_list,
00510 (gconstpointer) ev->xconfigure.window,
00511 (GCompareFunc) gmag_events_g_compare_func);
00512 if (elem) {
00513 pgmag_win = (GmagWinPtr) elem->data;
00514 if ((pgmag_win->attr.x != ev->xconfigure.x) ||
00515 (pgmag_win->attr.y != ev->xconfigure.y) ||
00516 (pgmag_win->attr.width != ev->xconfigure.width) ||
00517 (pgmag_win->attr.height != ev->xconfigure.height) ||
00518 (pgmag_win->attr.border_width !=
00519 ev->xconfigure.border_width)) {
00520
00521
00522
00523
00524
00525
00526 pgmag_win->attr.x = ev->xconfigure.x;
00527 pgmag_win->attr.y = ev->xconfigure.y;
00528 pgmag_win->attr.width = ev->xconfigure.width;
00529 pgmag_win->attr.height = ev->xconfigure.height;
00530 pgmag_win->attr.border_width =
00531 ev->xconfigure.border_width;
00532
00533 if (pgmag_win->attr.map_state == IsViewable) {
00534 XFixesCopyRegion (
00535 dpy_conn,
00536 old_region, pgmag_win->clip);
00537 gmag_events_calculate_window_clip (pgmag_win);
00538 XFixesCopyRegion (
00539 dpy_conn,
00540 new_region, pgmag_win->clip);
00541 XFixesUnionRegion (
00542 dpy_conn,
00543 exp_region, exp_region, old_region);
00544 XFixesUnionRegion (
00545 dpy_conn,
00546 exp_region, exp_region, new_region);
00547 }
00548 }
00549 if (!ev->xconfigure.above) {
00550 g_queue_remove (mag_windows_list, pgmag_win);
00551 g_queue_push_head (mag_windows_list,
00552 pgmag_win);
00553 if (pgmag_win->attr.map_state == IsViewable) {
00554 XFixesUnionRegion (
00555 dpy_conn,
00556 exp_region, exp_region,
00557 pgmag_win->win_region);
00558 }
00559 } else {
00560 elem = g_queue_find_custom (
00561 mag_windows_list,
00562 (gconstpointer) ev->xconfigure.above,
00563 (GCompareFunc) gmag_events_g_compare_func);
00564 if (elem) {
00565 g_queue_remove (mag_windows_list,
00566 pgmag_win);
00567 g_queue_insert_after (mag_windows_list,
00568 elem, pgmag_win);
00569 if (pgmag_win->attr.map_state == IsViewable) {
00570 XFixesUnionRegion (
00571 dpy_conn,
00572 exp_region, exp_region,
00573 pgmag_win->win_region);
00574 }
00575 }
00576 }
00577 }
00578 }
00579
00580 static void
00581 gmag_events_create_notify_handler (XEvent *ev)
00582 {
00583 GList *elem;
00584 GmagWinPtr pgmag_win;
00585
00586 #ifdef COMPOSITE_DEBUG
00587 printf ("Received CreateNotify event: 0x%x\n",
00588 (guint) ev->xcreatewindow.window);
00589 #endif
00590 if (ev->xcreatewindow.window == mag_window) {
00591 #ifdef HAVE_OVERLAY
00592 #ifdef COMPOSITE_DEBUG
00593 printf ("Overlay window = 0x%x\n",
00594 (guint) gmag_events_overlay_window);
00595 #endif
00596 #endif
00597 return;
00598 }
00599 gmag_events_add_window (ev->xcreatewindow.window);
00600 elem = g_queue_find_custom (mag_windows_list,
00601 (gconstpointer) ev->xcreatewindow.window,
00602 (GCompareFunc) gmag_events_g_compare_func);
00603 if (elem) {
00604 pgmag_win = (GmagWinPtr) elem->data;
00605 if (pgmag_win->attr.map_state == IsViewable) {
00606 gmag_events_calculate_window_clip (pgmag_win);
00607 XFixesUnionRegion (dpy_conn,
00608 exp_region, exp_region,
00609 pgmag_win->clip);
00610 }
00611 }
00612 }
00613
00614 static void
00615 gmag_events_destroy_notify_handler (XEvent *ev)
00616 {
00617 GList *elem;
00618 GmagWinPtr pgmag_win;
00619
00620 #ifdef COMPOSITE_DEBUG
00621 printf ("Received DestroyNotify event: 0x%x\n",
00622 (guint) ev->xdestroywindow.window);
00623 #endif
00624 if (ev->xdestroywindow.window == mag_window) {
00625 #ifdef HAVE_OVERLAY
00626 #ifdef COMPOSITE_DEBUG
00627 printf ("Overlay window = 0x%x\n",
00628 (guint) gmag_events_overlay_window);
00629 #endif
00630 #endif
00631 return;
00632 }
00633 elem = g_queue_find_custom (mag_windows_list,
00634 (gconstpointer) ev->xdestroywindow.window,
00635 (GCompareFunc) gmag_events_g_compare_func);
00636 if (elem) {
00637 pgmag_win = (GmagWinPtr) elem->data;
00638 if (pgmag_win->attr.map_state == IsViewable)
00639 XFixesUnionRegion (dpy_conn,
00640 exp_region, exp_region,
00641 pgmag_win->clip);
00642 gmag_events_remove_window (ev->xdestroywindow.window);
00643 }
00644 }
00645
00646 static void
00647 gmag_events_map_notify_handler (XEvent *ev)
00648 {
00649 GList *elem;
00650 GmagWinPtr pgmag_win;
00651
00652 #ifdef COMPOSITE_DEBUG
00653 printf ("Received MapNotify event: 0x%x\n",
00654 (guint) ev->xmap.window);
00655 #endif
00656 if (ev->xmap.window == mag_window) {
00657 #ifdef HAVE_OVERLAY
00658 #ifdef COMPOSITE_DEBUG
00659 printf ("Overlay window = 0x%x\n",
00660 (guint) gmag_events_overlay_window);
00661 #endif
00662 #endif
00663 return;
00664 }
00665 elem = g_queue_find_custom (mag_windows_list,
00666 (gconstpointer) ev->xmap.window,
00667 (GCompareFunc) gmag_events_g_compare_func);
00668 if (elem) {
00669 pgmag_win = (GmagWinPtr) elem->data;
00670 pgmag_win->attr.map_state = IsViewable;
00671 gmag_events_calculate_window_clip (pgmag_win);
00672 XFixesUnionRegion (dpy_conn, exp_region,
00673 exp_region, pgmag_win->clip);
00674 }
00675 }
00676
00677 static void
00678 gmag_events_unmap_notify_handler (XEvent *ev)
00679 {
00680 GList *elem;
00681 GmagWinPtr pgmag_win;
00682
00683 #ifdef COMPOSITE_DEBUG
00684 printf ("Received UnmapNotify event: 0x%x\n",
00685 (guint) ev->xunmap.window);
00686 #endif
00687 if (ev->xunmap.window == mag_window) {
00688 #ifdef HAVE_OVERLAY
00689 #ifdef COMPOSITE_DEBUG
00690 printf ("Overlay window = 0x%x\n",
00691 (guint) gmag_events_overlay_window);
00692 #endif
00693 #endif
00694 return;
00695 }
00696 elem = g_queue_find_custom (mag_windows_list,
00697 (gconstpointer) ev->xunmap.window,
00698 (GCompareFunc) gmag_events_g_compare_func);
00699 if (elem) {
00700 pgmag_win = (GmagWinPtr) elem->data;
00701 pgmag_win->attr.map_state = IsUnmapped;
00702 XFixesUnionRegion (dpy_conn, exp_region,
00703 exp_region, pgmag_win->clip);
00704 }
00705 }
00706
00707 static void
00708 gmag_events_reparent_notify_handler (XEvent *ev)
00709 {
00710 GList *elem;
00711 GmagWinPtr pgmag_win;
00712
00713 #ifdef COMPOSITE_DEBUG
00714 printf ("Received ReparentNotify event: 0x%x (Window), 0x%x (Parent)\n", (guint) ev->xreparent.window, (guint) ev->xreparent.parent);
00715 #endif
00716 if (ev->xreparent.window == mag_window) {
00717 #ifdef HAVE_OVERLAY
00718 #ifdef COMPOSITE_DEBUG
00719 printf ("Overlay window = 0x%x\n",
00720 (guint) gmag_events_overlay_window);
00721 #endif
00722 #endif
00723 return;
00724 }
00725 if (ev->xreparent.parent != root_window) {
00726 gmag_events_remove_window (ev->xreparent.window);
00727 } else {
00728 gmag_events_add_window (ev->xreparent.window);
00729 elem = g_queue_find_custom (
00730 mag_windows_list,
00731 (gconstpointer) ev->xreparent.window,
00732 (GCompareFunc) gmag_events_g_compare_func);
00733 if (elem) {
00734 pgmag_win = (GmagWinPtr) elem->data;
00735 if (pgmag_win->attr.map_state == IsViewable) {
00736 gmag_events_calculate_window_clip (pgmag_win);
00737 XFixesUnionRegion (
00738 dpy_conn,
00739 exp_region, exp_region,
00740 pgmag_win->clip);
00741 }
00742 }
00743 }
00744 }
00745
00746 #endif
00747
00748 #ifdef HAVE_DAMAGE
00749
00750 static void
00751 gmag_events_damage_notify_handler (XEvent *ev)
00752 {
00753 XDamageNotifyEvent *dev = (XDamageNotifyEvent *) ev;
00754 #ifdef DAMAGE_DEBUG
00755 g_message ("Damage area %3d, %3d x %3d, %3d",
00756 (int) dev->area.x, (int) dev->area.x + dev->area.width,
00757 (int) dev->area.y, (int) dev->area.y + dev->area.height);
00758 g_message ("Damage geometry %3d, %3d x %3d, %3d",
00759 (int) dev->geometry.x,
00760 (int) dev->geometry.x + dev->geometry.width,
00761 (int) dev->geometry.y,
00762 (int) dev->geometry.y + dev->geometry.height);
00763 #endif
00764
00765 #ifdef HAVE_COMPOSITE
00766 if (use_composite) {
00767 if (dev->damage == off_screen_damage) {
00768 #ifdef DAMAGE_DEBUG
00769 g_message ("off_screen_damage damaged");
00770 #endif
00771 XDamageSubtract (dpy_conn, dev->damage, None,
00772 gmag_events_tmp_region);
00773 XFixesUnionRegion (dpy_conn,
00774 off_screen_region,
00775 off_screen_region,
00776 gmag_events_tmp_region);
00777 } else {
00778 #ifdef DAMAGE_DEBUG
00779 g_message ("Window with damage: 0x%x", dev->drawable);
00780 #endif
00781 XDamageSubtract (dpy_conn, dev->damage, None,
00782 gmag_events_tmp_region);
00783 gmag_events_add_win_damaged_region (
00784 dev->drawable, gmag_events_tmp_region);
00785 }
00786 }
00787 #endif
00788 }
00789
00790 #endif
00791
00792 static void
00793 gmag_events_cursor_convert_to_rgba (Magnifier *magnifier,
00794 XFixesCursorImage *cursor_image)
00795 {
00796 int i, count = cursor_image->width * cursor_image->height;
00797 for (i = 0; i < count; ++i) {
00798 guint32 pixval = GUINT_TO_LE (cursor_image->pixels[i]);
00799 cursor_image->pixels[i] = pixval;
00800 }
00801 }
00802
00803 static void
00804 gmag_events_free_cursor_pixels (guchar *pixels, gpointer data)
00805 {
00806
00807 }
00808
00809 #endif
00810
00811 GdkPixbuf *
00812 gmag_events_get_source_pixbuf (Magnifier *magnifier)
00813 {
00814 #ifdef HAVE_XFIXES
00815 XFixesCursorImage *cursor_image = XFixesGetCursorImage (
00816 dpy_conn);
00817 GdkPixbuf *cursor_pixbuf = NULL;
00818 gchar s[6];
00819 if (cursor_image)
00820 {
00821 gmag_events_cursor_convert_to_rgba (magnifier, cursor_image);
00822 cursor_pixbuf = gdk_pixbuf_new_from_data (
00823 (guchar *) cursor_image->pixels, GDK_COLORSPACE_RGB,
00824 TRUE, 8, cursor_image->width, cursor_image->height,
00825 cursor_image->width * 4,
00826 gmag_events_free_cursor_pixels, cursor_image);
00827 gdk_pixbuf_set_option (cursor_pixbuf, "x_hot",
00828 g_ascii_dtostr (
00829 s, 6,
00830 (gdouble) cursor_image->xhot));
00831 gdk_pixbuf_set_option (cursor_pixbuf, "y_hot",
00832 g_ascii_dtostr (
00833 s, 6,
00834 (gdouble) cursor_image->yhot));
00835 }
00836 return cursor_pixbuf;
00837 #else
00838 return NULL;
00839 #endif
00840 }
00841
00842 gboolean
00843 gmag_events_source_has_damage_extension (Magnifier *magnifier)
00844 {
00845 #ifdef HAVE_DAMAGE
00846 gint event_base, error_base;
00847 Display *dpy;
00848 g_assert (magnifier);
00849 dpy = GDK_DISPLAY_XDISPLAY (magnifier->source_display);
00850 if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
00851 return FALSE;
00852 if (XDamageQueryExtension (dpy, &event_base, &error_base))
00853 return TRUE;
00854 #endif
00855 return FALSE;
00856 }
00857
00858 static gboolean
00859 gmag_events_handler (GIOChannel *source, GIOCondition condition, gpointer data)
00860 {
00861 #ifdef HAVE_XFIXES
00862 XEvent ev;
00863 XFixesCursorNotifyEvent *cev = NULL;
00864 gboolean cursor_changed = FALSE;
00865 Magnifier *magnifier = (Magnifier *) data;
00866 XRectangle *rectlist;
00867 #ifdef HAVE_COMPOSITE
00868 gboolean calc_clip = FALSE;
00869 #endif
00870
00871 #ifdef HAVE_OVERLAY
00872 if (magnifier->priv->overlay)
00873 mag_window = GDK_WINDOW_XID (magnifier->priv->overlay);
00874 #else
00875 if (magnifier->priv->w && magnifier->priv->w->window)
00876 mag_window = GDK_WINDOW_XID (magnifier->priv->w->window);
00877 #endif
00878
00879 do
00880 {
00881 XNextEvent(dpy_conn, &ev);
00882
00883 #ifdef HAVE_COMPOSITE
00884 if (use_composite) {
00885 switch (ev.type) {
00886 case CirculateNotify:
00887 gmag_events_circulate_notify_handler (&ev);
00888 calc_clip = TRUE;
00889 break;
00890 case ConfigureNotify:
00891 gmag_events_configure_notify_handler (&ev);
00892 calc_clip = TRUE;
00893 break;
00894 case CreateNotify:
00895 gmag_events_create_notify_handler (&ev);
00896 calc_clip = TRUE;
00897 break;
00898 case DestroyNotify:
00899 gmag_events_destroy_notify_handler (&ev);
00900 calc_clip = TRUE;
00901 break;
00902 case MapNotify:
00903 gmag_events_map_notify_handler (&ev);
00904 calc_clip = TRUE;
00905 break;
00906 case UnmapNotify:
00907 gmag_events_unmap_notify_handler (&ev);
00908 calc_clip = TRUE;
00909 break;
00910 case ReparentNotify:
00911 gmag_events_reparent_notify_handler (&ev);
00912 calc_clip = TRUE;
00913 break;
00914 }
00915 }
00916 #endif
00917
00918 #ifdef HAVE_DAMAGE
00919 if (use_damage) {
00920 if (ev.type == damage_event_base + XDamageNotify) {
00921 gmag_events_damage_notify_handler (&ev);
00922 }
00923 }
00924 #endif
00925
00926 #ifdef HAVE_XFIXES
00927 if (ev.type == fixes_event_base + XFixesCursorNotify) {
00928 cursor_changed = TRUE;
00929 cev = (XFixesCursorNotifyEvent *) &ev;
00930 }
00931 #endif
00932
00933 } while (XPending (dpy_conn));
00934
00935 #ifndef HAVE_OVERLAY
00936 if (use_composite && mag_window) {
00937 XRaiseWindow (dpy_conn, mag_window);
00938 }
00939 #endif
00940
00941 #ifdef HAVE_DAMAGE
00942 if (!use_composite) {
00943 XDamageSubtract (dpy_conn, root_window_damage, None,
00944 gmag_events_tmp_region);
00945 }
00946
00947 if (use_damage) {
00948 if (magnifier) {
00949 int i, howmany;
00950
00951
00952 #ifdef HAVE_COMPOSITE
00953 if (use_composite) {
00954 rectlist = XFixesFetchRegion (
00955 dpy_conn,
00956 off_screen_region,
00957 &howmany);
00958 } else {
00959 #endif
00960 rectlist = XFixesFetchRegion (
00961 dpy_conn, gmag_events_tmp_region,
00962 &howmany);
00963 #ifdef HAVE_COMPOSITE
00964 }
00965 #endif
00966 if (rectlist == NULL)
00967 return TRUE;
00968 for (i=0; i < howmany; ++i) {
00969 magnifier_notify_damage (magnifier,
00970 &rectlist[i]);
00971 }
00972 XFree (rectlist);
00973 }
00974 }
00975 #endif
00976
00977 #ifdef HAVE_COMPOSITE
00978 if (use_composite) {
00979 if (calc_clip) {
00980 gmag_events_calculate_windows_clip ();
00981 gmag_events_paint_windows (exp_region);
00982 }
00983 gmag_events_paint_damaged_windows ();
00984 }
00985 #endif
00986
00987 #ifdef HAVE_XFIXES
00988 if (cursor_changed) {
00989 if (magnifier->priv->use_source_cursor) {
00990 GdkPixbuf *cursor_pixbuf =
00991 gmag_events_get_source_pixbuf (magnifier);
00992 magnifier_set_cursor_from_pixbuf (magnifier,
00993 cursor_pixbuf);
00994 if (cursor_pixbuf) g_object_unref (cursor_pixbuf);
00995 } else {
00996 magnifier_set_cursor_pixmap_by_name (magnifier, cev ? gdk_x11_get_xatom_name (cev->cursor_name) : "default", TRUE);
00997 }
00998
00999 magnifier_transform_cursor (magnifier);
01000 #ifdef CURSOR_DEBUG
01001 if (cev)
01002 g_message ("cursor changed: subtype=%d, " \
01003 "cursor_serial=%lu, name=[%x] %s\n",
01004 (int) cev->subtype, cev->cursor_serial,
01005 (int) cev->cursor_name,
01006 gdk_x11_get_xatom_name (cev->cursor_name));
01007 #endif
01008 cursor_changed = FALSE;
01009 }
01010 #endif
01011
01012 #ifdef HAVE_COMPOSITE
01013 if (use_composite) {
01014 XFixesSetRegion (dpy_conn, tmp_region, 0, 0);
01015 XFixesSetRegion (dpy_conn, new_region, 0, 0);
01016 XFixesSetRegion (dpy_conn, old_region, 0, 0);
01017 XFixesSetRegion (dpy_conn, exp_region, 0, 0);
01018 XFixesSetRegion (dpy_conn, off_screen_region, 0, 0);
01019 }
01020 #endif
01021
01022 XFlush (dpy_conn);
01023 #else
01024 return FALSE;
01025 #endif
01026 return TRUE;
01027 }
01028
01029 static gboolean
01030 gmag_events_use_damage ()
01031 {
01032 #ifdef HAVE_DAMAGE
01033 gint major, event, error;
01034 if (XQueryExtension (dpy_conn, "DAMAGE", &major, &event, &error) &&
01035 !g_getenv ("MAGNIFIER_IGNORE_DAMAGE"))
01036 return TRUE;
01037 return FALSE;
01038 #else
01039 return FALSE;
01040 #endif
01041 }
01042
01043 static gboolean
01044 gmag_events_use_composite ()
01045 {
01046 if (!gmag_events_use_damage ()) {
01047 return FALSE;
01048 }
01049 #ifdef HAVE_COMPOSITE
01050 gint major, event, error;
01051 if (XQueryExtension (dpy_conn, "Composite", &major, &event, &error) &&
01052 !g_getenv ("MAGNIFIER_IGNORE_COMPOSITE"))
01053 return TRUE;
01054 return FALSE;
01055 #else
01056 return FALSE;
01057 #endif
01058 }
01059
01060 void
01061 gmag_events_client_init (Magnifier *magnifier)
01062 {
01063 GIOChannel *ioc;
01064 gint fd;
01065 gint event_base, error_base;
01066 #ifdef HAVE_COMPOSITE
01067 XRenderPictureAttributes pic_attr;
01068 XRenderPictFormat *format;
01069 GdkDisplay *gdk_display_connection;
01070 GdkScreen *gdkscr;
01071 gint scr = 0, root_w, root_h;
01072 #endif
01073
01074 if (dpy_conn) {
01075
01076 if (dpy_gsource)
01077 g_source_remove (dpy_gsource);
01078 XCloseDisplay (dpy_conn);
01079 }
01080
01081 if (magnifier) {
01082
01083
01084 dpy_conn = XOpenDisplay (magnifier->source_display_name);
01085 root_window = GDK_WINDOW_XWINDOW (magnifier->priv->root);
01086 } else {
01087 dpy_conn = XOpenDisplay (NULL);
01088 root_window = RootWindow (dpy_conn, DefaultScreen (dpy_conn));
01089 g_message ("warning - using DefaultScreen for X connection.");
01090 }
01091
01092 #ifdef EVENTS_DEBUG
01093 XSynchronize (dpy_conn, True);
01094 #endif
01095
01096 fd = ConnectionNumber (dpy_conn);
01097 ioc = g_io_channel_unix_new (fd);
01098 dpy_gsource = g_io_add_watch (ioc,
01099 G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR,
01100 gmag_events_handler, magnifier);
01101 g_io_channel_unref (ioc);
01102
01103 #ifdef HAVE_XFIXES
01104
01105 use_damage = gmag_events_use_damage ();
01106 use_composite = gmag_events_use_composite ();
01107
01108 if (!XFixesQueryExtension (dpy_conn, &fixes_event_base,
01109 &fixes_error_base)) {
01110 g_warning ("XFixes extension not currently active.\n");
01111 } else {
01112 XFixesSelectCursorInput (dpy_conn, root_window,
01113 XFixesDisplayCursorNotifyMask);
01114 g_message ("added event source to xfixes cursor-notify " \
01115 "connection");
01116 }
01117
01118 #ifdef HAVE_DAMAGE
01119 if (!XDamageQueryExtension (dpy_conn, &damage_event_base,
01120 &damage_error_base)) {
01121 g_warning ("Damage extension not currently active.\n");
01122 } else if (g_getenv ("MAGNIFIER_IGNORE_DAMAGE")) {
01123 g_warning ("Damage extension being ignored at user request.");
01124 } else {
01125 gmag_events_tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01126 if (!use_composite) {
01127 root_window_damage = XDamageCreate (
01128 dpy_conn, root_window,
01129 XDamageReportDeltaRectangles);
01130
01131
01132
01133
01134
01135 XDamageSubtract (dpy_conn, root_window_damage, None,
01136 None);
01137 }
01138 g_message ("added event source to damage connection");
01139 }
01140 #else
01141 g_warning ("this copy of gnome-mag was built without damage " \
01142 "extension support.\n");
01143 #endif
01144
01145 #ifdef HAVE_COMPOSITE
01146 if (!XCompositeQueryExtension (dpy_conn, &event_base, &error_base)) {
01147 g_warning ("Composite extension not currently active.\n");
01148 } else if (g_getenv ("MAGNIFIER_IGNORE_COMPOSITE")) {
01149 g_warning ("Composite extension being ignored at user " \
01150 "request.");
01151 } else if (!use_damage) {
01152 g_setenv ("MAGNIFIER_IGNORE_COMPOSITE", "1", TRUE);
01153 g_warning ("Composite extension being ignored due Damage " \
01154 "is not actived.");
01155 } else {
01156 #ifndef HAVE_OVERLAY
01157 g_warning ("update composite to version 0.3 or higher to " \
01158 "have overlay window support.\n");
01159 #endif
01160
01161 gdk_drawable_get_size (magnifier->priv->root, &root_w,
01162 &root_h);
01163 magnifier->priv->source_drawable = gdk_pixmap_new (
01164 magnifier->priv->root, root_w, root_h, -1);
01165
01166
01167
01168 gdk_flush ();
01169
01170 gdk_display_connection = gdk_drawable_get_display (
01171 magnifier->priv->root);
01172 gdkscr = gdk_display_get_default_screen (
01173 gdk_display_connection);
01174
01175 scr = GDK_SCREEN_XNUMBER (gdkscr);
01176
01177 XCompositeRedirectSubwindows (dpy_conn, root_window,
01178 CompositeRedirectAutomatic);
01179 off_screen_region = XFixesCreateRegion (
01180 dpy_conn, 0, 0);
01181 tmp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01182 new_region = XFixesCreateRegion (dpy_conn, 0, 0);
01183 old_region = XFixesCreateRegion (dpy_conn, 0, 0);
01184 exp_region = XFixesCreateRegion (dpy_conn, 0, 0);
01185 off_screen_damage = XDamageCreate (
01186 dpy_conn,
01187 GDK_DRAWABLE_XID (
01188 magnifier->priv->source_drawable),
01189 XDamageReportDeltaRectangles);
01190
01191 format = XRenderFindVisualFormat (
01192 dpy_conn,
01193 DefaultVisual (dpy_conn, scr));
01194 pic_attr.subwindow_mode = IncludeInferiors;
01195 off_screen_picture = XRenderCreatePicture (
01196 dpy_conn,
01197 GDK_DRAWABLE_XID (magnifier->priv->source_drawable),
01198 format, CPSubwindowMode, &pic_attr);
01199
01200 gmag_events_create_windows_list (gdk_display_connection,
01201 gdkscr);
01202 gmag_events_calculate_windows_clip ();
01203 g_message ("added event source to composite connection");
01204 }
01205 #else
01206 g_warning ("this copy of gnome-mag was built without composite " \
01207 "extension support.\n");
01208 #endif
01209
01210 #else
01211 g_warning ("this copy of gnome-mag was built without xfixes " \
01212 "extension support.\n");
01213 #endif
01214 XFlush (dpy_conn);
01215 }