]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/xcut.c
r4275@bucket (orig r265): kcr | 2008-01-21 02:57:32 -0500
[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 #include "X_driver.h"
41
42 /*
43  *
44  */
45
46 extern long ttl;
47
48 static char *selected_text=NULL;
49 static Window selecting_in = 0;
50
51 char *
52 getSelectedText(void)
53 {
54    return(selected_text);
55 }
56
57 #ifdef notdef
58 static string
59 x_gram_to_string(x_gram *gram)
60 {
61     int i, index, len;
62     int last_y = -1;
63     string temp;
64     string text_so_far = string_Copy("");
65     char *text;
66
67     text = gram->text;
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);
75         free(temp);
76         last_y = gram->blocks[i].y;
77     }
78
79     text_so_far = string_Concat2(text_so_far, "\n");
80     return(text_so_far);
81 }
82 #endif
83
84 /*
85  *
86  */
87
88 /*ARGSUSED*/
89 Bool
90 isShiftButton1(Display *dpy,
91                XEvent *event,
92                char *arg)
93 {
94    return(event->xbutton.state & (ShiftMask|Button1Mask));
95 }
96
97 /*ARGSUSED*/
98 Bool
99 isShiftButton3(Display *dpy,
100                XEvent *event,
101                char *arg)
102 {
103    return(event->xbutton.state & (ShiftMask|Button3Mask));
104 }
105
106 void
107 getLastEvent(Display *dpy,
108              unsigned int state,
109              XEvent *event)
110 {
111    XEvent xev;
112
113    if (state & Button1Mask) {
114       while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL))
115          *event=xev;
116    } else if (state & Button3Mask) {
117       while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL))
118          *event=xev;
119    }
120 }
121
122 void
123 xunmark(Display *dpy,
124         Window w,
125         x_gram *gram,
126         XContext desc_context)
127 {
128    if (gram == NULL)
129      if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
130        return;
131
132    xmarkClear();
133    xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD);
134 }
135
136 /* This is out here so xdestroygram can get at it */
137
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 */
144
145 static int current_pressop = PRESSOP_NONE;
146
147 void
148 xdestroygram(Display *dpy,
149              Window w,
150              XContext desc_context,
151              x_gram *gram)
152 {
153     struct timeval now;
154
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)))
160         return;
161
162     if (w == selecting_in) {
163         selecting_in = 0;
164         xmarkClear();
165     }
166     current_pressop = PRESSOP_NONE;
167     XDeleteContext(dpy, w, desc_context);
168     XDestroyWindow(dpy, w);
169     delete_gram(gram);
170     free(gram->text);
171     free(gram->blocks);
172     free(gram);
173
174     if (bottom_gram == NULL && unlinked == NULL) {
175        /* flush colormap here */
176     }
177 }
178
179 void
180 xcut(Display *dpy,
181      XEvent *event,
182      XContext desc_context)
183 {
184     x_gram *gram;
185     Window w = event->xany.window;
186     int changedbound;
187
188     /*
189      * If event is for a window that's not ours anymore (say we're
190      * in the process of deleting it...), ignore it:
191      */
192     if (XFindContext(dpy, w, desc_context, (caddr_t *) &gram))
193       return;
194
195     /*
196      * Dispatch on the event type:
197      */
198     switch(event->type) {
199       case ClientMessage:
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);
204         break;
205
206       case MapNotify:
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
209          */
210
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;
215         }
216         break;
217
218       case UnmapNotify:
219         unlink_gram(gram);
220         break;
221
222       case LeaveNotify:
223         if (current_pressop == PRESSOP_KILL ||
224             current_pressop == PRESSOP_NUKE)
225            current_pressop = PRESSOP_STOP;
226         break;
227
228       case MotionNotify:
229         if (current_pressop == PRESSOP_SEL) {
230            /*     getLastEvent(dpy,Button1Mask,event); */
231            changedbound=xmarkExtendFromFirst(gram,event->xmotion.x,
232                                              event->xmotion.y);
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,
237                                                event->xmotion.y);
238            xmarkRedraw(dpy,w,gram,changedbound);
239         } 
240         break;
241
242       case ButtonPress:
243         if (current_pressop != PRESSOP_NONE) {
244            current_pressop = PRESSOP_STOP;
245         } else if ((event->xbutton.button==Button4 ||
246                     event->xbutton.button==Button5) &&
247                    !get_bool_resource("scrollDelete","ScrollDelete",0)) {
248            /* Ignore scroll wheel movement. */
249            break;
250         } else if ( (event->xbutton.state)&ShiftMask ) {
251            if (event->xbutton.button==Button1) {
252               if (selecting_in)
253                  xunmark(dpy,selecting_in,NULL,desc_context);
254               if (selected_text) free(selected_text);
255               selected_text = NULL;
256               if (! xselGetOwnership(dpy,w,event->xbutton.time)) {
257                  XBell(dpy,0);
258                  ERROR("Unable to get ownership of PRIMARY selection.\n");
259                  selecting_in = 0;
260                  current_pressop = PRESSOP_STOP;
261               } else {
262                  selecting_in = w;
263                  xmarkStart(gram,event->xbutton.x,event->xbutton.y);
264                  current_pressop = PRESSOP_SEL;
265               }
266            } else if ((event->xbutton.button==Button3) &&
267                       (w == selecting_in)) {
268               if (selected_text) free(selected_text);
269               selected_text = NULL;
270               changedbound=xmarkExtendFromNearest(gram,event->xbutton.x,
271                                                   event->xbutton.y);
272               xmarkRedraw(dpy,w,gram,changedbound);
273               selected_text = xmarkGetText();
274               /* this is ok, since to get here, the selection must be owned */
275               current_pressop = PRESSOP_EXT;
276            }
277         } else if ( (event->xbutton.state)&ControlMask ) {
278            current_pressop = PRESSOP_NUKE;
279         } else {
280            current_pressop = PRESSOP_KILL;
281         }
282         break;
283
284       case ButtonRelease:
285         if (current_pressop == PRESSOP_KILL) {
286            xdestroygram(dpy,w,desc_context,gram);
287         } else if (current_pressop == PRESSOP_SEL ||
288                    current_pressop == PRESSOP_EXT) {
289            if (selected_text) free(selected_text);
290            selected_text = xmarkGetText();
291         } else if (current_pressop == PRESSOP_NUKE) {
292            XWindowAttributes wa;
293            int gx,gy;
294            Window temp;
295            x_gram *next;
296
297            for (gram = bottom_gram ; gram ; gram = next) {
298               XGetWindowAttributes(dpy,gram->w,&wa);
299               XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
300                                     &temp);
301
302               next = gram->above;
303
304               if ((wa.map_state == IsViewable) &&
305                   (gx <= event->xbutton.x_root) &&
306                   (event->xbutton.x_root < gx+wa.width) &&
307                   (gy <= event->xbutton.y_root) &&
308                   (event->xbutton.y_root < gy+wa.height)) {
309                  xdestroygram(dpy,gram->w,desc_context,gram);
310               }
311            }
312            for (gram = unlinked ; gram ; gram = next) {
313               XGetWindowAttributes(dpy,gram->w,&wa);
314               XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
315                                     &temp);
316
317               next = gram->above;
318
319               if ((wa.map_state == IsViewable) &&
320                   (gx <= event->xbutton.x_root) &&
321                   (event->xbutton.x_root < gx+wa.width) &&
322                   (gy <= event->xbutton.y_root) &&
323                   (event->xbutton.y_root < gy+wa.height)) {
324                  xdestroygram(dpy,gram->w,desc_context,gram);
325               }
326            }
327         }
328         current_pressop = PRESSOP_NONE;
329         break;
330
331      case SelectionRequest:
332        xselProcessSelection(dpy,w,event);
333        break;
334
335      case SelectionClear:
336        xselOwnershipLost(event->xselectionclear.time);
337        if (w == selecting_in) {
338           selecting_in = 0;
339           xunmark(dpy,w,gram,desc_context);
340           if (selected_text) free(selected_text);
341           selected_text = NULL;
342        }
343        break;
344
345 #ifdef notdef
346       case ConfigureNotify:
347 #ifdef DEBUG
348         if (zwgc_debug)
349           printf("ConfigureNotify received for wid %lx above wid %lx\n",
350                  (long) w,(long) event->xconfigure.above);
351 #endif
352         if (gram->above==gram) {
353            /* a new zgram.  Straight to the bottom! */
354            add_to_bottom(gram);
355         } else if (event->xconfigure.above)  {
356            /* some zgram was pulled to the top */
357            pull_to_top(gram);
358         } else {
359            /* Some zgram was pushed to the bottom */
360            push_to_bottom(gram);
361         }
362         /* Note that there is no option to configure a zgram to the middle */
363         break;
364 #endif
365       default:
366         break;
367     }
368
369     XFlush(dpy);
370 }
371
372 #endif
373