/* Clementine Window Manager Copyright 2002 Dave Berton based on aewm Copyright 1998-2001 Decklin Foster This program is free software; see LICENSE for details. */ #include "windowsystem.h" #include "painter.h" #include "keys.h" #include "look.h" #include #include #include #include #include #include #include #include #include #include #define DEF_PAD 3 // ## db more : get rid of these #define ChildMask (SubstructureRedirectMask|SubstructureNotifyMask) #define ButtonMask (ButtonPressMask|ButtonReleaseMask) #define MouseMask (ButtonMask|PointerMotionMask) #include #include std::string convertToString(int x) { std::ostringstream o; if (o << x) return o.str(); // db more some sort of error handling goes here... return "string conversion error"; } int handle_xerror(Display *dpy, XErrorEvent *e) { // if ( !windowManager ) { char msg[255]; XGetErrorText(dpy, e->error_code, msg, sizeof msg); std::cerr<<"X error:" + std::string(msg) << std::endl;//e->resourceid //db more dump core // std::cout << ((std::string*)0)->size(); exit(1); // } // windowManager->handleXerror( e ); // return 0; } void quit_nicely(void) { printf("quit_nicely\n"); // if ( !windowManager ) { // std::cerr << "internal error, exiting" << std::endl; exit(1); // } // windowManager->setQuitting( true ); // force graceful exit // windowManager->flush(); } void sig_handler(int signal) { switch (signal) { case SIGINT: case SIGTERM: case SIGHUP: quit_nicely(); break; case SIGCHLD: wait(NULL); break; } } WindowSystem::WindowSystem() { struct sigaction act; act.sa_handler = sig_handler; act.sa_flags = 0; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGCHLD, &act, NULL); opt_pad = DEF_PAD; quit = false; XSetWindowAttributes sattr; dpy = XOpenDisplay(NULL); if (!dpy) { err("can't open display '??' (is $DISPLAY set properly?)"); // ,getenv("DISPLAY")); exit(1); } XSetErrorHandler(handle_xerror); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wm_state = XInternAtom(dpy, "WM_STATE", False); wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); move_curs = XCreateFontCursor(dpy, XC_fleur); resize_curs = XCreateFontCursor(dpy, XC_sizing); arrow_curs = XCreateFontCursor(dpy, XC_left_ptr); paint = new Painter( dpy, root, screen ); keys = new Keys(); sattr.cursor = arrow_curs; sattr.event_mask = ChildMask|ColormapChangeMask|KeyPressMask|ButtonMask; XChangeWindowAttributes(dpy, root, CWCursor|CWEventMask, &sattr); /* Window cycling */ XGrabKey( dpy, XKeysymToKeycode(dpy, XK_Tab), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey( dpy, XKeysymToKeycode(dpy, XK_Tab), ( Mod1Mask | ShiftMask ), root, True, GrabModeAsync, GrabModeAsync); XGrabKey( dpy, XKeysymToKeycode(dpy, XK_Tab), ControlMask, root, True, GrabModeAsync, GrabModeAsync); XGrabKey( dpy, XKeysymToKeycode(dpy, XK_Tab), ( ControlMask | ShiftMask ), root, True, GrabModeAsync, GrabModeAsync); } WindowSystem::~WindowSystem() { shutdown(); } void WindowSystem::shutdown() { #ifdef DEBUG std::cout << "WindowSystem shutting down" << std::endl; #endif delete paint; delete keys; XFreeCursor(dpy, move_curs); XFreeCursor(dpy, resize_curs); XFreeCursor(dpy, arrow_curs); XInstallColormap(dpy, DefaultColormap(dpy, screen)); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XCloseDisplay(dpy); } void WindowSystem::scanWindows() { unsigned int nwins, i; Window dummyw1, dummyw2, *wins; XWindowAttributes attr; XQueryTree(dpy, root, &dummyw1, &dummyw2, &wins, &nwins); for (i = 0; i < nwins; i++) { XGetWindowAttributes(dpy, wins[i], &attr); if (!attr.override_redirect && attr.map_state == IsViewable) { newWindow( wins[i], true, attr.x, attr.y, attr.width, attr.height, attr.colormap ); } } XFree(wins); } std::string WindowSystem::windowName( Window w ) { char* n; if ( XFetchName(dpy, w, &n) ) { std::string name( n ); XFree(n); return name; } return std::string(); } /* creates a window parented to the root window */ Window WindowSystem::createFrame( int x, int y, unsigned int width, unsigned int height ) { XSetWindowAttributes pattr; pattr.override_redirect = True; pattr.background_pixel = BlackPixel( dpy, screen ); // pattr.border_pixel = BlackPixel( dpy, screen ); pattr.event_mask = ChildMask|ButtonPressMask|ButtonReleaseMask| ExposureMask|EnterWindowMask|KeyPressMask; return XCreateWindow(dpy, root, x, y, width, height, 0, /* border width */ DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWBackPixel| /*CWBorderPixel|*/CWEventMask, &pattr); } /* creates a window parented to the root window */ Window WindowSystem::createWindow( int x, int y, unsigned int width, unsigned int height ) { XSetWindowAttributes pattr; pattr.override_redirect = True; pattr.event_mask = ChildMask|ButtonPressMask|ButtonReleaseMask| ExposureMask|EnterWindowMask|KeyPressMask; Window w = XCreateWindow(dpy, root, x, y, width, height, 0, /* border width */ DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|CWEventMask, &pattr); setBackPixmapParentRelative( w ); return w; } void WindowSystem::setBackPixmapParentRelative( Window w ) { // XSetWindowAttributes sattr; // sattr.background_pixmap = ParentRelative; // XChangeWindowAttributes(dpy, w, CWBackPixmap, &sattr); XSetWindowBackgroundPixmap( dpy, w, None ); XClearWindow( dpy, w ); } Window WindowSystem::createMenu() { XSetWindowAttributes pattr; pattr.override_redirect = True; //pattr.background_pixel = painter()->backgroundColor().pixel; pattr.border_pixel = BlackPixel( dpy, screen ); pattr.event_mask = ChildMask|ButtonPressMask|ButtonMotionMask| ExposureMask|EnterWindowMask|PointerMotionMask; return XCreateWindow(dpy, root, 0, 0, 1, 1, 0, /* border width */ DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect|/*CWBackPixel|*/ CWBorderPixel|CWEventMask, &pattr); } bool WindowSystem::grabPointer( Cursor c ) { return XGrabPointer(dpy, root, False, MouseMask, GrabModeAsync, GrabModeAsync, None, c, CurrentTime) == GrabSuccess; } void WindowSystem::ungrabPointer() { XUngrabPointer(dpy, CurrentTime); } void WindowSystem::waitForMouse( XEvent* ev ) { XMaskEvent(dpy, MouseMask, ev); } void WindowSystem::handleXerror( XErrorEvent *e) { err("encountered X error, bailing"); exit(1); /* Client *c = findClient(e->resourceid, WINDOW); if (e->error_code == BadAccess && e->resourceid == root) { err("root window unavailible (maybe another wm is running?)"); exit(1); } else { char msg[255]; XGetErrorText(dpy, e->error_code, msg, sizeof msg); err("X error:" + std::string(msg));//e->resourceid } if (c) remove(c, WITHDRAW); */ } int WindowSystem::sendDeleteMessage( Window w) { XEvent e; e.type = ClientMessage; e.xclient.window = w; e.xclient.message_type = wm_protos; e.xclient.format = 32; e.xclient.data.l[0] = wm_delete; e.xclient.data.l[1] = CurrentTime; return XSendEvent(dpy, w, False, NoEventMask, &e); } void WindowSystem::tryDelete( Window w ) { int i, n, found = 0; Atom *protocols; if ( getProtocols(w, &protocols, &n) ) { for (i=0; iname : "(none)"); // err( convertToString(w) + std::string(":") + std::string( buf ) + // std::string(":") + std::string( s ) ); err( convertToString(w) + std::string(":") + std::string(":") + std::string( s ) ); } #endif void WindowSystem::err( std::string e ) { std::cerr << e << std::endl; } void WindowSystem::eventLoop() { scanWindows(); XEvent ev; for (;;) { XNextEvent(dpy, &ev); if ( quit ) break; #ifdef DEBUG showEvent(ev); #endif switch (ev.type) { case ButtonPress: handleButtonPress(&ev.xbutton); break; case ButtonRelease: handleButtonRelease(&ev.xbutton); break; case ConfigureRequest: handleConfigure(&ev.xconfigurerequest); break; case MapRequest: handleMap(&ev.xmaprequest); break; case UnmapNotify: handleUnmap(&ev.xunmap); break; case KeyPress: handleKeyPress(&ev.xkey); break; case DestroyNotify: handleDestroy(&ev.xdestroywindow); break; case ClientMessage: handleClientMessage(&ev.xclient); break; case ColormapNotify: handleColormapChange(&ev.xcolormap); break; case PropertyNotify: handlePropertyChange(&ev.xproperty); break; case EnterNotify: handleEnter(&ev.xcrossing); break; case Expose: handleExpose(&ev.xexpose); break; case MotionNotify: handleMotion(&ev.xmotion); break; } } } void WindowSystem::handleButtonPress(XButtonEvent *e) { unsigned int button = 0; switch (e->button) { case Button1: button = 1; break; case Button2: button = 2; break; case Button3: button = 3; break; } if (e->window == root) takeRootButton( button, e->state & Mod1Mask, e->x, e->y ); else takeButtonPress( e->window, button, e->state & Mod1Mask, e->x, e->y ); } void WindowSystem::handleButtonRelease(XButtonEvent *e) { unsigned int button = 0; switch (e->button) { case Button1: button = 1; break; case Button2: button = 2; break; case Button3: button = 3; break; } if (e->window != root) takeButtonRelease( e->window, button, e->state & Mod1Mask, e->x, e->y ); } void WindowSystem::configure( Window w, int x, int y, int width, int height, unsigned int valuemask, Window sibling, int stack_mode) { XWindowChanges wc; wc.x = x; wc.y = y; wc.width = width; wc.height = height; wc.border_width = 0; wc.sibling = sibling; wc.stack_mode = stack_mode; XConfigureWindow(dpy, w, valuemask, &wc); } void WindowSystem::handleConfigure(XConfigureRequestEvent *e) { int x, y, width, height; x = y = width = height = 0; Window sibling; int stack_mode; if (e->value_mask & CWX) x = e->x; if (e->value_mask & CWY) y = e->y; if (e->value_mask & CWWidth) width = e->width; if (e->value_mask & CWHeight) height = e->height; sibling = e->above; stack_mode = e->detail; takeConfigureRequest( e->window, x, y, width, height, e->value_mask, sibling, stack_mode ); } void WindowSystem::handleMap(XMapRequestEvent *e) { XWindowAttributes attr; XGetWindowAttributes(dpy, e->window, &attr); //## db more fix this mess if (!attr.override_redirect && !managedWindow(e->window) ) { newWindow(e->window, (attr.map_state == IsViewable), attr.x, attr.y, attr.width, attr.height, attr.colormap); } else { takeMap( e->window ); } } void WindowSystem::handleUnmap(XUnmapEvent *e) { takeUnmap( e->window ); } void WindowSystem::handleDestroy(XDestroyWindowEvent *e) { takeDestroy( e->window ); } void WindowSystem::handleClientMessage(XClientMessageEvent *e) { if ( e->message_type == wm_change_state && e->format == 32 && e->data.l[0] == IconicState ) { iconize( e->window ); } } void WindowSystem::handlePropertyChange(XPropertyEvent *e) { switch (e->atom) { case XA_WM_NAME: { char* n; XFetchName(dpy, e->window, &n); std::string newName( n ); XFree( n ); takeNameChange( e->window, newName ); break; } case XA_WM_NORMAL_HINTS: // db more err("XA_WM_NORMAL_HINTS not handled"); //XGetWMNormalHints(dpy, c->window, c->size, &dummy); } } void WindowSystem::handleEnter(XCrossingEvent *e) { takeFocus( e->window ); } void WindowSystem::handleColormapChange(XColormapEvent *e) { if ( e->c_new ) takeNewColormap( e->window, e->colormap ); } void WindowSystem::handleExpose(XExposeEvent *e) { if (e->count == 0) takeExpose( e->window ); } void WindowSystem::handleMotion(XMotionEvent *e) { takeMotion( e->window, e->x, e->y ); } void WindowSystem::handleKeyPress(XKeyEvent *e) { takeKeyPress( e->window, e->state, XKeycodeToKeysym( dpy, e->keycode, 0) ); }