1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It is one of the source files comprising zwgc, the Zephyr WindowGram
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: xcut.c,v 1.11 1999/01/22 23:20:43 ghudson Exp $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_xcut_c[] = "$Id: xcut.c,v 1.11 1999/01/22 23:20:43 ghudson Exp $";
20 #include <zephyr/mit-copyright.h>
22 /****************************************************************************/
24 /* Code to deal with handling X events: */
26 /****************************************************************************/
28 #ifndef X_DISPLAY_MISSING
31 #include <X11/Xutil.h>
32 #include "new_memory.h"
33 #include "new_string.h"
39 #include "xrevstack.h"
45 extern char *xmarkGetText();
49 static char *selected_text=NULL;
50 static Window selecting_in = 0;
52 char *getSelectedText()
54 return(selected_text);
58 static string x_gram_to_string(gram)
64 string text_so_far = string_Copy("");
68 for (i=0; i<gram->numblocks; i++) {
69 if (last_y != -1 && last_y != gram->blocks[i].y)
70 text_so_far = string_Concat2(text_so_far, "\n");
71 index = gram->blocks[i].strindex;
72 len = gram->blocks[i].strlen;
73 temp = string_CreateFromData(text+index, len);
74 text_so_far = string_Concat2(text_so_far, temp);
76 last_y = gram->blocks[i].y;
79 text_so_far = string_Concat2(text_so_far, "\n");
89 Bool isShiftButton1(dpy,event,arg)
94 return(event->xbutton.state & (ShiftMask|Button1Mask));
98 Bool isShiftButton3(dpy,event,arg)
103 return(event->xbutton.state & (ShiftMask|Button3Mask));
106 void getLastEvent(dpy,state,event)
113 if (state & Button1Mask) {
114 while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL))
116 } else if (state & Button3Mask) {
117 while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL))
122 void xunmark(dpy,w,gram,desc_context)
126 XContext desc_context;
129 if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
133 xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD);
136 /* This is out here so xdestroygram can get at it */
138 #define PRESSOP_NONE 0 /* nothing */
139 #define PRESSOP_KILL 1 /* normal click */
140 #define PRESSOP_SEL 2 /* shift left */
141 #define PRESSOP_EXT 3 /* shift right */
142 #define PRESSOP_NUKE 4 /* ctrl */
143 #define PRESSOP_STOP 5 /* pressop cancelled by moving out of window */
145 static int current_pressop = PRESSOP_NONE;
147 void xdestroygram(dpy,w,desc_context,gram)
150 XContext desc_context;
155 gettimeofday(&now,NULL);
156 if ((gram->can_die.tv_sec == 0) ||
157 (gram->can_die.tv_sec > now.tv_sec) ||
158 ((gram->can_die.tv_sec == now.tv_sec) &&
159 (gram->can_die.tv_usec > now.tv_usec)))
162 if (w == selecting_in) {
166 current_pressop = PRESSOP_NONE;
167 XDeleteContext(dpy, w, desc_context);
168 XDestroyWindow(dpy, w);
174 if (bottom_gram == NULL && unlinked == NULL) {
175 /* flush colormap here */
179 void xcut(dpy,event,desc_context)
182 XContext desc_context;
185 Window w = event->xany.window;
189 * If event is for a window that's not ours anymore (say we're
190 * in the process of deleting it...), ignore it:
192 if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
196 * Dispatch on the event type:
198 switch(event->type) {
200 if ((event->xclient.message_type == XA_WM_PROTOCOLS) &&
201 (event->xclient.format == 32) &&
202 (event->xclient.data.l[0] == XA_WM_DELETE_WINDOW))
203 xdestroygram(dpy,w,desc_context,gram);
207 /* I don't like using the local time, but MapNotify events don't
208 * come with a timestamp, and there's no way to query the server
211 if (gram->can_die.tv_sec == 0) {
212 gettimeofday(&(gram->can_die),NULL);
213 gram->can_die.tv_sec += (int) (ttl/1000);
214 gram->can_die.tv_usec += (ttl%1000)*1000;
223 if (current_pressop == PRESSOP_KILL ||
224 current_pressop == PRESSOP_NUKE)
225 current_pressop = PRESSOP_STOP;
229 if (current_pressop == PRESSOP_SEL) {
230 /* getLastEvent(dpy,Button1Mask,event); */
231 changedbound=xmarkExtendFromFirst(gram,event->xmotion.x,
233 xmarkRedraw(dpy,w,gram,changedbound);
234 } else if (current_pressop == PRESSOP_EXT) {
235 /* getLastEvent(dpy,Button3Mask,event); */
236 changedbound=xmarkExtendFromNearest(gram,event->xmotion.x,
238 xmarkRedraw(dpy,w,gram,changedbound);
243 if (current_pressop != PRESSOP_NONE) {
244 current_pressop = PRESSOP_STOP;
245 } else if ( (event->xbutton.state)&ShiftMask ) {
246 if (event->xbutton.button==Button1) {
248 xunmark(dpy,selecting_in,NULL,desc_context);
249 if (selected_text) free(selected_text);
250 selected_text = NULL;
251 if (! xselGetOwnership(dpy,w,event->xbutton.time)) {
253 ERROR("Unable to get ownership of PRIMARY selection.\n");
255 current_pressop = PRESSOP_STOP;
258 xmarkStart(gram,event->xbutton.x,event->xbutton.y);
259 current_pressop = PRESSOP_SEL;
261 } else if ((event->xbutton.button==Button3) &&
262 (w == selecting_in)) {
263 if (selected_text) free(selected_text);
264 selected_text = NULL;
265 changedbound=xmarkExtendFromNearest(gram,event->xbutton.x,
267 xmarkRedraw(dpy,w,gram,changedbound);
268 selected_text = xmarkGetText();
269 /* this is ok, since to get here, the selection must be owned */
270 current_pressop = PRESSOP_EXT;
272 } else if ( (event->xbutton.state)&ControlMask ) {
273 current_pressop = PRESSOP_NUKE;
275 current_pressop = PRESSOP_KILL;
280 if (current_pressop == PRESSOP_KILL) {
281 xdestroygram(dpy,w,desc_context,gram);
282 } else if (current_pressop == PRESSOP_SEL ||
283 current_pressop == PRESSOP_EXT) {
284 if (selected_text) free(selected_text);
285 selected_text = xmarkGetText();
286 } else if (current_pressop == PRESSOP_NUKE) {
287 XWindowAttributes wa;
292 for (gram = bottom_gram ; gram ; gram = next) {
293 XGetWindowAttributes(dpy,gram->w,&wa);
294 XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
299 if ((wa.map_state == IsViewable) &&
300 (gx <= event->xbutton.x_root) &&
301 (event->xbutton.x_root < gx+wa.width) &&
302 (gy <= event->xbutton.y_root) &&
303 (event->xbutton.y_root < gy+wa.height)) {
304 xdestroygram(dpy,gram->w,desc_context,gram);
307 for (gram = unlinked ; gram ; gram = next) {
308 XGetWindowAttributes(dpy,gram->w,&wa);
309 XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
314 if ((wa.map_state == IsViewable) &&
315 (gx <= event->xbutton.x_root) &&
316 (event->xbutton.x_root < gx+wa.width) &&
317 (gy <= event->xbutton.y_root) &&
318 (event->xbutton.y_root < gy+wa.height)) {
319 xdestroygram(dpy,gram->w,desc_context,gram);
323 current_pressop = PRESSOP_NONE;
326 case SelectionRequest:
327 xselProcessSelection(dpy,w,event);
331 xselOwnershipLost(event->xselectionclear.time);
332 if (w == selecting_in) {
334 xunmark(dpy,w,gram,desc_context);
335 if (selected_text) free(selected_text);
336 selected_text = NULL;
341 case ConfigureNotify:
344 printf("ConfigureNotify received for wid %lx above wid %lx\n",
345 (long) w,(long) event->xconfigure.above);
347 if (gram->above==gram) {
348 /* a new zgram. Straight to the bottom! */
350 } else if (event->xconfigure.above) {
351 /* some zgram was pulled to the top */
354 /* Some zgram was pushed to the bottom */
355 push_to_bottom(gram);
357 /* Note that there is no option to configure a zgram to the middle */