📄 x.c
字号:
/* x.c * (c) 2002 Petr 'Brain' Kulhavy * This file is a part of the Links program, released under GPL. *//* Takovej mensi problemek se scrollovanim: * * Mikulas a Xy zpusobili, ze scrollovani a prekreslovani je asynchronni. To znamena, ze * je v tom peknej bordylek. Kdyz BFU scrollne s oknem, tak se zavola funkce scroll. Ta * posle Xum XCopyArea (prekopiruje prislusny kus okna) a vygeneruje eventu * (GraphicsExpose) na postizenou (odkrytou) oblast. Funkce XCopyArea pripadne vygeneruje * dalsi GraphicsExpose eventu na postizenou oblast, ktera se muze objevit, kdyz je * linksove okno prekryto jinym oknem. * * Funkce scroll skonci. V event handleru se nekdy v budoucnosti (treba za tyden) * zpracuji eventy od Xu, mezi nimi i GraphicsExpose - tedy prekreslovani postizenych * oblasti. * * Problem je v tom, ze v okamziku, kdy scroll skonci, neni obrazovka prekreslena do * konzistentniho stavu (misty je garbaz) a navic se muze volat dalsi scroll. Tedy * XCopyArea muze posunout garbaz nekam do cudu a az se dostane na radu prekreslovani * postizenych oblasti, garbaz se uz nikdy neprekresli. * * Ja jsem navrhoval udelat scrollovani synchronni, to znamena, ze v okamziku, kdy scroll * skonci, bude okno v konzistentnim stavu. To by znamenalo volat ze scrollu zpracovavani * eventu (alespon GraphicsExpose). To by ovsem nepomohlo, protoze prekreslovaci funkce * neprekresluje, ale registruje si bottom halfy a podobny ptakoviny a prekresluje az * nekdy v budoucnosti. Navic Mikulas rikal, ze prekreslovaci funkce muze generovat dalsi * prekreslovani (sice jsem nepochopil jak, ale hlavne, ze je vecirek), takze by to * neslo. * * Proto Mikulas vymyslel genialni tah - takzvany "genitah". Ve funkci scroll se projede * fronta eventu od Xserveru a vyberou se GraphicsExp(l)ose eventy a ulozi se do zvlastni * fronty. Ve funkci na zpracovani Xovych eventu se zpracuji eventy z teto fronty. Na * zacatku scrollovaci funkce se projedou vsechny eventy ve zvlastni fronte a updatuji se * jim souradnice podle prislusneho scrollu. * * Na to jsem ja vymyslel uzasnou vymluvu: co kdyz 1. scroll vyrobi nejake postizene * oblasti a 2. scroll bude mit jinou clipovaci oblast, ktera bude tu postizenou oblast * zasahovat z casti. Tak to se bude jako ta postizena oblast stipat na casti a ty casti * se posunou podle toho, jestli jsou zasazene tim 2. scrollem? Tim jsem ho utrel, jak * zpoceny celo. * * Takze se to nakonec udela tak, ze ze scrollu vratim hromadu rectanglu, ktere se maji * prekreslit, a Mikulas si s tim udela, co bude chtit. Podobne jako ve svgalib, kde se * vrati 1 a Mikulas si prislusnou odkrytou oblast prekresli sam. Doufam jen, ze to je * posledni verze a ze nevzniknou dalsi problemy. * * Ve funkci scroll tedy pribude argument struct rect_set **. *//* Data od XImage se alokujou pomoci malloc. get_links_icon musi alokovat taky * pomoci malloc. *//* Pozor: po kazdem XSync se musi dat * register_bottom_half(x_process_events, NULL); * jinak to bude cekat na filedescriptoru, i kdyz to ma eventy uz ve fronte. * -- mikulas */#include "cfg.h"#ifdef GRDRV_X/* #define X_DEBUG *//* #define SC_DEBUG */#if defined(X_DEBUG) || defined(SC_DEBUG) #define MESSAGE(a) fprintf(stderr,"%s",a);#endif#ifdef TEXT#undef TEXT#endif#include "links.h"/* Mikulas je PRASE: definuje makro "format" a navrch to jeste nechce vopravit */#ifdef format #undef format#endif#include <stdlib.h>#include <stdio.h>#include <X11/Xlib.h>#include <X11/X.h>#include <X11/Xutil.h>#include <X11/Xlocale.h>#include <X11/Xatom.h>#ifndef XK_MISCELLANY #define XK_MISCELLANY#endif#ifndef XK_LATIN1 #define XK_LATIN1#endif#include <X11/keysymdef.h>#ifdef HAVE_LANGINFO_H#include <langinfo.h>#endif#define X_BORDER_WIDTH 4#define X_HASH_TABLE_SIZE 64#define XPIXMAPP(a) ((struct x_pixmapa*)(a))int x_default_window_width;int x_default_window_height;long (*x_get_color_function)(int);void selection_request(XEvent *event);int x_fd; /* x socket */Display *x_display; /* display */int x_screen; /* screen */int x_display_height,x_display_width; /* screen dimensions */int x_black_pixel,x_white_pixel; /* white and black pixel */int x_depth,x_bitmap_bpp; /* bits per pixel and bytes per pixel */int x_bitmap_scanline_pad; /* bitmap scanline_padding in bytes */int x_colors; /* colors in the palette (undefined when there's no palette) */int x_have_palette;int x_input_encoding; /* locales encoding */int x_bitmap_bit_order;Window x_root_window, fake_window;GC x_normal_gc,x_copy_gc,x_drawbitmap_gc,x_scroll_gc;Colormap x_colormap;Atom x_delete_window_atom, x_wm_protocols_atom, x_sel_atom, x_targets_atom;Visual* x_default_visual;Pixmap x_icon;extern struct graphics_driver x_driver;static unsigned char *x_driver_param=NULL;static int n_wins; /* number of windows */#define X_TYPE_PIXMAP 1#define X_TYPE_IMAGE 2struct x_pixmapa{ unsigned char type; union { XImage *image; Pixmap *pixmap; }data;};struct{ unsigned char count; struct graphics_device **pointer;}x_hash_table[X_HASH_TABLE_SIZE];/* string in clipboard is in x_input_encoding */static unsigned char * x_my_clipboard=NULL;/*----------------------------------------------------------------------*//* Tyhle opicarny tu jsou pro zvyseni rychlosti. Flush se nedela pri kazde operaci, ale * rekne se, ze je potreba udelat flush, a zaregistruje se bottom-half, ktery flush * provede. Takze jakmile se vrati rizeni do select smycky, tak se provede flush. */static int flush_in_progress=0;/* prototypes */unsigned char * x_set_palette(void);int x_hscroll(struct graphics_device *, struct rect_set **, int);int x_vscroll(struct graphics_device *, struct rect_set **, int);void *x_prepare_strip(struct bitmap *, int, int);void x_commit_strip(struct bitmap *, int, int);void x_set_window_title(struct graphics_device *, unsigned char *);int x_exec(unsigned char *, int);void x_clear_clipboard(void);static void x_wait_for_event(void){ fd_set rfds; FD_ZERO(&rfds); FD_SET(x_fd, &rfds); select(x_fd+1, &rfds, NULL, NULL, NULL);}static void x_do_flush(void *ignore){ /* kdyz budu mit zaregistrovanej bottom-half na tuhle funkci a nekdo mi * tipne Xy, tak se nic nedeje, maximalne se zavola XFlush na blbej * display, ale Xy se nepodelaj */ ignore=ignore; XFlush(x_display); flush_in_progress=0;}static inline void X_FLUSH(void){ if (!flush_in_progress) { register_bottom_half(x_do_flush,NULL); flush_in_progress=1; }}static void x_process_events(void *data);static int (*old_error_handler)(Display *, XErrorEvent *) = NULL;static int failure_happened;static int failure_handler(Display *d, XErrorEvent *e){ failure_happened = 1; return 0;}static void x_prepare_for_failure(void){ if (old_error_handler) internal("x_prepare_for_failure: double call"); failure_happened = 0; old_error_handler = XSetErrorHandler(failure_handler);}static int x_test_for_failure(void){ XSync(x_display, 0); register_bottom_half(x_process_events, NULL); XSetErrorHandler(old_error_handler); old_error_handler = NULL; return failure_happened;}/* suppose l<h */static void x_clip_number(int *n,int l,int h){ if ((*n)<l)*n=l; if ((*n)>h)*n=h;}unsigned char * x_set_palette(void){ XColor color; int a,r,g,b; int tbl0[4]={0,21845,43690,65535}; int tbl1[8]={0,9362,18724,28086,37449,46811,56173,65535}; x_colormap=XCreateColormap(x_display,x_root_window,x_default_visual,AllocAll); XInstallColormap(x_display,x_colormap); switch(x_depth) { case 4: for (a=0;a<16;a++) { color.red=(a&8)?65535:0; color.green=tbl0[(a>>1)&3]; color.blue=(a&1)?65535:0; color.pixel=a; color.flags=DoRed|DoGreen|DoBlue; XStoreColor(x_display,x_colormap,&color); } break; case 8: for (a=0;a<256;a++) { color.red=tbl1[(a>>5)&7]; color.green=tbl1[(a>>2)&7]; color.blue=tbl0[a&3]; color.pixel=a; color.flags=DoRed|DoGreen|DoBlue; XStoreColor(x_display,x_colormap,&color); } break; case 15: for (a=0;a<32768;a++){ color.red=((a>>10)&31)*(65535/31); color.green=((a>>5)&31)*(65535/31); color.blue=(a&31)*(65535/31); color.pixel=a; color.flags=DoRed|DoGreen|DoBlue; XStoreColor(x_display,x_colormap,&color); } break; case 16: for (a=0;a<65536;a++){ color.red=((a>>11)&31)*(65535/31); color.green=((a>>5)&63)*(65535/63); color.blue=(a&31)*(65535/31); color.pixel=a; color.flags=DoRed|DoGreen|DoBlue; XStoreColor(x_display,x_colormap,&color); } break; case 24: for (r=0;r<256;r++) for (g=0;g<256;g++) for (b=0;b<256;b++) { color.red=r<<8; color.green=g<<8; color.blue=b<<8; color.pixel=(r<<16)+(g<<8)+(b); color.flags=DoRed|DoGreen|DoBlue; XStoreColor(x_display,x_colormap,&color); } break; } X_FLUSH(); return NULL;}static inline int trans_key(unsigned char * str, int table){ if (table==utf8_table){int a; GET_UTF_8(str,a);return a;} if (*str<128)return *str; return cp2u(*str,table);}/* translates X keys to links representation *//* return value: 1=valid key, 0=nothing */static int x_translate_key(XKeyEvent *e,int *key,int *flag){ KeySym ks; static XComposeStatus comp = { NULL, 0 }; static char str[16]; int table=x_input_encoding<0?drv->codepage:x_input_encoding; int len; len=XLookupString(e,str,15,&ks,&comp); str[len>15?15:len]=0; if (!len) str[0]=ks, str[1]=0; *flag=0; *key=0; /* alt, control, shift ... */ if (e->state&ShiftMask)*flag|=KBD_SHIFT; if (e->state&ControlMask)*flag|=KBD_CTRL; if (e->state&Mod1Mask)*flag|=KBD_ALT; /* alt-f4 */ if (((*flag)&KBD_ALT)&&(ks==XK_F4)){*key=KBD_CTRL_C;*flag=0;return 1;} /* ctrl-c */ if (((*flag)&KBD_CTRL)&&(ks==XK_c||ks==XK_C)){*key=KBD_CTRL_C;*flag=0;return 1;} switch (ks) { case NoSymbol: return 0; case XK_Return: *key=KBD_ENTER;break; case XK_BackSpace: *key=KBD_BS;break; case XK_KP_Tab: case XK_Tab: *key=KBD_TAB;break; case XK_Escape: *key=KBD_ESC;break; case XK_KP_Left: case XK_Left: *key=KBD_LEFT;break; case XK_KP_Right: case XK_Right: *key=KBD_RIGHT;break; case XK_KP_Up: case XK_Up: *key=KBD_UP;break; case XK_KP_Down: case XK_Down: *key=KBD_DOWN;break; case XK_KP_Insert: case XK_Insert: *key=KBD_INS;break; case XK_KP_Delete: case XK_Delete: *key=KBD_DEL;break; case XK_KP_Home: case XK_Home: *key=KBD_HOME;break; case XK_KP_End: case XK_End: *key=KBD_END;break; case XK_KP_Page_Up: case XK_Page_Up: *key=KBD_PAGE_UP;break; case XK_KP_Page_Down: case XK_Page_Down: *key=KBD_PAGE_DOWN;break; case XK_KP_F1: case XK_F1: *key=KBD_F1;break; case XK_KP_F2: case XK_F2: *key=KBD_F2;break; case XK_KP_F3: case XK_F3: *key=KBD_F3;break; case XK_KP_F4: case XK_F4: *key=KBD_F4;break; case XK_F5: *key=KBD_F5;break; case XK_F6: *key=KBD_F6;break; case XK_F7: *key=KBD_F7;break; case XK_F8: *key=KBD_F8;break; case XK_F9: *key=KBD_F9;break; case XK_F10: *key=KBD_F10;break; case XK_F11: *key=KBD_F11;break; case XK_F12: *key=KBD_F12;break; case XK_KP_Subtract: *key='-';break; case XK_KP_Decimal: *key='.';break; case XK_KP_Divide: *key='/';break; case XK_KP_Space: *key=' ';break; case XK_KP_Enter: *key=KBD_ENTER;break; case XK_KP_Equal: *key='=';break; case XK_KP_Multiply: *key='*';break; case XK_KP_Add: *key='+';break; case XK_KP_0: *key='0';break; case XK_KP_1: *key='1';break; case XK_KP_2: *key='2';break; case XK_KP_3: *key='3';break; case XK_KP_4: *key='4';break; case XK_KP_5: *key='5';break; case XK_KP_6: *key='6';break; case XK_KP_7: *key='7';break; case XK_KP_8: *key='8';break; case XK_KP_9: *key='9';break; default: if (ks&0x8000)return 0; *key=((*flag)&KBD_CTRL)?(int)ks&255:trans_key(str,table); break; /* default: *key=((*flag)&KBD_CTRL)?(int)ks&255:trans_key(str,table);(*flag)&=~KBD_SHIFT;break; */ } return 1;}static void x_hash_table_init(void){ int a; for (a=0;a<X_HASH_TABLE_SIZE;a++) { x_hash_table[a].count=0; x_hash_table[a].pointer=NULL; }}static void x_free_hash_table(void){ int a,b; for (a=0;a<X_HASH_TABLE_SIZE;a++) { for (b=0;b<x_hash_table[a].count;b++) mem_free(x_hash_table[a].pointer[b]); if (x_hash_table[a].pointer) mem_free(x_hash_table[a].pointer); }}/* returns graphics device structure which belonging to the window */static struct graphics_device * x_find_gd(Window *win){ int a,b; a=(*win)&(X_HASH_TABLE_SIZE-1); if (!x_hash_table[a].count)return 0; for (b=0;b<x_hash_table[a].count;b++) { if ((*(Window*)((x_hash_table[a].pointer[b])->driver_data))==(*win)) return x_hash_table[a].pointer[b]; } return 0;}static void x_update_driver_param(int w, int h){ int l=0; if (n_wins!=1)return; x_default_window_width=w; x_default_window_height=h; if (x_driver_param)mem_free(x_driver_param); x_driver_param=init_str(); add_num_to_str(&x_driver_param,&l,x_default_window_width); add_to_str(&x_driver_param,&l,"x"); add_num_to_str(&x_driver_param,&l,x_default_window_height);}/* adds graphics device to hash table */static int x_add_to_table(struct graphics_device* gd){ int a=(*((Window*)(gd->driver_data)))&(X_HASH_TABLE_SIZE-1); int c=x_hash_table[a].count; if (!c) { x_hash_table[a].pointer=mem_alloc(sizeof(struct graphics_device *)); } else { if ((unsigned)c > MAXINT / sizeof(struct graphics_device *) - 1) overalloc(); x_hash_table[a].pointer=mem_realloc(x_hash_table[a].pointer,(c+1)*sizeof(struct graphics_device *)); } x_hash_table[a].pointer[c]=gd; x_hash_table[a].count++; return 0;}/* removes graphics device from table */static void x_remove_from_table(Window *win){ int a=(*win)&(X_HASH_TABLE_SIZE-1); int b; for (b=0;b<x_hash_table[a].count;b++) if ((*(Window*)((x_hash_table[a].pointer[b])->driver_data))==(*win)) { memmove(x_hash_table[a].pointer+b,x_hash_table[a].pointer+b+1,(x_hash_table[a].count-b-1)*sizeof(struct graphics_device *)); x_hash_table[a].count--; x_hash_table[a].pointer=mem_realloc(x_hash_table[a].pointer,x_hash_table[a].count*sizeof(struct graphics_device*)); }}void x_clear_clipboard(void){ if(x_my_clipboard) { mem_free(x_my_clipboard); x_my_clipboard=NULL; }}static void x_process_events(void *data){ XEvent event; XEvent last_event; struct graphics_device *gd; int last_was_mouse; int replay_event = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -