#include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "WinBase.h" char *def_geom_string = NULL; char *def_fg_string = DEFAULT_FORECOLOR; char *def_bg_string = DEFAULT_BACKCOLOR; char *def_font = DEFAULT_FONT; char *def_bw = DEFAULT_BEVEL; char *def_resname = "XThing"; char *def_display = NULL; char **orig_argv = NULL; int orig_argc = 0; /************************************************************************ * ReapChildren - wait() for all dead child processes ************************************************************************/ #include #ifdef HAVE_WAITPID #define ReapChildren() while ((waitpid(-1, NULL, WNOHANG)) > 0); #else #define ReapChildren() while ((wait3(NULL, WNOHANG, NULL)) > 0); #endif int GetFdWidth(void) { #ifdef HAVE_SYSCONF return sysconf(_SC_OPEN_MAX); #else return getdtablesize(); #endif } int My_XNextEvent(Display *dpy, XEvent *event); static int MyXAllocColor(Display *dpy,Colormap cmap,int screen, XColor *color); /************************************************************************** * * Standard options * *************************************************************************/ struct res_list { char **dataptr; char *keyword; }; struct res_list string_resource_list[] = { {&def_geom_string, "geometry"}, {&def_geom_string, "geom"}, {&def_fg_string, "foreground"}, {&def_fg_string, "fg"}, {&def_bg_string, "background"}, {&def_bg_string, "bg"}, {&def_font, "font"}, {&def_bw, "bevelwidth"}, {&def_bw, "bw"}, {0, NULL} }; /*************************************************************************** * * Declarations for static members of WinBase * ***************************************************************************/ Display *WinBase::dpy = 0; Window WinBase::Root = None; int WinBase::Screen; GC WinBase::DefaultReliefGC; GC WinBase::DefaultShadowGC; GC WinBase::DefaultForeGC; XFontStruct *WinBase::DefaultFont; Pixel WinBase::DefaultBackColor; Pixel WinBase::DefaultReliefColor; Pixel WinBase::DefaultShadowColor; Pixel WinBase::DefaultForeColor; Colormap WinBase::cmap; static Atom wm_del_win; static int fd_width; static int x_fd; struct iodesc { int fd; void (*func)(int); }; struct iodesc *wininputdesc; struct iodesc *winoutputdesc; static int wininputcount; static int winoutputcount; void WinInitialize(char **argv, int argc) { int i = 0,j,done; char *tmp; orig_argv = argv; orig_argc = argc; for(i=1;iwin; x = x_loc; y = y_loc; w = width; h = height; if(Parent == NULL) { BackColor = DefaultBackColor; ForeColor = DefaultForeColor; ReliefColor = DefaultReliefColor; ShadowColor = DefaultShadowColor; bw = atoi(def_bw); } else { BackColor = Parent->BackColor; ForeColor = Parent->ForeColor; ReliefColor = Parent->ReliefColor; ShadowColor = Parent->ShadowColor; bw = Parent->bw; } popped_out = 1; name_set = 0; icon_name_set = 0; CloseWindowAction = NULL; mask = CWBackPixel | CWEventMask; attributes.background_pixel = BackColor; attributes.event_mask = ButtonPressMask|ButtonReleaseMask|ExposureMask|KeyPressMask| StructureNotifyMask; win = XCreateWindow(dpy,pwindow,x_loc,y_loc,width,height,0, CopyFromParent,InputOutput,CopyFromParent, mask,&attributes); if(create_defaults) { DefaultFont = XLoadQueryFont(dpy, def_font); if(DefaultFont == NULL) { cerr <<"Can't load font "<fid; gcv.plane_mask = AllPlanes; gcv.graphics_exposures = False; gcv.foreground = DefaultReliefColor; DefaultReliefGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = DefaultShadowColor; DefaultShadowGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = DefaultForeColor; DefaultForeGC = XCreateGC(dpy,win,mask,&gcv); } if(Parent == NULL) { XClassHint classhints; XWMHints wmhints; XSizeHints normal_hints; XTextProperty name; main_window = this; ReliefGC = DefaultReliefGC; ShadowGC = DefaultShadowGC; ForeGC = DefaultForeGC; Font = DefaultFont; normal_hints.flags = PWinGravity|PMinSize|PResizeInc; normal_hints.width_inc = 1; normal_hints.height_inc = 1; normal_hints.min_width = 1; normal_hints.min_height = 1; normal_hints.win_gravity = NorthWestGravity; wmhints.input = True; wmhints.initial_state = NormalState; wmhints.flags = InputHint|StateHint; classhints.res_name = def_resname; classhints.res_class = def_resname; if (XStringListToTextProperty(&def_resname,1,&name) == 0) { cerr <<"cannot allocate window name"; return; } XSetWMProperties(dpy,win, &name, &name,orig_argv, orig_argc, &normal_hints,&wmhints,&classhints); } else { main_window = Parent->main_window; mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth| GCForeground|GCBackground| GCFont; if(Parent->ReliefGC == DefaultReliefGC) ReliefGC = DefaultReliefGC; else { XGetGCValues(dpy,Parent->ReliefGC,mask,&gcv); ReliefGC = XCreateGC(dpy,win,mask,&gcv); } if(Parent->ShadowGC == DefaultShadowGC) ShadowGC = DefaultShadowGC; else { XGetGCValues(dpy,Parent->ShadowGC,mask,&gcv); ShadowGC = XCreateGC(dpy,win,mask,&gcv); } if(Parent->ForeGC == DefaultForeGC) ForeGC = DefaultForeGC; else { XGetGCValues(dpy,Parent->ForeGC,mask,&gcv); ForeGC = XCreateGC(dpy,win,mask,&gcv); } Font = Parent->DefaultFont; } RegisterWindow(win,this); if(wm_del_win == 0) wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False); XSetWMProtocols(dpy,win,&wm_del_win,1); } WinBase::~WinBase() { XDestroyWindow(dpy,win); UnregisterWindow(this); } void WinBase::Map() { XMapSubwindows(dpy,win); XMapRaised(dpy,win); XSync(dpy,0); } void WinBase::RedrawWindow(int clear) { if(clear) XClearWindow(dpy,win); DrawCallback(NULL); } void WinBase::DrawCallback(XEvent *event) { int i; GC gc1; GC gc2; if((!event)||(event->xexpose.count == 0)) { if(popped_out) { gc1 = ShadowGC; gc2 = ReliefGC; } else { gc2 = ShadowGC; gc1 = ReliefGC; } for(i=0;ifid; gcv.graphics_exposures = False; gcv.foreground = ReliefColor; ReliefGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = ShadowColor; ShadowGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = ForeColor; ForeGC = XCreateGC(dpy,win,mask,&gcv); mask = CWBackPixel; attributes.background_pixel = BackColor; XChangeWindowAttributes(dpy,win, mask,&attributes); XClearWindow(dpy,win); } void WinBase::SetBevelWidth(int new_bw) { bw = new_bw; } void WinBase::PushIn() { popped_out = 0; } void WinBase::PopOut() { popped_out = 1; } void WinBase::MakeTransient(WinBase *TransientFor) { XSetTransientForHint(dpy,win,TransientFor->win); } void WinBase::SetForeColor(char *newcolor = DEFAULT_FORECOLOR) { XGCValues gcv; unsigned long mask; ForeColor = GetColor(newcolor,dpy,cmap,Screen); if(ForeColor == 0xffffffff) ForeColor = DefaultForeColor; if(ForeGC!= DefaultForeGC) XFreeGC(dpy,ShadowGC); mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth| GCForeground|GCBackground|GCFont; gcv.background = BackColor; gcv.line_width = 0; gcv.function = GXcopy; gcv.plane_mask = AllPlanes; gcv.graphics_exposures = False; gcv.foreground = DefaultForeColor; gcv.font = Font->fid; ForeGC = XCreateGC(dpy,win,mask,&gcv); } void WinBase::SetFont(char *newfont=DEFAULT_FONT) { XGCValues gcv; unsigned long mask; Font = XLoadQueryFont(dpy, newfont); if(Font == NULL) Font = DefaultFont; if(ForeGC != DefaultForeGC) { XFreeGC(dpy,ForeGC); } if(ShadowGC != DefaultShadowGC) { XFreeGC(dpy,ShadowGC); } if(ReliefGC != DefaultReliefGC) { XFreeGC(dpy,ReliefGC); } mask = GCFunction|GCPlaneMask|GCGraphicsExposures|GCLineWidth| GCForeground|GCBackground|GCFont; gcv.background = BackColor; gcv.line_width = 0; gcv.function = GXcopy; gcv.plane_mask = AllPlanes; gcv.font = Font->fid; gcv.graphics_exposures = False; gcv.foreground = ReliefColor; ReliefGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = ShadowColor; ShadowGC = XCreateGC(dpy,win,mask,&gcv); gcv.foreground = ForeColor; ForeGC = XCreateGC(dpy,win,mask,&gcv); } void WinBase::SetWindowName(char *new_name) { XTextProperty name; if (XStringListToTextProperty(&new_name,1,&name) == 0) { cerr <<"cannot allocate window name"; return; } XSetWMName(dpy,win,&name); XFree(name.value); if(icon_name_set == 0) { SetIconName(new_name); icon_name_set = 0; } name_set = 1; } void WinBase::SetIconName(char *new_name) { XTextProperty name; if (XStringListToTextProperty(&new_name,1,&name) == 0) { cerr<<"cannot allocate icon name"; return; } XSetWMIconName(dpy,win,&name); XFree(name.value); icon_name_set = 1; } void WinBase::SetWindowClass(char *resclass) { XClassHint class_hint; class_hint.res_name = def_resname; class_hint.res_class = resclass; XSetClassHint(dpy,win,&class_hint); } /**************************************************************************** * * This routine computes the shadow color from the background color * ****************************************************************************/ Pixel GetShadow(Pixel background, Display *dpy, int Screen, Colormap cmap) { XColor bg_color, white_p; bg_color.pixel = background; XQueryColor(dpy,cmap,&bg_color); white_p.pixel = WhitePixel(dpy,Screen); XQueryColor(dpy,cmap,&white_p); if((bg_color.red < white_p.red/5)&& (bg_color.green < white_p.green/5)&& (bg_color.blue < white_p.blue/5)) { bg_color.red = white_p.red/4; bg_color.green = white_p.green/4; bg_color.blue = white_p.blue/4; } else { bg_color.red = (bg_color.red*50)/100; bg_color.green = (bg_color.green*50)/100; bg_color.blue = (bg_color.blue*50)/100; } if(!MyXAllocColor(dpy,cmap,Screen,&bg_color)) { cout <<"Can't allocate shadow color\n"; bg_color.pixel = BlackPixel(dpy,Screen); } return bg_color.pixel; } /**************************************************************************** * * This routine computes the hilight color from the background color * ****************************************************************************/ Pixel GetHilite(Pixel background, Display *dpy, int Screen, Colormap cmap) { XColor bg_color, white_p; int r,g,b; bg_color.pixel = background; XQueryColor(dpy,cmap,&bg_color); white_p.pixel = WhitePixel(dpy,Screen); XQueryColor(dpy,cmap,&white_p); if((bg_color.red > 2*white_p.red/3)&& (bg_color.green > 2*white_p.green/3)&& (bg_color.blue > 2*white_p.blue/3)) { r = white_p.red*3/4; g = white_p.green*3/4; b = white_p.blue*3/4; } else { r = bg_color.red + (white_p.red - bg_color.red)/2; g = bg_color.green + (white_p.green - bg_color.green)/2; b = bg_color.blue + (white_p.blue - bg_color.blue)/2; } if(r > white_p.red) bg_color.red = white_p.red; else bg_color.red = r; if(g > white_p.green) bg_color.green = white_p.green; else bg_color.green = g; if(b > white_p.blue) bg_color.blue = white_p.blue; else bg_color.blue = b; if(!MyXAllocColor(dpy,cmap,Screen,&bg_color)) { cout <<"Can't allocate highlight color\n"; bg_color.pixel = WhitePixel(dpy,Screen);; } return bg_color.pixel; } /**************************************************************************** * * Loads a single color * ****************************************************************************/ Pixel GetColor(char *name, Display *dpy, Colormap cmap, int Screen) { XColor color; color.pixel = 0xffffffff; if (!XParseColor (dpy, cmap, name, &color)) { cerr<< "Can't parse color "<red- allcolors[i].red; bdist = color->blue- allcolors[i].blue; gdist = color->green- allcolors[i].green; distance = rdist*rdist+bdist*bdist+gdist*gdist; if(distance < bestdistance) { bestdistance = distance; bestpixel = i; } } color->red = allcolors[bestpixel].red; color->green = allcolors[bestpixel].green; color->blue = allcolors[bestpixel].blue; if(XAllocColor (dpy, cmap, color)) return 1; else return 0; } struct registered { Window win; WinBase *thing; int occupied; }; static struct registered thinglist[100]; void RegisterWindow(Window win, WinBase *a) { static int firsttime = 1; int i; if(firsttime) { firsttime = 0; for(i=0;i<100;i++) { thinglist[i].occupied = 0; } } for(i=0;i<100;i++) { if(thinglist[i].occupied == 0) { thinglist[i].occupied = 1; thinglist[i].win = win; thinglist[i].thing = a; return; } } cout <<"Too many windows\n"; exit(-1); } void UnregisterWindow(WinBase *thing) { int i; for(i=0;i<100;i++) { if((thinglist[i].occupied ==1)&& (thinglist[i].thing == thing)) { thinglist[i].occupied = 0; return; } } } void WinLoop() { XEvent event; int i; Display *dpy; i=0; while((thinglist[i].occupied == 0)&&(i<100)) { i++; } if(i<100) dpy = thinglist[i].thing->dpy; else return; while(!My_XNextEvent(dpy,&event)); for(i=0;i<100;i++) { if((thinglist[i].occupied)&&(event.xany.window == thinglist[i].win)) { switch(event.type) { case Expose: case GraphicsExpose: thinglist[i].thing->DrawCallback(&event); break; case ButtonPress: thinglist[i].thing->BPressCallback(&event); break; case ButtonRelease: thinglist[i].thing->BReleaseCallback(&event); break; case KeyPress: thinglist[i].thing->KPressCallback(&event); break; case ConfigureNotify: if((thinglist[i].thing->w!= event.xconfigure.width)|| (thinglist[i].thing->h!= event.xconfigure.height)) thinglist[i].thing->ResizeCallback(event.xconfigure.width, event.xconfigure.height,&event); break; case ClientMessage: if (event.xclient.format == 32 && event.xclient.data.l[0] == wm_del_win) { if(thinglist[i].thing->CloseWindowAction == NULL) exit(0); else thinglist[i].thing->CloseWindowAction(thinglist[i].thing); } break; case MotionNotify: thinglist[i].thing->MotionCallback(&event); break; default: break; } return; } } } /*************************************************************************** * * Waits for next X event, or for an auto-raise timeout. * ****************************************************************************/ int My_XNextEvent(Display *dpy, XEvent *event) { fd_set in_fdset,out_fdset; Window child; Window targetWindow; int i,count; int retval; FD_ZERO(&in_fdset); FD_SET(x_fd,&in_fdset); FD_ZERO(&out_fdset); for(i=0; i= 0)&&(FD_ISSET(wininputdesc[i].fd, &in_fdset))) { wininputdesc[i].func(wininputdesc[i].fd); } if((winoutputdesc[i].fd>=0)&&(FD_ISSET(winoutputdesc[i].fd, &out_fdset))) { winoutputdesc[i].func(winoutputdesc[i].fd); } } return 0; }