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 2630 2011-02-02 05:26:26Z kcr@ATHENA.MIT.EDU $
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 2630 2011-02-02 05:26:26Z kcr@ATHENA.MIT.EDU $";
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 <zephyr/zephyr.h>
33 #include "new_memory.h"
34 #include "new_string.h"
40 #include "xrevstack.h"
45 #include "variables.h"
54 static char *selected_text=NULL;
55 static Window selecting_in = 0;
60 return(selected_text);
65 x_gram_to_string(x_gram *gram)
70 string text_so_far = string_Copy("");
74 for (i=0; i<gram->numblocks; i++) {
75 if (last_y != -1 && last_y != gram->blocks[i].y)
76 text_so_far = string_Concat2(text_so_far, "\n");
77 index = gram->blocks[i].strindex;
78 len = gram->blocks[i].strlen;
79 temp = string_CreateFromData(text+index, len);
80 text_so_far = string_Concat2(text_so_far, temp);
82 last_y = gram->blocks[i].y;
85 text_so_far = string_Concat2(text_so_far, "\n");
96 isShiftButton1(Display *dpy,
100 return(event->xbutton.state & (ShiftMask|Button1Mask));
105 isShiftButton3(Display *dpy,
109 return(event->xbutton.state & (ShiftMask|Button3Mask));
113 getLastEvent(Display *dpy,
119 if (state & Button1Mask) {
120 while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL))
122 } else if (state & Button3Mask) {
123 while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL))
129 xunmark(Display *dpy,
132 XContext desc_context)
135 if (XFindContext(dpy, w, desc_context, (XPointer *) &gram))
139 xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD);
142 /* This is out here so xdestroygram can get at it */
144 #define PRESSOP_NONE 0 /* nothing */
145 #define PRESSOP_KILL 1 /* normal click */
146 #define PRESSOP_SEL 2 /* shift left */
147 #define PRESSOP_EXT 3 /* shift right */
148 #define PRESSOP_NUKE 4 /* ctrl */
149 #define PRESSOP_STOP 5 /* pressop cancelled by moving out of window */
151 static int current_pressop = PRESSOP_NONE;
154 xdestroygram(Display *dpy,
156 XContext desc_context,
162 gettimeofday(&now,NULL);
163 if ((gram->can_die.tv_sec == 0) ||
164 (gram->can_die.tv_sec > now.tv_sec) ||
165 ((gram->can_die.tv_sec == now.tv_sec) &&
166 (gram->can_die.tv_usec > now.tv_usec)))
169 if (w == selecting_in) {
173 current_pressop = PRESSOP_NONE;
174 XDeleteContext(dpy, w, desc_context);
175 XDestroyWindow(dpy, w);
178 for (i=0; i < gram->numblocks; i++)
179 free(gram->blocks[i].wstr);
183 list_del_notice(gram->notice);
191 if (bottom_gram == NULL && unlinked == NULL) {
192 /* flush colormap here */
199 XContext desc_context)
202 Window w = event->xany.window;
206 * If event is for a window that's not ours anymore (say we're
207 * in the process of deleting it...), ignore it:
209 if (XFindContext(dpy, w, desc_context, (XPointer *) &gram))
213 * Dispatch on the event type:
215 switch(event->type) {
222 res = XLookupString(&(event->xkey), &c, 1, NULL, NULL);
223 metaflag = event->xkey.state & Mod1Mask;
225 /* Recheck if zwgcplus is turned on;
226 * Zephyr variables override zwgc variables
230 plusvar = ZGetVariable("zwgcplus")
231 ? ZGetVariable("zwgcplus") : var_get_variable("zwgcplus");
233 if ((plusvar[0]=='\0') || (strcmp(plusvar,"no") == 0))
236 if (strcmp(plusvar,"no") == 0)
238 if (strcmp(plusvar,"new") == 0)
242 if (res != 0 && zwgcplus != 0)
243 plus_retry_notice(gram->notice, c, metaflag);
248 if ((event->xclient.message_type == XA_WM_PROTOCOLS) &&
249 (event->xclient.format == 32) &&
250 (event->xclient.data.l[0] == XA_WM_DELETE_WINDOW))
251 xdestroygram(dpy,w,desc_context,gram);
255 /* I don't like using the local time, but MapNotify events don't
256 * come with a timestamp, and there's no way to query the server
259 if (gram->can_die.tv_sec == 0) {
260 gettimeofday(&(gram->can_die),NULL);
261 gram->can_die.tv_sec += (int) (ttl/1000);
262 gram->can_die.tv_usec += (ttl%1000)*1000;
271 if (current_pressop == PRESSOP_KILL ||
272 current_pressop == PRESSOP_NUKE)
273 current_pressop = PRESSOP_STOP;
277 if (current_pressop == PRESSOP_SEL) {
278 /* getLastEvent(dpy,Button1Mask,event); */
279 changedbound=xmarkExtendFromFirst(gram,event->xmotion.x,
281 xmarkRedraw(dpy,w,gram,changedbound);
282 } else if (current_pressop == PRESSOP_EXT) {
283 /* getLastEvent(dpy,Button3Mask,event); */
284 changedbound=xmarkExtendFromNearest(gram,event->xmotion.x,
286 xmarkRedraw(dpy,w,gram,changedbound);
291 if (current_pressop != PRESSOP_NONE) {
292 current_pressop = PRESSOP_STOP;
293 } else if ((event->xbutton.button==Button4 ||
294 event->xbutton.button==Button5) &&
295 !get_bool_resource("scrollDelete","ScrollDelete",0)) {
296 /* Ignore scroll wheel movement. */
298 } else if ( (event->xbutton.state)&ShiftMask ) {
299 if (event->xbutton.button==Button1) {
301 xunmark(dpy,selecting_in,NULL,desc_context);
302 if (selected_text) free(selected_text);
303 selected_text = NULL;
304 if (! xselGetOwnership(dpy,w,event->xbutton.time)) {
306 ERROR("Unable to get ownership of PRIMARY selection.\n");
308 current_pressop = PRESSOP_STOP;
311 xmarkStart(gram,event->xbutton.x,event->xbutton.y);
312 current_pressop = PRESSOP_SEL;
314 } else if ((event->xbutton.button==Button3) &&
315 (w == selecting_in)) {
316 if (selected_text) free(selected_text);
317 selected_text = NULL;
318 changedbound=xmarkExtendFromNearest(gram,event->xbutton.x,
320 xmarkRedraw(dpy,w,gram,changedbound);
321 selected_text = xmarkGetText();
322 /* this is ok, since to get here, the selection must be owned */
323 current_pressop = PRESSOP_EXT;
326 XStoreBytes(dpy, selected_text, strlen(selected_text)+1);
329 } else if ( (event->xbutton.state)&ControlMask ) {
330 current_pressop = PRESSOP_NUKE;
332 current_pressop = PRESSOP_KILL;
337 if (current_pressop == PRESSOP_KILL) {
338 xdestroygram(dpy,w,desc_context,gram);
339 } else if (current_pressop == PRESSOP_SEL ||
340 current_pressop == PRESSOP_EXT) {
341 if (selected_text) free(selected_text);
342 selected_text = xmarkGetText();
345 XStoreBytes(dpy, selected_text, strlen(selected_text)+1);
347 } else if (current_pressop == PRESSOP_NUKE) {
348 XWindowAttributes wa;
353 for (gram = bottom_gram ; gram ; gram = next) {
354 XGetWindowAttributes(dpy,gram->w,&wa);
355 XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
360 if ((wa.map_state == IsViewable) &&
361 (gx <= event->xbutton.x_root) &&
362 (event->xbutton.x_root < gx+wa.width) &&
363 (gy <= event->xbutton.y_root) &&
364 (event->xbutton.y_root < gy+wa.height)) {
365 xdestroygram(dpy,gram->w,desc_context,gram);
368 for (gram = unlinked ; gram ; gram = next) {
369 XGetWindowAttributes(dpy,gram->w,&wa);
370 XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy,
375 if ((wa.map_state == IsViewable) &&
376 (gx <= event->xbutton.x_root) &&
377 (event->xbutton.x_root < gx+wa.width) &&
378 (gy <= event->xbutton.y_root) &&
379 (event->xbutton.y_root < gy+wa.height)) {
380 xdestroygram(dpy,gram->w,desc_context,gram);
384 current_pressop = PRESSOP_NONE;
387 case SelectionRequest:
388 xselProcessSelection(dpy,w,event);
392 xselOwnershipLost(event->xselectionclear.time);
393 if (w == selecting_in) {
395 xunmark(dpy,w,gram,desc_context);
396 if (selected_text) free(selected_text);
397 selected_text = NULL;
402 case ConfigureNotify:
405 printf("ConfigureNotify received for wid %lx above wid %lx\n",
406 (long) w,(long) event->xconfigure.above);
408 if (gram->above==gram) {
409 /* a new zgram. Straight to the bottom! */
411 } else if (event->xconfigure.above) {
412 /* some zgram was pulled to the top */
415 /* Some zgram was pushed to the bottom */
416 push_to_bottom(gram);
418 /* Note that there is no option to configure a zgram to the middle */