int x11_init(GraceApp *gapp) { X11Stuff *xstuff = gapp->gui->xstuff; XGCValues gc_val; long mrsize; int max_path_limit; xstuff->screennumber = DefaultScreen(xstuff->disp); xstuff->root = RootWindow(xstuff->disp, xstuff->screennumber); xstuff->gc = DefaultGC(xstuff->disp, xstuff->screennumber); xstuff->depth = DisplayPlanes(xstuff->disp, xstuff->screennumber); /* init colormap */ xstuff->cmap = DefaultColormap(xstuff->disp, xstuff->screennumber); /* redefine colormap, if needed */ if (gapp->gui->install_cmap == CMAP_INSTALL_ALWAYS) { xstuff->cmap = XCopyColormapAndFree(xstuff->disp, xstuff->cmap); gapp->gui->private_cmap = TRUE; } /* set GCs */ if (gapp->gui->invert) { gc_val.function = GXinvert; } else { gc_val.function = GXxor; } gcxor = XCreateGC(xstuff->disp, xstuff->root, GCFunction, &gc_val); /* XExtendedMaxRequestSize() appeared in X11R6 */ #if XlibSpecificationRelease > 5 mrsize = XExtendedMaxRequestSize(xstuff->disp); #else mrsize = 0; #endif if (mrsize <= 0) { mrsize = XMaxRequestSize(xstuff->disp); } max_path_limit = (mrsize - 3)/2; if (max_path_limit < get_max_path_limit(grace_get_canvas(gapp->grace))) { char buf[128]; sprintf(buf, "Setting max drawing path length to %d (limited by the X server)", max_path_limit); errmsg(buf); set_max_path_limit(grace_get_canvas(gapp->grace), max_path_limit); } xstuff->dpi = rint(MM_PER_INCH*DisplayWidth(xstuff->disp, xstuff->screennumber)/ DisplayWidthMM(xstuff->disp, xstuff->screennumber)); return RETURN_SUCCESS; }
static void handleSelectionRequest(XSelectionRequestEvent ev) { static long chunk_size; static Atom targets; int sel_len = 0; int x, y; unsigned char *dst = cutBuffer; XEvent res; sortSelectionCorners(); //printf("cx1=%d\n", cx1); for (y = cy1; y <= cy2; y++) { for (x = cx1; x <= cx2; x++) { *dst++ = bws[y * selected_model->text_width + x]; sel_len++; } *dst++ = 0x0a; sel_len++; } if (!targets) { targets = XInternAtom(display, "TARGETS", False); } if (!chunk_size) { chunk_size = XExtendedMaxRequestSize(display) / 4; if (!chunk_size) { chunk_size = XMaxRequestSize(display) / 4; } } sel_len = sel_len > chunk_size ? chunk_size : sel_len; XChangeProperty(display, ev.requestor, ev.property, XA_STRING, 8, PropModeReplace, cutBuffer, sel_len); res.xselection.property = ev.property; res.xselection.type = SelectionNotify; res.xselection.display = ev.display; res.xselection.requestor = ev.requestor; res.xselection.selection = ev.selection; res.xselection.target = ev.target; res.xselection.time = ev.time; XSendEvent(display, ev.requestor, 0, 0, &res); XFlush(display); }
/* put data into a selection, in response to a SelecionRequest event from * another window (and any subsequent events relating to an INCR transfer). * * Arguments are: * * A display * * A window * * The event to respond to * * A pointer to an Atom. This gets set to the property nominated by the other * app in it's SelectionRequest. Things are likely to break if you change the * value of this yourself. * * The target(UTF8_STRING or XA_STRING) to respond to * * A pointer to an array of chars to read selection data from. * * The length of the array of chars. * * In the case of an INCR transfer, the position within the array of chars * that is being processed. * * The context that event is the be processed within. */ int xcin(Display * dpy, Window * win, XEvent evt, Atom * pty, Atom target, unsigned char *txt, unsigned long len, unsigned long *pos, unsigned int *context) { unsigned long chunk_len; /* length of current chunk (for incr * transfers only) */ XEvent res; /* response to event */ static Atom inc; static Atom targets; static long chunk_size; if (!targets) { targets = XInternAtom(dpy, "TARGETS", False); } if (!inc) { inc = XInternAtom(dpy, "INCR", False); } /* We consider selections larger than a quarter of the maximum request size to be "large". See ICCCM section 2.5 */ if (!chunk_size) { chunk_size = XExtendedMaxRequestSize(dpy) / 4; if (!chunk_size) { chunk_size = XMaxRequestSize(dpy) / 4; } } switch (*context) { case XCLIB_XCIN_NONE: if (evt.type != SelectionRequest) return (0); /* set the window and property that is being used */ *win = evt.xselectionrequest.requestor; *pty = evt.xselectionrequest.property; /* reset position to 0 */ *pos = 0; /* put the data into an property */ if (evt.xselectionrequest.target == targets) { Atom types[2] = { targets, target }; /* send data all at once (not using INCR) */ XChangeProperty(dpy, *win, *pty, XA_ATOM, 32, PropModeReplace, (unsigned char *) types, (int) (sizeof(types) / sizeof(Atom)) ); } else if (len > chunk_size) { /* send INCR response */ XChangeProperty(dpy, *win, *pty, inc, 32, PropModeReplace, 0, 0); /* With the INCR mechanism, we need to know * when the requestor window changes (deletes) * its properties */ XSelectInput(dpy, *win, PropertyChangeMask); *context = XCLIB_XCIN_INCR; } else { /* send data all at once (not using INCR) */ XChangeProperty(dpy, *win, *pty, target, 8, PropModeReplace, (unsigned char *) txt, (int) len); } /* Perhaps FIXME: According to ICCCM section 2.5, we should confirm that XChangeProperty succeeded without any Alloc errors before replying with SelectionNotify. However, doing so would require an error handler which modifies a global variable, plus doing XSync after each XChangeProperty. */ /* set values for the response event */ res.xselection.property = *pty; res.xselection.type = SelectionNotify; res.xselection.display = evt.xselectionrequest.display; res.xselection.requestor = *win; res.xselection.selection = evt.xselectionrequest.selection; res.xselection.target = evt.xselectionrequest.target; res.xselection.time = evt.xselectionrequest.time; /* send the response event */ XSendEvent(dpy, evt.xselectionrequest.requestor, 0, 0, &res); XFlush(dpy); /* if len < chunk_size, then the data was sent all at * once and the transfer is now complete, return 1 */ if (len > chunk_size) return (0); else return (1); break; case XCLIB_XCIN_INCR: /* length of current chunk */ /* ignore non-property events */ if (evt.type != PropertyNotify) return (0); /* ignore the event unless it's to report that the * property has been deleted */ if (evt.xproperty.state != PropertyDelete) return (0); /* set the chunk length to the maximum size */ chunk_len = chunk_size; /* if a chunk length of maximum size would extend * beyond the end ot txt, set the length to be the * remaining length of txt */ if ((*pos + chunk_len) > len) chunk_len = len - *pos; /* if the start of the chunk is beyond the end of txt, * then we've already sent all the data, so set the * length to be zero */ if (*pos > len) chunk_len = 0; if (chunk_len) { /* put the chunk into the property */ XChangeProperty(dpy, *win, *pty, target, 8, PropModeReplace, &txt[*pos], (int) chunk_len); } else { /* make an empty property to show we've * finished the transfer */ XChangeProperty(dpy, *win, *pty, target, 8, PropModeReplace, 0, 0); } XFlush(dpy); /* all data has been sent, break out of the loop */ if (!chunk_len) *context = XCLIB_XCIN_NONE; *pos += chunk_size; /* if chunk_len == 0, we just finished the transfer, * return 1 */ if (chunk_len > 0) return (0); else return (1); break; } return (0); }
/* Put data into a selection, in response to a SelecionRequest event from * another window (and any subsequent events relating to an INCR transfer). * * Arguments are: * A display * A window * The event to respond to * A pointer to an Atom. This gets set to the property nominated by the other * app in it's SelectionRequest. Things are likely to break if you change the * value of this yourself. * The target (UTF8_STRING or XA_STRING) to respond to * A pointer to an array of chars to read selection data from. * The length of the array of chars. * In case of an INCR transfer, the position within the array of chars that's being processed. * The context that event is the be processed within. */ static int xcin( Display*dpy, Window*win, XEvent evt, Atom*prop, Atom trg, uchar*txt, ulong len, ulong*pos, uint *ctx ) { ulong chunk_len; /* length of current chunk (for incr transfers only) */ XEvent resp; /* response to event */ static Atom inc; static Atom targets; static long chunk_size; if (!targets) { targets = XInternAtom(dpy, "TARGETS", False); } if (!inc) { inc = XInternAtom(dpy, "INCR", False); } /* Treat selections larger than 1/4 of the max request size as "large" per ICCCM sect. 2.5 */ if (!chunk_size) { chunk_size = XExtendedMaxRequestSize(dpy) / 4; if (!chunk_size) { chunk_size = XMaxRequestSize(dpy) / 4; } } switch (*ctx) { case XCLIB_XCIN_NONE: { if (evt.type != SelectionRequest) { return (0); } *win = evt.xselectionrequest.requestor; *prop = evt.xselectionrequest.property; *pos = 0; if (evt.xselectionrequest.target == targets) { /* put the data into an property */ Atom types[2]; int size=(int)(sizeof(types)/sizeof(Atom)); types[0]=targets; types[1]=trg; /* send data all at once (not using INCR) */ XChangeProperty(dpy,*win,*prop,XA_ATOM,32,PropModeReplace,(uchar*)types,size); } else if (len > chunk_size) { XChangeProperty(dpy,*win,*prop,inc,32,PropModeReplace,0,0); /* send INCR response */ /* With INCR, we need to know when requestor window changes/deletes properties */ XSelectInput(dpy, *win, PropertyChangeMask); *ctx = XCLIB_XCIN_INCR; } else { XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,(uchar*)txt,(int)len); /* All, not INCR */ } /* FIXME? According to ICCCM section 2.5, we should confirm that X ChangeProperty succeeded without any Alloc errors before replying with SelectionNotify. However, doing so would require an error handler which modifies a global variable, plus doing XSync after each X ChangeProperty. */ resp.xselection.property = *prop; resp.xselection.type = SelectionNotify; resp.xselection.display = evt.xselectionrequest.display; resp.xselection.requestor = *win; resp.xselection.selection = evt.xselectionrequest.selection; resp.xselection.target = evt.xselectionrequest.target; resp.xselection.time = evt.xselectionrequest.time; XSendEvent(dpy, evt.xselectionrequest.requestor, 0, 0, &resp); /* send response event */ XFlush(dpy); return (len > chunk_size) ? 0 : 1; /* if data sent all at once, transfer is complete. */ break; } case XCLIB_XCIN_INCR: { if (evt.type != PropertyNotify) { return (0); } /* ignore non-property events */ if (evt.xproperty.state != PropertyDelete) { return (0); } /* only interest in deleted props */ chunk_len = chunk_size; /* set length to max size */ /* if a max-sized chunk length would extend past end, set length to remaining txt length */ if ((*pos + chunk_len) > len) { chunk_len = len - *pos; } /* if start of chunk is beyond end of txt, then we've sent all data, so set length to zero */ if (*pos > len) { chunk_len = 0; } if (chunk_len) { /* put chunk into property */ XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,&txt[*pos],(int)chunk_len); } else { XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,0,0); /* empty prop shows we're done */ } XFlush(dpy); if (!chunk_len) { *ctx = XCLIB_XCIN_NONE; } /* all data is sent, break out of the loop */ *pos += chunk_size; return (chunk_len==0) ? 1 : 0; /* chunk_len == 0 means we finished the transfer. */ break; } } return (0); }