📄 coolnext.c
字号:
/* coolnext.c - CNextEvent function and support, and various event handlers and utils Copyright (C) 1996-2000 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. *//* #define DEBUG *//* #define DEBUG_ENTRY */#include <config.h>#include <stdio.h>#include <my_string.h>#include <stdlib.h>#include <stdarg.h>#include <X11/Intrinsic.h>#include "lkeysym.h"#include "stringtools.h"#include "app_glob.c"#include "coolwidget.h"#include "coollocal.h"#include "drawings.h"#include "edit.h"#include "editcmddef.h"#include "widget3d.h"#include "mad.h"int last_region = 0;int (*global_alarm_callback[33]) (CWidget *, XEvent *, CEvent *) = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};extern Pixmap Cswitchon, Cswitchoff;#ifdef HAVE_DNDextern Atom DndProtocol, OldDndProtocol;#endifvoid add_to_focus_stack (Window w);void selection_clear (void); /* from editwidget.c */int option_mouse_double_click = 300;int option_middle_button_pastes = 1;/* converts button presses from buttons 2 through 5 to button presses from 2 only, also gets double clicks */void resolve_button (XEvent * xevent, CEvent * cwevent){ static Time thyme_press = 0, thyme_release = 0; static Window window = 0; static int x, y; cwevent->state = xevent->xbutton.state; if (cwevent->state & (Button2Mask | Button3Mask /*| Button4Mask | Button5Mask */ )) cwevent->state |= Button2Mask; switch (xevent->type) { case ButtonRepeat: case ButtonRelease: case ButtonPress: cwevent->button = xevent->xbutton.button; if (cwevent->button == Button4 || cwevent->button == Button5) { /* ahaack: wheel mouse mapped as button 4 and 5 */ return; } if (cwevent->button == Button2 || cwevent->button == Button3 || cwevent->button == Button4 || cwevent->button == Button5) { cwevent->button = Button2; } cwevent->x = xevent->xbutton.x; cwevent->y = xevent->xbutton.y; if (xevent->type != ButtonRepeat) { if (window == xevent->xany.window) if (abs (x - cwevent->x) < 4 && abs (y - cwevent->y) < 4) { if (abs (xevent->xmotion.time - thyme_press) < option_mouse_double_click && xevent->type == ButtonPress) thyme_press = cwevent->double_click = 1; if (abs (xevent->xmotion.time - thyme_release) < option_mouse_double_click && xevent->type == ButtonRelease) thyme_release = cwevent->double_click = 1; } if (xevent->type == ButtonPress) thyme_press = xevent->xbutton.time; else thyme_release = xevent->xbutton.time; } x = xevent->xbutton.x; y = xevent->xbutton.y; break; case MotionNotify: x = cwevent->x = xevent->xmotion.x; y = cwevent->y = xevent->xmotion.y; break; } window = xevent->xany.window;}static long lower_window_callback (CWidget * w){ if (w->position & WINDOW_ALWAYS_LOWERED) XLowerWindow (CDisplay, w->winid); return 0;}/*sends all windows that are marked top_bottom = 1 to the bottom */void CLowerWindows (void){ for_all_widgets ((void *) lower_window_callback, 0, 0);}static long raise_window_callback (CWidget * w){ if (w->position & WINDOW_ALWAYS_RAISED) XRaiseWindow (CDisplay, w->winid); return 0;}/*sends all windows that are marked top_bottom = 2 to the top */void CRaiseWindows (void){ for_all_widgets ((void *) raise_window_callback, 0, 0);}/* {{{ here is an internal event queue handler to send events without going through XLib *//* We want to be able to send our own events internally because XSendEvent sometimes doesn't force the an event to be processed and the event sits on the queue with its thumb up its arse. */#define NUM_EVENTS_CACHED 256static unsigned char event_send_last = 0;static unsigned char event_read_last = 0;static XEvent event_sent[NUM_EVENTS_CACHED];/* returns 0, if buffer is full, else returns 1 */int push_event (XEvent * ev){ unsigned char j = event_send_last + 1; if (event_read_last == j) { /* no more space */#ifdef DEBUG/* NLS ? */ fprintf (stderr, "%s:%s:%d: *Warning* event stack full\n", PACKAGE, __FILE__, __LINE__);#endif /* we are just going to ignore this */ return 0; } if (ev->type == Expose || ev->type == InternalExpose) { /* must handle expose counts also */ unsigned char i = event_send_last - 1; XEvent *e; j = event_read_last - 1; ev->xexpose.count = 0; /* this is the very last expose by definition */ while (i != j) { /* search backwards until a similar event is found */ if ((e = &(event_sent[i]))->xany.window == ev->xany.window) { if (e->type == ev->type) { e->xexpose.count = 1; /* we are not going to actually "count", but we must indicate if the queue isn't empty with a "1" */ break; } } i--; } } memcpy (&event_sent[event_send_last], ev, sizeof (XEvent)); event_send_last++; return 1;}extern int block_push_event; /* see initapp.c *//* pops the oldest event, returns 0 if empty */int pop_event (XEvent * ev){ if (event_read_last == event_send_last) return 0; /* "stack" is empty */ block_push_event = 1; memcpy (ev, &event_sent[event_read_last], sizeof (XEvent)); memset (&event_sent[event_read_last], 0, sizeof (XEvent)); event_read_last++; block_push_event = 0; return 1;}/* use this instead of XSextEvent to send an event to your own application */int CSendEvent (XEvent * e){ int r = 0; block_push_event = 1; r = push_event (e); block_push_event = 0; return r;}/* sends an event (type = msg) to the given widget */int CSendMessage (CWidget * w, int msg){ CEvent cwevent; XEvent xevent; if (!w) return 0; memset (&cwevent, 0, sizeof (CEvent)); memset (&xevent, 0, sizeof (XEvent)); xevent.type = cwevent.type = msg; cwevent.kind = w->kind; xevent.xany.window = cwevent.window = w->winid; cwevent.ident = ""; return run_callbacks (w, &xevent, &cwevent);}int CQueueSize (){ int r = event_read_last; int s = event_send_last; s -= r; if (s < 0) return NUM_EVENTS_CACHED + s; return s;}/* returns nonzero if pending on either internal or X queue */int CPending (){ if (CQueueSize ()) return 1; if (XEventsQueued (CDisplay, QueuedAfterFlush)) return 1; return 0;}/* does checks for expose events pending, if there is one on either queue then it removes it and returns it. */int CExposePending (Window w, XEvent * ev){ XEvent *e; unsigned char i = event_read_last; while (i != event_send_last) { if ((e = &(event_sent[i]))->xany.window == w) if (e->type == Expose) { memcpy (ev, e, sizeof (XEvent)); e->type = 0; return 1; } i++; } return XCheckWindowEvent (CDisplay, w, ExposureMask, ev);}/* Searches the local queue for an event matching the window and mask. Does NOT remove the event, returns non-zero if found. a mask of 0 matches any type, only the masks below are supported: add more masks as needed. A window of 0 matches any window. event_return may be passed as 0 if unneeded. */int CCheckWindowEvent (Window w, long event_mask, XEvent ** event_return){ unsigned char i = event_send_last - 1; unsigned char j = event_read_last - 1; static XEvent e; static long mask[CLASTEvent] = {99}; if (!event_mask) event_mask = 0xFFFF; if (mask[0] == 99) { memset (mask, 0, CLASTEvent * sizeof (long)); mask[KeyPress] = KeyPressMask; mask[KeyRelease] = KeyReleaseMask; mask[ButtonPress] = ButtonPressMask; mask[ButtonRelease] = ButtonReleaseMask; mask[MotionNotify] = PointerMotionMask | ButtonMotionMask; mask[EnterNotify] = EnterWindowMask; mask[LeaveNotify] = LeaveWindowMask; mask[Expose] = ExposureMask; mask[ButtonRepeat] = ButtonReleaseMask | ButtonPressMask; } while (i != j) { if ((event_sent[i].xany.window == w || !w) && (mask[event_sent[i].type] & event_mask)) { if (event_return) *event_return = &(event_sent[i]); return 1; } i--; } if (!w) { if (XCheckMaskEvent (CDisplay, event_mask, &e)) goto send_event; } else { if (XCheckWindowEvent (CDisplay, w, event_mask, &e)) goto send_event; } return 0; send_event: CSendEvent (&e); if (event_return) *event_return = &e; return 1;}int CKeyPending (void){ XSync (CDisplay, 0); return CCheckWindowEvent (0, KeyPressMask, 0);}/* send an expose event via the internal queue */int CSendExpose (Window win, int x, int y, int w, int h){ XEvent e; e.xexpose.type = Expose; e.xexpose.serial = 0; e.xexpose.send_event = 1; e.xexpose.display = CDisplay; e.xexpose.window = win; e.xexpose.x = x; e.xexpose.y = y; e.xexpose.width = w; e.xexpose.height = h; return CSendEvent (&e);}/* }}} end of internal queue handler *//* {{{ here is an expose caching-amalgamating stack system */typedef struct { short x1, y1, x2, y2; Window w; long error; int count;} CRegion; #define MAX_NUM_REGIONS 63static CRegion regions[MAX_NUM_REGIONS + 1];#define area(c) abs(((c).x1-(c).x2)*((c).y1-(c).y2))static CRegion add_regions (CRegion r1, CRegion r2){ CRegion r; r.x2 = max (max (r1.x1, r1.x2), max (r2.x1, r2.x2)); r.x1 = min (min (r1.x1, r1.x2), min (r2.x1, r2.x2)); r.y2 = max (max (r1.y1, r1.y2), max (r2.y1, r2.y2)); r.y1 = min (min (r1.y1, r1.y2), min (r2.y1, r2.y2)); r.w = r2.w; r.error = (long) area (r) - area (r1) - area (r2); r.error = max (r.error, 0); r.error += r1.error + r2.error; r.count = min (r1.count, r2.count); return r;}/* returns 1 when the stack is full, 0 otherwise */static int push_region (XExposeEvent * e){ CRegion p; p.x1 = e->x; p.x2 = e->x + e->width; p.y1 = e->y; p.y2 = e->y + e->height; p.w = e->window; p.error = 0; p.count = e->count; if (last_region) { /* this amalgamates p with a region on the stack of the same window */ CRegion q; int i; for (i = last_region - 1; i >= 0; i--) { if (regions[i].w == p.w) { q = add_regions (regions[i], p); if (q.error < 100) { regions[i] = q; /* amalgamate region, else... */ return 0; } } } } regions[last_region++] = p; /* ...store a completely new region */ if (last_region >= MAX_NUM_REGIONS) {/* NLS ? */ printf ("push_region(): last_region >= MAX_NUM_REGIONS\n"); return 1; } return 0;}/* Pops the first region matching w, if w == 0 then pops the first region, returns 1 on empty. */static int pop_region (XExposeEvent * e, Window w){ e->type = 0; if (last_region) { int i = 0; if (w == 0) goto any_window; for (i = last_region - 1; i >= 0; i--) { if (regions[i].w == w) { any_window:; e->type = Expose; e->serial = e->send_event = 0; e->display = CDisplay; e->window = regions[i].w; e->x = min (regions[i].x1, regions[i].x2); e->y = min (regions[i].y1, regions[i].y2); e->width = abs (regions[i].x1 - regions[i].x2); e->height = abs (regions[i].y1 - regions[i].y2); e->count = regions[i].count; last_region--; memmove (&(regions[i]), &(regions[i + 1]), (last_region - i) * sizeof (CRegion)); return 0; } } } return 1;}static void pop_all_regions (Window w){ XEvent e; while (!pop_region (&(e.xexpose), w)) { e.type = InternalExpose; CSendEvent (&e); }}/* }}} end expose amalgamation stack system *//* {{{ key conversion utilities *//* xim.c */KeySym key_sym_xlat (XEvent * ev, char *x_lat);KeySym CKeySym (XEvent * e){ return key_sym_xlat (e, 0);}int mod_type_key (KeySym x){ switch ((int) x) {#ifdef XK_Shift_L case XK_Shift_L:#endif#ifdef XK_Shift_R case XK_Shift_R:#endif#ifdef XK_Control_L case XK_Control_L:#endif#ifdef XK_Control_R case XK_Control_R:#endif#ifdef XK_Caps_Lock case XK_Caps_Lock:#endif#ifdef XK_Shift_Lock case XK_Shift_Lock:#endif#ifdef XK_Meta_L case XK_Meta_L:#endif#ifdef XK_Meta_R case XK_Meta_R:#endif#ifdef XK_Alt_L case XK_Alt_L:#endif#ifdef XK_Alt_R case XK_Alt_R:#endif#ifdef XK_Super_L case XK_Super_L:#endif#ifdef XK_Super_R case XK_Super_R:#endif#ifdef XK_Hyper_L case XK_Hyper_L:#endif#ifdef XK_Hyper_R case XK_Hyper_R:#endif return 1; } return 0;}/* get a 15 bit "almost unique" key sym that includes keyboard modifier info in the top 3 bits */short CKeySymMod (XEvent * ev){ KeySym p; XEvent e;#ifdef USE_XIM XIC ic;#endif int state; if (!ev) return 0; e = *ev; state = e.xkey.state; e.xkey.state = 0; /* want the raw key */#ifdef USE_XIM ic = CIC;/* turn off IC 'cos we want raw translation */ CIC = 0; p = CKeySym (&e); CIC = ic;#else p = CKeySym (&e);#endif if (p && !mod_type_key (p)) { if (state & ShiftMask) p ^= 0x1000; if (state & ControlMask) p ^= 0x2000; if (state & MyAltMask) p ^= 0x4000; p &= 0x7FFF; } else p = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -