]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/xcut.c
b6019a96191c68d9eafbea8c59bbdf4dcefa1a7e
[1ts-debian.git] / zephyr / zwgc / xcut.c
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
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id$
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_xcut_c[] = "$Id$";
18 #endif
19
20 #include <zephyr/mit-copyright.h>
21
22 /****************************************************************************/
23 /*                                                                          */
24 /*                    Code to deal with handling X events:                  */
25 /*                                                                          */
26 /****************************************************************************/
27
28 #ifndef X_DISPLAY_MISSING
29
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32 #include "new_memory.h"
33 #include "new_string.h"
34 #include "X_gram.h"
35 #include "zwgc.h"
36 #include "xselect.h"
37 #include "xmark.h"
38 #include "error.h"
39 #include "xrevstack.h"
40
41 /*
42  *
43  */
44
45 extern long ttl;
46
47 static char *selected_text=NULL;
48 static Window selecting_in = 0;
49
50 char *
51 getSelectedText(void)
52 {
53    return(selected_text);
54 }
55
56 #ifdef notdef
57 static string
58 x_gram_to_string(x_gram *gram)
59 {
60     int i, index, len;
61     int last_y = -1;
62     string temp;
63     string text_so_far = string_Copy("");
64     char *text;
65
66     text = gram->text;
67     for (i=0; i<gram->numblocks; i++) {
68         if (last_y != -1 && last_y != gram->blocks[i].y)
69           text_so_far = string_Concat2(text_so_far, "\n");
70         index = gram->blocks[i].strindex;
71         len = gram->blocks[i].strlen;
72         temp = string_CreateFromData(text+index, len);
73         text_so_far = string_Concat2(text_so_far, temp);
74         free(temp);
75         last_y = gram->blocks[i].y;
76     }
77
78     text_so_far = string_Concat2(text_so_far, "\n");
79     return(text_so_far);
80 }
81 #endif
82
83 /*
84  *
85  */
86
87 /*ARGSUSED*/
88 Bool
89 isShiftButton1(Display *dpy,
90                XEvent *event,
91                char *arg)
92 {
93    return(event->xbutton.state & (ShiftMask|Button1Mask));
94 }
95
96 /*ARGSUSED*/
97 Bool
98 isShiftButton3(Display *dpy,
99                XEvent *event,
100                char *arg)
101 {
102    return(event->xbutton.state & (ShiftMask|Button3Mask));
103 }
104
105 void
106 getLastEvent(Display *dpy,
107              unsigned int state,
108              XEvent *event)
109 {
110    XEvent xev;
111
112    if (state & Button1Mask) {
113       while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL))
114          *event=xev;
115    } else if (state & Button3Mask) {
116       while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL))
117          *event=xev;
118    }
119 }
120
121 void
122 xunmark(Display *dpy,
123         Window w,
124         x_gram *gram,
125         XContext desc_context)
126 {
127    if (gram == NULL)
128      if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
129        return;
130
131    xmarkClear();
132    xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD);
133 }
134
135 /* This is out here so xdestroygram can get at it */
136
137 #define PRESSOP_NONE 0  /* nothing */
138 #define PRESSOP_KILL 1  /* normal click */
139 #define PRESSOP_SEL  2  /* shift left */
140 #define PRESSOP_EXT  3  /* shift right */
141 #define PRESSOP_NUKE 4  /* ctrl */
142 #define PRESSOP_STOP 5  /* pressop cancelled by moving out of window */
143
144 static int current_pressop = PRESSOP_NONE;
145
146 void
147 xdestroygram(Display *dpy,
148              Window w,
149              XContext desc_context,
150              x_gram *gram)
151 {
152     struct timeval now;
153
154     gettimeofday(&now,NULL);
155     if ((gram->can_die.tv_sec == 0) ||
156         (gram->can_die.tv_sec > now.tv_sec) ||
157         ((gram->can_die.tv_sec == now.tv_sec) &&
158          (gram->can_die.tv_usec > now.tv_usec)))
159         return;
160
161     if (w == selecting_in) {
162         selecting_in = 0;
163         xmarkClear();
164     }
165     current_pressop = PRESSOP_NONE;
166     XDeleteContext(dpy, w, desc_context);
167     XDestroyWindow(dpy, w);
168     delete_gram(gram);
169     free(gram->text);
170     free(gram->blocks);
171     free(gram);
172
173     if (bottom_gram == NULL && unlinked == NULL) {
174        /* flush colormap here */
175     }
176 }
177
178 void
179 xcut(Display *dpy,
180      XEvent *event,
181      XContext desc_context)
182 {
183     x_gram *gram;
184     Window w = event->xany.window;
185     int changedbound;
186
187     /*
188      * If event is for a window that's not ours anymore (say we're
189      * in the process of deleting it...), ignore it:
190      */
191     if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
192       return;
193
194     /*
195      * Dispatch on the event type:
196      */
197     switch(event->type) {
198       case ClientMessage:
199         if ((event->xclient.message_type == XA_WM_PROTOCOLS) &&
200             (event->xclient.format == 32) &&
201             (event->xclient.data.l[0] == XA_WM_DELETE_WINDOW))
202             xdestroygram(dpy,w,desc_context,gram);
203         break;
204
205       case MapNotify:
206         /* I don't like using the local time, but MapNotify events don't
207          * come with a timestamp, and there's no way to query the server
208          */
209
210         if (gram->can_die.tv_sec == 0) {
211             gettimeofday(&(gram->can_die),NULL);
212             gram->can_die.tv_sec += (int) (ttl/1000);
213             gram->can_die.tv_usec += (ttl%1000)*1000;
214         }
215         break;
216
217       case UnmapNotify:
218         unlink_gram(gram);
219         break;
220
221       case LeaveNotify:
222         if (current_pressop == PRESSOP_KILL ||
223             current_pressop == PRESSOP_NUKE)
224            current_pressop = PRESSOP_STOP;
225         break;
226
227       case MotionNotify:
228         if (current_pressop == PRESSOP_SEL) {
229            /*     getLastEvent(dpy,Button1Mask,event); */
230            changedbound=xmarkExtendFromFirst(gram,event->xmotion.x,
231                                              event->xmotion.y);
232            xmarkRedraw(dpy,w,gram,changedbound);
233         } else if (current_pressop == PRESSOP_EXT) {
234            /*     getLastEvent(dpy,Button3Mask,event); */
235            changedbound=xmarkExtendFromNearest(gram,event->xmotion.x,
236                                                event->xmotion.y);
237            xmarkRedraw(dpy,w,gram,changedbound);
238         } 
239         break;
240
241       case ButtonPress:
242         if (current_pressop != PRESSOP_NONE) {
243            current_pressop = PRESSOP_STOP;
244         } else if ((event->xbutton.button==Button4 ||
245                     event->xbutton.button==Button5) &&
246                    !get_bool_resource("scrollDelete","ScrollDelete",0)) {
247            /* Ignore scroll wheel movement. */
248            break;
249         } else if ( (event->xbutton.state)&ShiftMask ) {
250            if (event->xbutton.button==Button1) {
251               if (selecting_in)
252                  xunmark(dpy,selecting_in,NULL,desc_context);
253               if (selected_text) free(selected_text);
254               selected_text = NULL;
255               if (! xselGetOwnership(dpy,w,event->xbutton.time)) {
256                  XBell(dpy,0);
257                  ERROR("Unable to get ownership of PRIMARY selection.\n");
258                  selecting_in = 0;
259                  current_pressop = PRESSOP_STOP;
260               } else {
261                  selecting_in = w;
262                  xmarkStart(gram,event->xbutton.x,event->xbutton.y);
263                  current_pressop = PRESSOP_SEL;
264               }
265            } else if ((event->xbutton.button==Button3) &&
266                       (w == selecting_in)) {
267               if (selected_text) free(selected_text);
268               selected_text = NULL;
269               changedbound=xmarkExtendFromNearest(gram,event->xbutton.x,
270                                                   event->xbutton.y);
271               xmarkRedraw(dpy,w,gram,changedbound);
272               selected_text = xmarkGetText();
273               /* this is ok, since to get here, the selection must be owned */
274               current_pressop = PRESSOP_EXT;
275            }
276         } else if ( (event->xbutton.state)&ControlMask ) {
277            current_pressop = PRESSOP_NUKE;
278         } else {
279            current_pressop = PRESSOP_KILL;
280         }
281         break;
282
283       case ButtonRelease:
284         if (current_pressop == PRESSOP_KILL) {
285            xdestroygram(dpy,w,desc_context,gram);
286         } else if (current_pressop == PRESSOP_SEL ||
287                    current_pressop == PRESSOP_EXT) {
288            if (selected_text) free(selected_text);
289            selected_text = xmarkGetText();
290         } else if (current_pressop == PRESSOP_NUKE) {
291            XWindowAttributes wa;
292            int gx,gy;
293            Window temp;
294            x_gram *next;
295
296            for (gram = bottom_gram ; gram ; gram = next) {
297               XGetWindowAttributes(dpy,gram->w,&wa);
298               XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
299                                     &temp);
300
301               next = gram->above;
302
303               if ((wa.map_state == IsViewable) &&
304                   (gx <= event->xbutton.x_root) &&
305                   (event->xbutton.x_root < gx+wa.width) &&
306                   (gy <= event->xbutton.y_root) &&
307                   (event->xbutton.y_root < gy+wa.height)) {
308                  xdestroygram(dpy,gram->w,desc_context,gram);
309               }
310            }
311            for (gram = unlinked ; gram ; gram = next) {
312               XGetWindowAttributes(dpy,gram->w,&wa);
313               XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
314                                     &temp);
315
316               next = gram->above;
317
318               if ((wa.map_state == IsViewable) &&
319                   (gx <= event->xbutton.x_root) &&
320                   (event->xbutton.x_root < gx+wa.width) &&
321                   (gy <= event->xbutton.y_root) &&
322                   (event->xbutton.y_root < gy+wa.height)) {
323                  xdestroygram(dpy,gram->w,desc_context,gram);
324               }
325            }
326         }
327         current_pressop = PRESSOP_NONE;
328         break;
329
330      case SelectionRequest:
331        xselProcessSelection(dpy,w,event);
332        break;
333
334      case SelectionClear:
335        xselOwnershipLost(event->xselectionclear.time);
336        if (w == selecting_in) {
337           selecting_in = 0;
338           xunmark(dpy,w,gram,desc_context);
339           if (selected_text) free(selected_text);
340           selected_text = NULL;
341        }
342        break;
343
344 #ifdef notdef
345       case ConfigureNotify:
346 #ifdef DEBUG
347         if (zwgc_debug)
348           printf("ConfigureNotify received for wid %lx above wid %lx\n",
349                  (long) w,(long) event->xconfigure.above);
350 #endif
351         if (gram->above==gram) {
352            /* a new zgram.  Straight to the bottom! */
353            add_to_bottom(gram);
354         } else if (event->xconfigure.above)  {
355            /* some zgram was pulled to the top */
356            pull_to_top(gram);
357         } else {
358            /* Some zgram was pushed to the bottom */
359            push_to_bottom(gram);
360         }
361         /* Note that there is no option to configure a zgram to the middle */
362         break;
363 #endif
364       default:
365         break;
366     }
367
368     XFlush(dpy);
369 }
370
371 #endif
372