]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/xcut.c
Initial revision
[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: xcut.c,v 1.11 1999/01/22 23:20:43 ghudson Exp $
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: xcut.c,v 1.11 1999/01/22 23:20:43 ghudson Exp $";
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 char *xmarkGetText();
46
47 extern long ttl;
48
49 static char *selected_text=NULL;
50 static Window selecting_in = 0;
51
52 char *getSelectedText()
53 {
54    return(selected_text);
55 }
56
57 #ifdef notdef
58 static string x_gram_to_string(gram)
59      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 isShiftButton1(dpy,event,arg)
90      Display *dpy;
91      XEvent *event;
92      char *arg;
93 {
94    return(event->xbutton.state & (ShiftMask|Button1Mask));
95 }
96
97 /*ARGSUSED*/
98 Bool isShiftButton3(dpy,event,arg)
99      Display *dpy;
100      XEvent *event;
101      char *arg;
102 {
103    return(event->xbutton.state & (ShiftMask|Button3Mask));
104 }
105
106 void getLastEvent(dpy,state,event)
107      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 xunmark(dpy,w,gram,desc_context)
123      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 xdestroygram(dpy,w,desc_context,gram)
148      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 xcut(dpy,event,desc_context)
180      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.state)&ShiftMask ) {
246            if (event->xbutton.button==Button1) {
247               if (selecting_in)
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)) {
252                  XBell(dpy,0);
253                  ERROR("Unable to get ownership of PRIMARY selection.\n");
254                  selecting_in = 0;
255                  current_pressop = PRESSOP_STOP;
256               } else {
257                  selecting_in = w;
258                  xmarkStart(gram,event->xbutton.x,event->xbutton.y);
259                  current_pressop = PRESSOP_SEL;
260               }
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,
266                                                   event->xbutton.y);
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;
271            }
272         } else if ( (event->xbutton.state)&ControlMask ) {
273            current_pressop = PRESSOP_NUKE;
274         } else {
275            current_pressop = PRESSOP_KILL;
276         }
277         break;
278
279       case ButtonRelease:
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;
288            int gx,gy;
289            Window temp;
290            x_gram *next;
291
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,
295                                     &temp);
296
297               next = gram->above;
298
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);
305               }
306            }
307            for (gram = unlinked ; gram ; gram = next) {
308               XGetWindowAttributes(dpy,gram->w,&wa);
309               XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
310                                     &temp);
311
312               next = gram->above;
313
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);
320               }
321            }
322         }
323         current_pressop = PRESSOP_NONE;
324         break;
325
326      case SelectionRequest:
327        xselProcessSelection(dpy,w,event);
328        break;
329
330      case SelectionClear:
331        xselOwnershipLost(event->xselectionclear.time);
332        if (w == selecting_in) {
333           selecting_in = 0;
334           xunmark(dpy,w,gram,desc_context);
335           if (selected_text) free(selected_text);
336           selected_text = NULL;
337        }
338        break;
339
340 #ifdef notdef
341       case ConfigureNotify:
342 #ifdef DEBUG
343         if (zwgc_debug)
344           printf("ConfigureNotify received for wid %lx above wid %lx\n",
345                  (long) w,(long) event->xconfigure.above);
346 #endif
347         if (gram->above==gram) {
348            /* a new zgram.  Straight to the bottom! */
349            add_to_bottom(gram);
350         } else if (event->xconfigure.above)  {
351            /* some zgram was pulled to the top */
352            pull_to_top(gram);
353         } else {
354            /* Some zgram was pushed to the bottom */
355            push_to_bottom(gram);
356         }
357         /* Note that there is no option to configure a zgram to the middle */
358         break;
359 #endif
360       default:
361         break;
362     }
363
364     XFlush(dpy);
365 }
366
367 #endif
368