flwm-1.02+cvs20080422/0000755000175000017500000000000011003424123011564 5ustar memeflwm-1.02+cvs20080422/Desktop.C0000644000175000017500000000744507040736155013334 0ustar meme// Desktop.C #include "config.h" #if DESKTOPS #include "Frame.H" #include "Desktop.H" #include #include #include Desktop* Desktop::current_ = 0; Desktop* Desktop::first = 0; // return the highest desktop number: int Desktop::max_number() { int n = 0; for (Desktop* d = first; d; d = d->next) if (d->number_ > n) n = d->number_; return n; } // return an empty slot number: int Desktop::available_number() { int n = 1; for (Desktop* d = first; d;) { if (d->number_ == n) {n++; d = first;} else d = d->next; } return n; } // these are set by main.C: Atom _win_workspace; Atom _win_workspace_count; Atom _win_workspace_names; #ifndef __sgi static Atom kwm_current_desktop; #endif extern Fl_Window* Root; static int dont_send; static void send_desktops() { if (dont_send) return; int n = Desktop::max_number(); setProperty(fl_xid(Root), _win_workspace_count, XA_CARDINAL, n); char buffer[1025]; char* p = buffer; for (int i = 1; i <= n; i++) { Desktop* d = Desktop::number(i); const char* name = d ? d->name() : ""; while (p < buffer+1024 && *name) *p++ = *name++; *p++ = 0; if (p >= buffer+1024) break; } XChangeProperty(fl_display, fl_xid(Root), _win_workspace_names, XA_STRING, 8, PropModeReplace, (unsigned char *)buffer, p-buffer-1); } Desktop::Desktop(const char* n, int num) { next = first; first = this; name_ = strdup(n); number_ = num; send_desktops(); } Desktop::~Desktop() { // remove from list: for (Desktop** p = &first; *p; p = &((*p)->next)) if (*p == this) {*p = next; break;} send_desktops(); if (current_ == this || !first->next) current(first); // put any clients onto another desktop: for (Frame* c = Frame::first; c; c = c->next) if (c->desktop() == this) c->desktop(first); free((void*)name_); } void Desktop::name(const char* l) { free((void*)name_); name_ = strdup(l); } void Desktop::current(Desktop* n) { if (n == current_) return; current_ = n; for (Frame* c = Frame::first; c; c = c->next) { if (c->desktop() == n) { if (c->state() == OTHER_DESKTOP) c->state(NORMAL); } else if (c->desktop()) { if (c->state() == NORMAL) c->state(OTHER_DESKTOP); } } if (n && !dont_send) { #ifndef __sgi setProperty(fl_xid(Root), kwm_current_desktop, kwm_current_desktop, n->number()); #endif setProperty(fl_xid(Root), _win_workspace, XA_CARDINAL, n->number()-1); } } // return desktop with given number, create it if necessary: Desktop* Desktop::number(int n, int create) { if (!n) return 0; Desktop* d; for (d = first; d; d = d->next) if (d->number() == n) return d; if (create) { char buf[20]; sprintf(buf, "Desktop %d", n); d = new Desktop(buf,n); } return d; } // called at startup, read the list of desktops from the root // window properties, or on failure make some default desktops. void init_desktops() { dont_send = 1; int length; char* buffer = (char*)getProperty(fl_xid(Root), _win_workspace_names, XA_STRING, &length); if (buffer) { char* c = buffer; for (int i = 1; c < buffer+length; i++) { char* d = c; while (*d) d++; if (*c != '<') new Desktop(c,i); c = d+1; } XFree(buffer); } int current_num = 0; int p = getIntProperty(fl_xid(Root), _win_workspace, XA_CARDINAL, -1); if (p >= 0 && p < 25) current_num = p+1; #ifndef __sgi // SGI's Xlib barfs when you try to do this XInternAtom! // Maybe somebody there does not like KDE? kwm_current_desktop = XInternAtom(fl_display, "KWM_CURRENT_DESKTOP", 0); if (!current_num) { p = getIntProperty(fl_xid(Root), kwm_current_desktop, kwm_current_desktop); if (p > 0 && p < 25) current_num = p; } #endif if (!current_num) current_num = 1; Desktop::current(Desktop::number(current_num, 1)); dont_send = 0; } #endif flwm-1.02+cvs20080422/Desktop.H0000644000175000017500000000103307040736155013324 0ustar meme// Desktop.H class Desktop { const char* name_; int number_; static Desktop* current_; public: static Desktop* first; Desktop* next; const char* name() const {return name_;} void name(const char*); int number() const {return number_;} static Desktop* current() {return current_;} static Desktop* number(int, int create = 0); static void current(Desktop*); static int available_number(); static int max_number(); Desktop(const char*, int); ~Desktop(); int junk; // for temporary storage by menu builder }; flwm-1.02+cvs20080422/Frame.C0000644000175000017500000015724110654364646012764 0ustar meme// Frame.C #include "config.h" #include "Frame.H" #include "Desktop.H" #include #include #include #include "Rotated.H" static Atom wm_state = 0; static Atom wm_change_state; static Atom wm_protocols; static Atom wm_delete_window; static Atom wm_take_focus; static Atom wm_save_yourself; static Atom wm_colormap_windows; static Atom _motif_wm_hints; static Atom kwm_win_decoration; #if DESKTOPS static Atom kwm_win_desktop; static Atom kwm_win_sticky; #endif //static Atom wm_client_leader; static Atom _wm_quit_app; // these are set by initialize in main.C: Atom _win_hints; Atom _win_state; #if DESKTOPS extern Atom _win_workspace; #endif #ifdef SHOW_CLOCK extern char clock_buf[]; extern int clock_alarm_on; #endif static const int XEventMask = ExposureMask|StructureNotifyMask |KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask |ButtonPressMask|ButtonReleaseMask |EnterWindowMask|LeaveWindowMask |PointerMotionMask|SubstructureRedirectMask|SubstructureNotifyMask; extern Fl_Window* Root; Frame* Frame::active_; Frame* Frame::first; static inline int max(int a, int b) {return a > b ? a : b;} static inline int min(int a, int b) {return a < b ? a : b;} //////////////////////////////////////////////////////////////// // The constructor is by far the most complex part, as it collects // all the scattered pieces of information about the window that // X has and uses them to initialize the structure, position the // window, and then finally create it. int dont_set_event_mask = 0; // used by FrameWindow // "existing" is a pointer to an XWindowAttributes structure that is // passed for an already-existing window when the window manager is // starting up. If so we don't want to alter the state, size, or // position. If null than this is a MapRequest of a new window. Frame::Frame(XWindow window, XWindowAttributes* existing) : Fl_Window(0,0), window_(window), state_flags_(0), flags_(0), transient_for_xid(None), transient_for_(0), revert_to(active_), colormapWinCount(0), close_button(BUTTON_LEFT,BUTTON_TOP,BUTTON_W,BUTTON_H,"X"), iconize_button(BUTTON_LEFT,BUTTON_TOP,BUTTON_W,BUTTON_H,"i"), max_h_button(BUTTON_LEFT,BUTTON_TOP+3*BUTTON_H,BUTTON_W,BUTTON_H,"h"), max_w_button(BUTTON_LEFT,BUTTON_TOP+BUTTON_H,BUTTON_W,BUTTON_H,"w"), min_w_button(BUTTON_LEFT,BUTTON_TOP+2*BUTTON_H,BUTTON_W,BUTTON_H,"W") { #if FL_MAJOR_VERSION > 1 clear_double_buffer(); #endif close_button.callback(button_cb_static); iconize_button.callback(button_cb_static); max_h_button.type(FL_TOGGLE_BUTTON); max_h_button.callback(button_cb_static); max_w_button.type(FL_TOGGLE_BUTTON); max_w_button.callback(button_cb_static); min_w_button.type(FL_TOGGLE_BUTTON); min_w_button.callback(button_cb_static); end(); box(FL_NO_BOX); // relies on background color erasing interior labelcolor(FL_FOREGROUND_COLOR); next = first; first = this; // do this asap so we don't miss any events... if (!dont_set_event_mask) XSelectInput(fl_display, window_, ColormapChangeMask | PropertyChangeMask | FocusChangeMask ); if (!wm_state) { // allocate all the atoms if this is the first time wm_state = XInternAtom(fl_display, "WM_STATE", 0); wm_change_state = XInternAtom(fl_display, "WM_CHANGE_STATE", 0); wm_protocols = XInternAtom(fl_display, "WM_PROTOCOLS", 0); wm_delete_window = XInternAtom(fl_display, "WM_DELETE_WINDOW", 0); wm_take_focus = XInternAtom(fl_display, "WM_TAKE_FOCUS", 0); wm_save_yourself = XInternAtom(fl_display, "WM_SAVE_YOURSELF", 0); wm_colormap_windows = XInternAtom(fl_display, "WM_COLORMAP_WINDOWS",0); _motif_wm_hints = XInternAtom(fl_display, "_MOTIF_WM_HINTS", 0); kwm_win_decoration = XInternAtom(fl_display, "KWM_WIN_DECORATION", 0); #if DESKTOPS kwm_win_desktop = XInternAtom(fl_display, "KWM_WIN_DESKTOP", 0); kwm_win_sticky = XInternAtom(fl_display, "KWM_WIN_STICKY", 0); #endif // wm_client_leader = XInternAtom(fl_display, "WM_CLIENT_LEADER", 0); _wm_quit_app = XInternAtom(fl_display, "_WM_QUIT_APP", 0); } label_y = label_h = label_w = 0; getLabel(); // getIconLabel(); {XWindowAttributes attr; if (existing) attr = *existing; else { // put in some legal values in case XGetWindowAttributes fails: attr.x = attr.y = 0; attr.width = attr.height = 100; attr.colormap = fl_colormap; attr.border_width = 0; XGetWindowAttributes(fl_display, window, &attr); } left = top = dwidth = dheight = 0; // pretend border is zero-width for now app_border_width = attr.border_width; x(attr.x+app_border_width); restore_x = x(); y(attr.y+app_border_width); restore_y = y(); w(attr.width); restore_w = w(); h(attr.height); restore_h = h(); colormap = attr.colormap;} getColormaps(); //group_ = 0; {XWMHints* hints = XGetWMHints(fl_display, window_); if (hints) { if ((hints->flags & InputHint) && !hints->input) set_flag(NO_FOCUS); //if (hints && hints->flags&WindowGroupHint) group_ = hints->window_group; } switch (getIntProperty(wm_state, wm_state, 0)) { case NormalState: state_ = NORMAL; break; case IconicState: state_ = ICONIC; break; // X also defines obsolete values ZoomState and InactiveState default: if (hints && (hints->flags&StateHint) && hints->initial_state==IconicState) state_ = ICONIC; else state_ = NORMAL; } if (hints) XFree(hints);} // Maya sets this, seems to mean the same as group: // if (!group_) group_ = getIntProperty(wm_client_leader, XA_WINDOW); XGetTransientForHint(fl_display, window_, &transient_for_xid); getProtocols(); getMotifHints(); // get Gnome hints: int p = getIntProperty(_win_hints, XA_CARDINAL); if (p&1) set_flag(NO_FOCUS); // WIN_HINTS_SKIP_FOCUS // if (p&2) // WIN_HINTS_SKIP_WINLIST // if (p&4) // WIN_HINTS_SKIP_TASKBAR // if (p&8) ... // WIN_HINTS_GROUP_TRANSIENT if (p&16) set_flag(CLICK_TO_FOCUS); // WIN_HINTS_FOCUS_ON_CLICK // get KDE hints: p = getIntProperty(kwm_win_decoration, kwm_win_decoration, 1); if (!(p&3)) set_flag(NO_BORDER); else if (p & 2) set_flag(THIN_BORDER); if (p & 256) set_flag(NO_FOCUS); fix_transient_for(); if (transient_for()) { if (state_ == NORMAL) state_ = transient_for()->state_; #if DESKTOPS desktop_ = transient_for()->desktop_; #endif } #if DESKTOPS // see if anybody thinks window is "sticky:" else if ((getIntProperty(_win_state, XA_CARDINAL) & 1) // WIN_STATE_STICKY || getIntProperty(kwm_win_sticky, kwm_win_sticky)) { desktop_ = 0; } else { // get the desktop from either Gnome or KDE (Gnome takes precedence): p = getIntProperty(_win_workspace, XA_CARDINAL, -1) + 1; // Gnome desktop if (p <= 0) p = getIntProperty(kwm_win_desktop, kwm_win_desktop); if (p > 0 && p < 25) desktop_ = Desktop::number(p, 1); else desktop_ = Desktop::current(); } if (desktop_ && desktop_ != Desktop::current()) if (state_ == NORMAL) state_ = OTHER_DESKTOP; #endif int autoplace = getSizes(); // some Motif programs assumme this will force the size to conform :-( if (w() < min_w || h() < min_h) { if (w() < min_w) w(min_w); if (h() < min_h) h(min_h); XResizeWindow(fl_display, window_, w(), h()); } // try to detect programs that think "transient_for" means "no border": if (transient_for_xid && !label() && !flag(NO_BORDER)) { set_flag(THIN_BORDER); } updateBorder(); show_hide_buttons(); if (autoplace && !existing && !(transient_for() && (x() || y()))) { place_window(); } // move window so contents and border are visible: x(force_x_onscreen(x(), w())); y(force_y_onscreen(y(), h())); // guess some values for the "restore" fields, if already maximized: if (max_w_button.value()) { restore_w = min_w + ((w()-dwidth-min_w)/2/inc_w) * inc_w; restore_x = x()+left + (w()-dwidth-restore_w)/2; } if (max_h_button.value()) { restore_h = min_h + ((h()-dheight-min_h)/2/inc_h) * inc_h; restore_y = y()+top + (h()-dheight-restore_h)/2; } const int mask = CWBorderPixel | CWColormap | CWEventMask | CWBitGravity | CWBackPixel | CWOverrideRedirect; XSetWindowAttributes sattr; sattr.event_mask = XEventMask; sattr.colormap = fl_colormap; sattr.border_pixel = fl_xpixel(FL_GRAY0); sattr.bit_gravity = NorthWestGravity; sattr.override_redirect = 1; sattr.background_pixel = fl_xpixel(FL_GRAY); Fl_X::set_xid(this, XCreateWindow(fl_display, RootWindow(fl_display,fl_screen), x(), y(), w(), h(), 0, fl_visual->depth, InputOutput, fl_visual->visual, mask, &sattr)); setStateProperty(); if (!dont_set_event_mask) XAddToSaveSet(fl_display, window_); if (existing) set_state_flag(IGNORE_UNMAP); XReparentWindow(fl_display, window_, fl_xid(this), left, top); XSetWindowBorderWidth(fl_display, window_, 0); if (state_ == NORMAL) XMapWindow(fl_display, window_); sendConfigureNotify(); // many apps expect this even if window size unchanged #if CLICK_RAISES || CLICK_TO_TYPE if (!dont_set_event_mask) XGrabButton(fl_display, AnyButton, AnyModifier, window, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); #endif if (state_ == NORMAL) { XMapWindow(fl_display, fl_xid(this)); if (!existing) activate_if_transient(); } set_visible(); } #if SMART_PLACEMENT // Helper functions for "smart" window placement. int overlap1(int p1, int l1, int p2, int l2) { int ret = 0; if(p1 <= p2 && p2 <= p1 + l1) { ret = min(p1 + l1 - p2, l2); } else if (p2 <= p1 && p1 <= p2 + l2) { ret = min(p2 + l2 - p1, l1); } return ret; } int overlap(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { return (overlap1(x1, w1, x2, w2) * overlap1(y1, h1, y2, h2)); } // Compute the overlap with existing windows. // For normal windows the overlapping area is taken into account plus a // constant value for every overlapping window. // The active window counts twice. // For iconic windows half the overlapping area is taken into account. int getOverlap(int x, int y, int w, int h, Frame *first, Frame *self) { int ret = 0; short state; for (Frame* f = first; f; f = f->next) { if (f != self) { state = f->state(); if (state == NORMAL || state == ICONIC) { int o = overlap(x, y, w, h, f->x(), f->y(), f->w(), f->h()); if (state == NORMAL) { ret = ret + o + (o>0?40000:0) + (o * f->active()); } else if (state == ICONIC) { ret = ret + o/2; } } } } return ret; } // autoplacement (brute force version for now) void Frame::place_window() { int min_overlap = -1; int tmp_x, tmp_y, tmp_o; int best_x = 0; int best_y = 0; int _w = w(); int _h = h(); int max_x = Root->x() + Root->w(); int max_y = Root->y() + Root->h(); Frame *f1 = Frame::first; for(int i=0;; i++) { if (i==0) { tmp_x = 0; } else if (i==1) { tmp_x = max_x - _w; } else { if (f1 == this) { f1 = f1->next; } if (!f1) { break; } tmp_x = f1->x() + f1->w(); f1 = f1->next; } Frame *f2 = Frame::first; for(int j=0;; j++) { if (j==0) { tmp_y = 0; } else if (j==1) { tmp_y = max_y - _h; } else { if (f2 == this) { f2 = f2->next; } if (!f2) { break; } tmp_y = f2->y() + f2->h(); f2 = f2->next; } if ((tmp_x + _w <= max_x) && (tmp_y + _h <= max_y)) { tmp_o = getOverlap(tmp_x, tmp_y, _w, _h, Frame::first, this); if(tmp_o < min_overlap || min_overlap < 0) { best_x = tmp_x; best_y = tmp_y; min_overlap = tmp_o; if (min_overlap == 0) { break; } } } } if (min_overlap == 0) { break; } } x(best_x); y(best_y); } #else // autoplacement (stupid version for now) void Frame::place_window() { x(Root->x()+(Root->w()-w())/2); y(Root->y()+(Root->h()-h())/2); // move it until it does not hide any existing windows: const int delta = TITLE_WIDTH+LEFT; for (Frame* f = next; f; f = f->next) { if (f->x()+delta > x() && f->y()+delta > y() && f->x()+f->w()-delta < x()+w() && f->y()+f->h()-delta < y()+h()) { x(max(x(),f->x()+delta)); y(max(y(),f->y()+delta)); f = this; } } } #endif // modify the passed X & W to a legal horizontal window position int Frame::force_x_onscreen(int X, int W) { // force all except the black border on-screen: X = min(X, Root->x()+Root->w()+1-W); X = max(X, Root->x()-1); // force the contents on-screen: X = min(X, Root->x()+Root->w()-W+dwidth-left); if (W-dwidth > Root->w() || h()-dheight > Root->h()) // windows bigger than the screen need title bar so they can move X = max(X, Root->x()-LEFT); else X = max(X, Root->x()-left); return X; } // modify the passed Y & H to a legal vertical window position: int Frame::force_y_onscreen(int Y, int H) { // force border (except black edge) to be on-screen: Y = min(Y, Root->y()+Root->h()+1-H); Y = max(Y, Root->y()-1); // force contents to be on-screen: Y = min(Y, Root->y()+Root->h()-H+dheight-top); Y = max(Y, Root->y()-top); return Y; } //////////////////////////////////////////////////////////////// // destructor // The destructor is called on DestroyNotify, so I don't have to do anything // to the contained window, which is already been destroyed. // fltk bug: it does not clear these pointers when window is deleted, // causing flwm to crash on window close sometimes: extern Fl_Window *fl_xfocus; extern Fl_Window *fl_xmousewin; Frame::~Frame() { // It is possible for the frame to be destroyed while the menu is // popped-up, and the menu will still contain a pointer to it. To // fix this the menu checks the state_ location for a legal and // non-withdrawn state value before doing anything. This should // be reliable unless something reallocates the memory and writes // a legal state value to this location: state_ = UNMAPPED; #if FL_MAJOR_VERSION < 2 // fix fltk bug: fl_xfocus = 0; fl_xmousewin = 0; Fl::focus_ = 0; #endif // remove any pointers to this: Frame** cp; for (cp = &first; *cp; cp = &((*cp)->next)) if (*cp == this) {*cp = next; break;} for (Frame* f = first; f; f = f->next) { if (f->transient_for_ == this) f->transient_for_ = transient_for_; if (f->revert_to == this) f->revert_to = revert_to; } throw_focus(1); if (colormapWinCount) { XFree((char *)colormapWindows); delete[] window_Colormaps; } //if (iconlabel()) XFree((char*)iconlabel()); if (label()) XFree((char*)label()); } //////////////////////////////////////////////////////////////// void Frame::getLabel(int del) { char* old = (char*)label(); char* nu = del ? 0 : (char*)getProperty(XA_WM_NAME); if (nu) { // since many window managers print a default label when none is // given, many programs send spaces to make a blank label. Detect // this and make it really be blank: char* c = nu; while (*c == ' ') c++; if (!*c) {XFree(nu); nu = 0;} } if (old) { if (nu && !strcmp(old,nu)) {XFree(nu); return;} XFree(old); } else { if (!nu) return; } Fl_Widget::label(nu); if (nu) { fl_font(TITLE_FONT_SLOT, TITLE_FONT_SIZE); label_w = int(fl_width(nu))+6; } else label_w = 0; if (shown() && label_h > 3 && left > 3) XClearArea(fl_display, fl_xid(this), 1, label_y+3, left-1, label_h-3, 1); } //////////////////////////////////////////////////////////////// int Frame::getGnomeState(int &) { // values for _WIN_STATE property are from Gnome WM compliance docs: #define WIN_STATE_STICKY (1<<0) /*everyone knows sticky*/ #define WIN_STATE_MINIMIZED (1<<1) /*Reserved - definition is unclear*/ #define WIN_STATE_MAXIMIZED_VERT (1<<2) /*window in maximized V state*/ #define WIN_STATE_MAXIMIZED_HORIZ (1<<3) /*window in maximized H state*/ #define WIN_STATE_HIDDEN (1<<4) /*not on taskbar but window visible*/ #define WIN_STATE_SHADED (1<<5) /*shaded (MacOS / Afterstep style)*/ #define WIN_STATE_HID_WORKSPACE (1<<6) /*not on current desktop*/ #define WIN_STATE_HID_TRANSIENT (1<<7) /*owner of transient is hidden*/ #define WIN_STATE_FIXED_POSITION (1<<8) /*window is fixed in position even*/ #define WIN_STATE_ARRANGE_IGNORE (1<<9) /*ignore for auto arranging*/ // nyi return 0; } //////////////////////////////////////////////////////////////// // Read the sizeHints, and try to remove the vast number of mistakes // that some applications seem to do writing them. // Returns true if autoplace should be done. int Frame::getSizes() { XSizeHints sizeHints; long junk; if (!XGetWMNormalHints(fl_display, window_, &sizeHints, &junk)) sizeHints.flags = 0; // get the increment, use 1 if none or illegal values: if (sizeHints.flags & PResizeInc) { inc_w = sizeHints.width_inc; if (inc_w < 1) inc_w = 1; inc_h = sizeHints.height_inc; if (inc_h < 1) inc_h = 1; } else { inc_w = inc_h = 1; } // get the current size of the window: int W = w()-dwidth; int H = h()-dheight; // I try a lot of places to get a good minimum size value. Lots of // programs set illegal or junk values, so getting this correct is // difficult: min_w = W; min_h = H; // guess a value for minimum size in case it is not set anywhere: min_w = min(min_w, 4*BUTTON_H); min_w = ((min_w+inc_w-1)/inc_w) * inc_w; min_h = min(min_h, 4*BUTTON_H); min_h = ((min_h+inc_h-1)/inc_h) * inc_h; // some programs put the minimum size here: if (sizeHints.flags & PBaseSize) { junk = sizeHints.base_width; if (junk > 0) min_w = junk; junk = sizeHints.base_height; if (junk > 0) min_h = junk; } // finally, try the actual place the minimum size should be: if (sizeHints.flags & PMinSize) { junk = sizeHints.min_width; if (junk > 0) min_w = junk; junk = sizeHints.min_height; if (junk > 0) min_h = junk; } max_w = max_h = 0; // default maximum size is "infinity" if (sizeHints.flags & PMaxSize) { // Though not defined by ICCCM standard, I interpret any maximum // size that is less than the minimum to mean "infinity". This // allows the maximum to be set in one direction only: junk = sizeHints.max_width; if (junk >= min_w && junk <= W) max_w = junk; junk = sizeHints.max_height; if (junk >= min_h && junk <= H) max_h = junk; } // set the maximize buttons according to current size: max_w_button.value(W == maximize_width()); max_h_button.value(H == maximize_height()); // Currently only 1x1 aspect works: if (sizeHints.flags & PAspect && sizeHints.min_aspect.x == sizeHints.min_aspect.y) set_flag(KEEP_ASPECT); // another fix for gimp, which sets PPosition to 0,0: if (x() <= 0 && y() <= 0) sizeHints.flags &= ~PPosition; return !(sizeHints.flags & (USPosition|PPosition)); } int max_w_switch; // return width of contents when maximize button pressed: int Frame::maximize_width() { int W = max_w_switch; if (!W) W = Root->w(); return ((W-TITLE_WIDTH-min_w)/inc_w) * inc_w + min_w; } int max_h_switch; int Frame::maximize_height() { int H = max_h_switch; if (!H) H = Root->h(); return ((H-min_h)/inc_h) * inc_h + min_h; } //////////////////////////////////////////////////////////////// void Frame::getProtocols() { int n; Atom* p = (Atom*)getProperty(wm_protocols, XA_ATOM, &n); if (p) { clear_flag(DELETE_WINDOW_PROTOCOL|TAKE_FOCUS_PROTOCOL|QUIT_PROTOCOL); for (int i = 0; i < n; ++i) { if (p[i] == wm_delete_window) { set_flag(DELETE_WINDOW_PROTOCOL); } else if (p[i] == wm_take_focus) { set_flag(TAKE_FOCUS_PROTOCOL); } else if (p[i] == wm_save_yourself) { set_flag(SAVE_PROTOCOL); } else if (p[i] == _wm_quit_app) { set_flag(QUIT_PROTOCOL); } } } XFree((char*)p); } //////////////////////////////////////////////////////////////// int Frame::getMotifHints() { long* prop = (long*)getProperty(_motif_wm_hints, _motif_wm_hints); if (!prop) return 0; // see /usr/include/X11/Xm/MwmUtil.h for meaning of these bits... // prop[0] = flags (what props are specified) // prop[1] = functions (all, resize, move, minimize, maximize, close, quit) // prop[2] = decorations (all, border, resize, title, menu, minimize, // maximize) // prop[3] = input_mode (modeless, primary application modal, system modal, // full application modal) // prop[4] = status (tear-off window) // Fill in the default value for missing fields: if (!(prop[0]&1)) prop[1] = 1; if (!(prop[0]&2)) prop[2] = 1; // The low bit means "turn the marked items off", invert this. // Transient windows already have size & iconize buttons turned off: if (prop[1]&1) prop[1] = ~prop[1] & (transient_for_xid ? ~0x58 : -1); if (prop[2]&1) prop[2] = ~prop[2] & (transient_for_xid ? ~0x60 : -1); int old_flags = flags(); // see if they are trying to turn off border: if (!(prop[2])) set_flag(NO_BORDER); else clear_flag(NO_BORDER); // see if they are trying to turn off title & close box: if (!(prop[2]&0x18)) set_flag(THIN_BORDER); else clear_flag(THIN_BORDER); // some Motif programs use this to disable resize :-( // and some programs change this after the window is shown (*&%$#%) if (!(prop[1]&2) || !(prop[2]&4)) set_flag(NO_RESIZE); else clear_flag(NO_RESIZE); // and some use this to disable the Close function. The commented // out test is it trying to turn off the mwm menu button: it appears // programs that do that still expect Alt+F4 to close them, so I // leave the close on then: if (!(prop[1]&0x20) /*|| !(prop[2]&0x10)*/) set_flag(NO_CLOSE); else clear_flag(NO_CLOSE); // see if they set "input hint" to non-zero: // prop[3] should be nonzero but the only example of this I have // found is Netscape 3.0 and it sets it to zero... if (!shown() && (prop[0]&4) /*&& prop[3]*/) set_flag(::MODAL); // see if it is forcing the iconize button back on. This makes // transient_for act like group instead... if ((prop[1]&0x8) || (prop[2]&0x20)) set_flag(ICONIZE); // Silly 'ol Amazon paint ignores WM_DELETE_WINDOW and expects to // get the SGI-specific "_WM_QUIT_APP". It indicates this by trying // to turn off the close box. SIGH!!! if (flag(QUIT_PROTOCOL) && !(prop[1]&0x20)) clear_flag(DELETE_WINDOW_PROTOCOL); XFree((char*)prop); return (flags() ^ old_flags); } //////////////////////////////////////////////////////////////// void Frame::getColormaps(void) { if (colormapWinCount) { XFree((char *)colormapWindows); delete[] window_Colormaps; } int n; XWindow* cw = (XWindow*)getProperty(wm_colormap_windows, XA_WINDOW, &n); if (cw) { colormapWinCount = n; colormapWindows = cw; window_Colormaps = new Colormap[n]; for (int i = 0; i < n; ++i) { if (cw[i] == window_) { window_Colormaps[i] = colormap; } else { XWindowAttributes attr; XSelectInput(fl_display, cw[i], ColormapChangeMask); XGetWindowAttributes(fl_display, cw[i], &attr); window_Colormaps[i] = attr.colormap; } } } else { colormapWinCount = 0; } } void Frame::installColormap() const { for (int i = colormapWinCount; i--;) if (colormapWindows[i] != window_ && window_Colormaps[i]) XInstallColormap(fl_display, window_Colormaps[i]); if (colormap) XInstallColormap(fl_display, colormap); } //////////////////////////////////////////////////////////////// // figure out transient_for(), based on the windows that exist, the // transient_for and group attributes, etc: void Frame::fix_transient_for() { Frame* p = 0; if (transient_for_xid && !flag(ICONIZE)) { for (Frame* f = first; f; f = f->next) { if (f != this && f->window_ == transient_for_xid) {p = f; break;} } // loops are illegal: for (Frame* q = p; q; q = q->transient_for_) if (q == this) {p = 0; break;} } transient_for_ = p; } int Frame::is_transient_for(const Frame* f) const { if (f) for (Frame* p = transient_for(); p; p = p->transient_for()) if (p == f) return 1; return 0; } // When a program maps or raises a window, this is called. It guesses // if this window is in fact a modal window for the currently active // window and if so transfers the active state to this: // This also activates new main windows automatically int Frame::activate_if_transient() { if (!Fl::pushed()) if (!transient_for() || is_transient_for(active_)) return activate(1); return 0; } //////////////////////////////////////////////////////////////// int Frame::activate(int warp) { // see if a modal & newer window is up: for (Frame* c = first; c && c != this; c = c->next) if (c->flag(::MODAL) && c->transient_for() == this) if (c->activate(warp)) return 1; // ignore invisible windows: if (state() != NORMAL || w() <= dwidth) return 0; // always put in the colormap: installColormap(); // move the pointer if desired: // (note that moving the pointer is pretty much required for point-to-type // unless you know the pointer is already in the window): if (!warp || Fl::event_state() & (FL_BUTTON1|FL_BUTTON2|FL_BUTTON3)) { ; } else if (warp==2) { // warp to point at title: XWarpPointer(fl_display, None, fl_xid(this), 0,0,0,0, left/2+1, min(label_y+label_w/2+1,h()/2)); } else { warp_pointer(); } // skip windows that don't want focus: if (flag(NO_FOCUS)) return 0; // set this even if we think it already has it, this seems to fix // bugs with Motif popups: XSetInputFocus(fl_display, window_, RevertToPointerRoot, fl_event_time); if (active_ != this) { if (active_) active_->deactivate(); active_ = this; #ifdef ACTIVE_COLOR XSetWindowAttributes a; a.background_pixel = fl_xpixel(FL_SELECTION_COLOR); XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a); labelcolor(contrast(FL_FOREGROUND_COLOR, FL_SELECTION_COLOR)); XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1); #else #ifdef SHOW_CLOCK redraw(); #endif #endif if (flag(TAKE_FOCUS_PROTOCOL)) sendMessage(wm_protocols, wm_take_focus); } return 1; } // this private function should only be called by constructor and if // the window is active(): void Frame::deactivate() { #ifdef ACTIVE_COLOR XSetWindowAttributes a; a.background_pixel = fl_xpixel(FL_GRAY); XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a); labelcolor(FL_FOREGROUND_COLOR); XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1); #else #ifdef SHOW_CLOCK redraw(); #endif #endif } #if CLICK_RAISES || CLICK_TO_TYPE // After the XGrabButton, the main loop will get the mouse clicks, and // it will call here when it gets them: void click_raise(Frame* f) { f->activate(); #if CLICK_RAISES if (fl_xevent->xbutton.button <= 1) f->raise(); #endif XAllowEvents(fl_display, ReplayPointer, CurrentTime); } #endif // get rid of the focus by giving it to somebody, if possible: void Frame::throw_focus(int destructor) { if (!active()) return; if (!destructor) deactivate(); active_ = 0; if (revert_to && revert_to->activate()) return; for (Frame* f = first; f; f = f->next) if (f != this && f->activate()) return; } //////////////////////////////////////////////////////////////// // change the state of the window (this is a private function and // it ignores the transient-for or desktop information): void Frame::state(short newstate) { short oldstate = state(); if (newstate == oldstate) return; state_ = newstate; switch (newstate) { case UNMAPPED: throw_focus(); XUnmapWindow(fl_display, fl_xid(this)); //set_state_flag(IGNORE_UNMAP); //XUnmapWindow(fl_display, window_); XRemoveFromSaveSet(fl_display, window_); break; case NORMAL: if (oldstate == UNMAPPED) XAddToSaveSet(fl_display, window_); if (w() > dwidth) XMapWindow(fl_display, window_); XMapWindow(fl_display, fl_xid(this)); clear_state_flag(IGNORE_UNMAP); break; default: if (oldstate == UNMAPPED) { XAddToSaveSet(fl_display, window_); } else if (oldstate == NORMAL) { throw_focus(); XUnmapWindow(fl_display, fl_xid(this)); //set_state_flag(IGNORE_UNMAP); //XUnmapWindow(fl_display, window_); } else { return; // don't setStateProperty IconicState multiple times } break; } setStateProperty(); } void Frame::setStateProperty() const { long data[2]; switch (state()) { case UNMAPPED : data[0] = WithdrawnState; break; case NORMAL : case OTHER_DESKTOP : data[0] = NormalState; break; default : data[0] = IconicState; break; } data[1] = (long)None; XChangeProperty(fl_display, window_, wm_state, wm_state, 32, PropModeReplace, (unsigned char *)data, 2); } //////////////////////////////////////////////////////////////// // Public state modifiers that move all transient_for(this) children // with the frame and do the desktops right: void Frame::raise() { Frame* newtop = 0; Frame* previous = 0; int previous_state = state_; Frame** p; // Find all the transient-for windows and this one, and raise them, // preserving stacking order: for (p = &first; *p;) { Frame* f = *p; if (f == this || f->is_transient_for(this) && f->state() != UNMAPPED) { *p = f->next; // remove it from list if (previous) { XWindowChanges w; w.sibling = fl_xid(previous); w.stack_mode = Below; XConfigureWindow(fl_display, fl_xid(f), CWSibling|CWStackMode, &w); previous->next = f; } else { XRaiseWindow(fl_display, fl_xid(f)); newtop = f; } #if DESKTOPS if (f->desktop_ && f->desktop_ != Desktop::current()) f->state(OTHER_DESKTOP); else #endif f->state(NORMAL); previous = f; } else { p = &((*p)->next); } } previous->next = first; first = newtop; #if DESKTOPS if (!transient_for() && desktop_ && desktop_ != Desktop::current()) { // for main windows we also must move to the current desktop desktop(Desktop::current()); } #endif if (previous_state != NORMAL && newtop->state_==NORMAL) newtop->activate_if_transient(); } void Frame::lower() { Frame* t = transient_for(); if (t) t->lower(); if (!next || next == t) return; // already on bottom // pull it out of the list: Frame** p = &first; for (; *p != this; p = &((*p)->next)) {} *p = next; // find end of list: Frame* f = next; while (f->next != t) f = f->next; // insert it after that: f->next = this; next = t; // and move the X window: XWindowChanges w; w.sibling = fl_xid(f); w.stack_mode = Below; XConfigureWindow(fl_display, fl_xid(this), CWSibling|CWStackMode, &w); } void Frame::iconize() { for (Frame* c = first; c; c = c->next) { if (c == this || c->is_transient_for(this) && c->state() != UNMAPPED) c->state(ICONIC); } } #if DESKTOPS void Frame::desktop(Desktop* d) { if (d == desktop_) return; // Put all the relatives onto the desktop as well: for (Frame* c = first; c; c = c->next) { if (c == this || c->is_transient_for(this)) { c->desktop_ = d; c->setProperty(_win_state, XA_CARDINAL, !d); c->setProperty(kwm_win_sticky, kwm_win_sticky, !d); if (d) { c->setProperty(kwm_win_desktop, kwm_win_desktop, d->number()); c->setProperty(_win_workspace, XA_CARDINAL, d->number()-1); } if (!d || d == Desktop::current()) { if (c->state() == OTHER_DESKTOP) c->state(NORMAL); } else { if (c->state() == NORMAL) c->state(OTHER_DESKTOP); } } } } #endif //////////////////////////////////////////////////////////////// // Resize and/or move the window. The size is given for the frame, not // the contents. This also sets the buttons on/off as needed: void Frame::set_size(int nx, int ny, int nw, int nh, int warp) { int dx = nx-x(); x(nx); int dy = ny-y(); y(ny); if (!dx && !dy && nw == w() && nh == h()) return; int unmap = 0; int remap = 0; // use XClearArea to cause correct damage events: if (nw != w()) { max_w_button.value(nw-dwidth == maximize_width()); min_w_button.value(nw <= dwidth); if (nw <= dwidth) { unmap = 1; } else { if (w() <= dwidth) remap = 1; } int minw = (nw < w()) ? nw : w(); XClearArea(fl_display, fl_xid(this), minw-RIGHT, 0, RIGHT, nh, 1); w(nw); } if (nh != h()) { max_h_button.value(nh-dheight == maximize_height()); int minh = (nh < h()) ? nh : h(); XClearArea(fl_display, fl_xid(this), 0, minh-BOTTOM, w(), BOTTOM, 1); // see if label or close box moved, erase the minimum area: // int old_label_y = label_y; // int old_label_h = label_h; h(nh); show_hide_buttons(); #if 1 //def SHOW_CLOCK int t = label_y + 3; // we have to clear the entire label area #else int t = nh; if (label_y != old_label_y) { t = label_y; if (old_label_y < t) t = old_label_y; } else if (label_y+label_h != old_label_y+old_label_h) { t = label_y+label_h; if (old_label_y+old_label_h < t) t = old_label_y+old_label_h; } #endif if (t < nh && left>LEFT) XClearArea(fl_display,fl_xid(this), 1, t, left-1, nh-t, 1); } // for maximize button move the cursor first if window gets smaller if (warp == 1 && (dx || dy)) XWarpPointer(fl_display, None,None,0,0,0,0, dx, dy); // for configure request, move the cursor first if (warp == 2 && active() && !Fl::pushed()) warp_pointer(); XMoveResizeWindow(fl_display, fl_xid(this), nx, ny, nw, nh); if (nw <= dwidth) { if (unmap) { set_state_flag(IGNORE_UNMAP); XUnmapWindow(fl_display, window_); } } else { XResizeWindow(fl_display, window_, nw-dwidth, nh-dheight); if (remap) { XMapWindow(fl_display, window_); #if CLICK_TO_TYPE if (active()) activate(); #else activate(); #endif } } // for maximize button move the cursor second if window gets bigger: if (warp == 3 && (dx || dy)) XWarpPointer(fl_display, None,None,0,0,0,0, dx, dy); if (nw > dwidth) sendConfigureNotify(); XSync(fl_display,0); } void Frame::sendConfigureNotify() const { XConfigureEvent ce; ce.type = ConfigureNotify; ce.event = window_; ce.window = window_; ce.x = x()+left-app_border_width; ce.y = y()+top-app_border_width; ce.width = w()-dwidth; ce.height = h()-dheight; ce.border_width = app_border_width; ce.above = None; ce.override_redirect = 0; XSendEvent(fl_display, window_, False, StructureNotifyMask, (XEvent*)&ce); } // move the pointer inside the window: void Frame::warp_pointer() { int X,Y; Fl::get_mouse(X,Y); X -= x(); int Xi = X; if (X <= 0) X = left/2+1; if (X >= w()) X = w()-(RIGHT/2+1); Y -= y(); int Yi = Y; if (Y < 0) Y = TOP/2+1; if (Y >= h()) Y = h()-(BOTTOM/2+1); if (X != Xi || Y != Yi) XWarpPointer(fl_display, None, fl_xid(this), 0,0,0,0, X, Y); } // Resize the frame to match the current border type: void Frame::updateBorder() { int nx = x()+left; int ny = y()+top; int nw = w()-dwidth; int nh = h()-dheight; if (flag(NO_BORDER)) { left = top = dwidth = dheight = 0; } else { left = flag(THIN_BORDER) ? LEFT : LEFT+TITLE_WIDTH; dwidth = left+RIGHT; top = TOP; dheight = TOP+BOTTOM; } nx -= left; ny -= top; nw += dwidth; nh += dheight; if (x()==nx && y()==ny && w()==nw && h()==nh) return; x(nx); y(ny); w(nw); h(nh); if (!shown()) return; // this is so constructor can call this // try to make the contents not move while the border changes around it: XSetWindowAttributes a; a.win_gravity = StaticGravity; XChangeWindowAttributes(fl_display, window_, CWWinGravity, &a); XMoveResizeWindow(fl_display, fl_xid(this), nx, ny, nw, nh); a.win_gravity = NorthWestGravity; XChangeWindowAttributes(fl_display, window_, CWWinGravity, &a); // fix the window position if the X server didn't do the gravity: XMoveWindow(fl_display, window_, left, top); } // position and show the buttons according to current border, size, // and other state information: void Frame::show_hide_buttons() { if (flag(THIN_BORDER|NO_BORDER)) { iconize_button.hide(); max_w_button.hide(); min_w_button.hide(); max_h_button.hide(); close_button.hide(); return; } int by = BUTTON_TOP; if (transient_for()) { iconize_button.hide(); min_w_button.hide(); } else { iconize_button.position(BUTTON_LEFT,by); iconize_button.show(); by += BUTTON_H; #if MINIMIZE_BOX min_w_button.position(BUTTON_LEFT,by); min_w_button.show(); by += BUTTON_H; #else min_w_button.hide(); #endif } if (min_h == max_h || flag(KEEP_ASPECT|NO_RESIZE) || !max_h_button.value() && by+label_w+2*BUTTON_H > h()-BUTTON_BOTTOM) { max_h_button.hide(); } else { max_h_button.position(BUTTON_LEFT,by); max_h_button.show(); by += BUTTON_H; } if (min_w == max_w || flag(KEEP_ASPECT|NO_RESIZE) || !max_w_button.value() && by+label_w+2*BUTTON_H > h()-BUTTON_BOTTOM) { max_w_button.hide(); } else { max_w_button.position(BUTTON_LEFT,by); max_w_button.show(); by += BUTTON_H; } if (label_y != by && shown()) XClearArea(fl_display,fl_xid(this), 1, by, left-1, label_h+label_y-by, 1); label_y = by; #if CLOSE_BOX if (by+BUTTON_H > h()-BUTTON_BOTTOM || flag(NO_CLOSE)) { #endif label_h = h()-BOTTOM-by; close_button.hide(); #if CLOSE_BOX } else { close_button.show(); close_button.position(BUTTON_LEFT,h()-(BUTTON_BOTTOM+BUTTON_H)); label_h = close_button.y()-by; } #endif } // make sure fltk does not try to set the window size: void Frame::resize(int, int, int, int) {} // For fltk2.0: void Frame::layout() { #if FL_MAJOR_VERSION>1 layout_damage(0); // actually this line is not needed in newest cvs fltk2.0 #endif } //////////////////////////////////////////////////////////////// void Frame::close() { if (flag(DELETE_WINDOW_PROTOCOL)) sendMessage(wm_protocols, wm_delete_window); else if (flag(QUIT_PROTOCOL)) sendMessage(wm_protocols, _wm_quit_app); else kill(); } void Frame::kill() { XKillClient(fl_display, window_); } // this is called when window manager exits: void Frame::save_protocol() { Frame* f; for (f = first; f; f = f->next) if (f->flag(SAVE_PROTOCOL)) { f->set_state_flag(SAVE_PROTOCOL_WAIT); f->sendMessage(wm_protocols, wm_save_yourself); } double t = 10.0; // number of seconds to wait before giving up while (t > 0.0) { for (f = first; ; f = f->next) { if (!f) return; if (f->flag(SAVE_PROTOCOL) && f->state_flags_&SAVE_PROTOCOL_WAIT) break; } t = Fl::wait(t); } } //////////////////////////////////////////////////////////////// // Drawing code: #if FL_MAJOR_VERSION>1 # include #endif void Frame::draw() { if (flag(NO_BORDER)) return; if (!flag(THIN_BORDER)) Fl_Window::draw(); if (damage() != FL_DAMAGE_CHILD) { #ifdef ACTIVE_COLOR fl_frame2(active() ? "AAAAJJWW" : "AAAAJJWWNNTT",0,0,w(),h()); if (active()) { fl_color(FL_GRAY_RAMP+('N'-'A')); fl_xyline(2, h()-3, w()-3, 2); } #else fl_frame("AAAAWWJJTTNN",0,0,w(),h()); #endif if (!flag(THIN_BORDER) && label_h > 3) { #ifdef SHOW_CLOCK if (active()) { int clkw = int(fl_width(clock_buf)); if (clock_alarm_on) { fl_font(TITLE_FONT_SLOT, TITLE_FONT_SIZE); fl_rectf(LEFT-1, label_y + label_h - 3 - clkw, TITLE_WIDTH, clkw, (ALARM_BG_COLOR>>16)&0xff, (ALARM_BG_COLOR>>8)&0xff, ALARM_BG_COLOR&0xff); fl_color((ALARM_FG_COLOR>>16)&0xff, (ALARM_FG_COLOR>>8)&0xff, ALARM_FG_COLOR&0xff); } else fl_font(MENU_FONT_SLOT, TITLE_FONT_SIZE); // This might overlay the label if the label is long enough // and the window height is short enough. For now, we'll // assume this is not enough of a problem to be concerned // about. draw_rotated90(clock_buf, 1, label_y+3, left-1, label_h-6, Fl_Align(FL_ALIGN_BOTTOM|FL_ALIGN_CLIP)); } else // Only show the clock on the active frame. XClearArea(fl_display, fl_xid(this), 1, label_y+3, left-1, label_h-3, 0); #endif fl_color(labelcolor()); fl_font(TITLE_FONT_SLOT, TITLE_FONT_SIZE); draw_rotated90(label(), 1, label_y+3, left-1, label_h-3, Fl_Align(FL_ALIGN_TOP|FL_ALIGN_CLIP)); } } } #ifdef SHOW_CLOCK void Frame::redraw_clock() { double clkw = fl_width(clock_buf); XClearArea(fl_display, fl_xid(this), 1, label_y+label_h-3-(int)clkw, left-1, (int)clkw, 1); } #endif void FrameButton::draw() { #if FL_MAJOR_VERSION>1 const int x = value()?1:0; const int y = x; drawstyle(style(),flags()|fltk::OUTPUT); FL_UP_BOX->draw(Rectangle(w(),h())); #else const int x = this->x(); const int y = this->y(); Fl_Widget::draw_box(value() ? FL_DOWN_FRAME : FL_UP_FRAME, FL_GRAY); #endif fl_color(parent()->labelcolor()); switch (label()[0]) { case 'W': #if MINIMIZE_ARROW fl_line (x+2,y+(h())/2,x+w()-4,y+h()/2); fl_line (x+2,y+(h())/2,x+2+4,y+h()/2+4); fl_line (x+2,y+(h())/2,x+2+4,y+h()/2-4); #else fl_rect(x+(h()-7)/2,y+3,2,h()-6); #endif return; case 'w': fl_rect(x+2,y+(h()-7)/2,w()-4,7); return; case 'h': fl_rect(x+(h()-7)/2,y+2,7,h()-4); return; case 'X': #if CLOSE_X fl_line(x+2,y+3,x+w()-5,y+h()-4); fl_line(x+3,y+3,x+w()-4,y+h()-4); fl_line(x+2,y+h()-4,x+w()-5,y+3); fl_line(x+3,y+h()-4,x+w()-4,y+3); #endif #if CLOSE_HITTITE_LIGHTNING fl_arc(x+3,y+3,w()-6,h()-6,0,360); fl_line(x+7,y+3, x+7,y+11); #endif return; case 'i': #if ICONIZE_BOX fl_rect(x+w()/2-1,y+h()/2-1,3,3); #endif return; } } //////////////////////////////////////////////////////////////// // User interface code: // this is called when user clicks the buttons: void Frame::button_cb(Fl_Button* b) { switch (b->label()[0]) { case 'W': // minimize button if (b->value()) { if (!max_w_button.value()) { restore_x = x()+left; restore_y = y()+top; #if MINIMIZE_HEIGHT restore_w=w()-dwidth; restore_h = h()-dwidth; #endif } #if MINIMIZE_HEIGHT set_size(x(), y(), dwidth-1, min(h(),min(350,label_w+3*BUTTON_H+BUTTON_TOP+BUTTON_BOTTOM)), 1); #else set_size(x(), y(), dwidth-1, h(), 1); #endif } else { #if MINIMIZE_HEIGHT set_size(x(), y(), restore_w+dwidth, restore_h+dwidth, 1); #else set_size(x(), y(), restore_w+dwidth, h(), 1); #endif } show_hide_buttons(); break; case 'w': // max-width button if (b->value()) { if (!min_w_button.value()) {restore_x=x()+left; restore_w=w()-dwidth;} int W = maximize_width()+dwidth; int X = force_x_onscreen(x() + (w()-W)/2, W); set_size(X, y(), W, h(), 3); } else { set_size(restore_x-left, y(), restore_w+dwidth, h(), 1); } show_hide_buttons(); break; case 'h': // max-height button if (b->value()) { restore_y = y()+top; restore_h = h()-dwidth; int H = maximize_height()+dheight; int Y = force_y_onscreen(y() + (h()-H)/2, H); set_size(x(), Y, w(), H, 3); } else { set_size(x(), restore_y-top, w(), restore_h+dwidth, 1); } break; case 'X': close(); break; default: // iconize button iconize(); break; } } // static callback for fltk: void Frame::button_cb_static(Fl_Widget* w, void*) { ((Frame*)(w->parent()))->button_cb((Fl_Button*)w); } // This method figures out what way the mouse will resize the window. // It is used to set the cursor and to actually control what you grab. // If the window cannot be resized in some direction this should not // return that direction. int Frame::mouse_location() { int x = Fl::event_x(); int y = Fl::event_y(); int r = 0; if (flag(NO_RESIZE)) return 0; if (min_h != max_h) { if (y < RESIZE_EDGE) r |= FL_ALIGN_TOP; else if (y >= h()-RESIZE_EDGE) r |= FL_ALIGN_BOTTOM; } if (min_w != max_w) { #if RESIZE_LEFT if (x < RESIZE_EDGE) r |= FL_ALIGN_LEFT; #else if (x < RESIZE_EDGE && r) r |= FL_ALIGN_LEFT; #endif else if (x >= w()-RESIZE_EDGE) r |= FL_ALIGN_RIGHT; } return r; } // set the cursor correctly for a return value from mouse_location(): void Frame::set_cursor(int r) { Fl_Cursor c = r ? FL_CURSOR_ARROW : FL_CURSOR_MOVE; switch (r) { case FL_ALIGN_TOP: case FL_ALIGN_BOTTOM: c = FL_CURSOR_NS; break; case FL_ALIGN_LEFT: case FL_ALIGN_RIGHT: c = FL_CURSOR_WE; break; case FL_ALIGN_LEFT|FL_ALIGN_TOP: case FL_ALIGN_RIGHT|FL_ALIGN_BOTTOM: c = FL_CURSOR_NWSE; break; case FL_ALIGN_LEFT|FL_ALIGN_BOTTOM: case FL_ALIGN_RIGHT|FL_ALIGN_TOP: c = FL_CURSOR_NESW; break; } #if FL_MAJOR_VERSION>1 cursor(c); #else static Frame* previous_frame; static Fl_Cursor previous_cursor; if (this != previous_frame || c != previous_cursor) { previous_frame = this; previous_cursor = c; cursor(c, CURSOR_FG_SLOT, CURSOR_BG_SLOT); } #endif } #ifdef AUTO_RAISE // timeout callback to cause autoraise: void auto_raise(void*) { if (Frame::activeFrame() && !Fl::grab() && !Fl::pushed()) Frame::activeFrame()->raise(); } #endif extern void ShowMenu(); // If cursor is in the contents of a window this is set to that window. // This is only used to force the cursor to an arrow even though X keeps // sending mysterious erroneous move events: static Frame* cursor_inside = 0; // Handle an fltk event. int Frame::handle(int e) { static int what, dx, dy, ix, iy, iw, ih; // see if child widget handles event: #if FL_MAJOR_VERSION > 1 if (fltk::Group::handle(e) && e != FL_ENTER && e != FL_MOVE) { if (e == FL_PUSH) set_cursor(-1); return 1; } #else if (Fl_Group::handle(e) && e != FL_ENTER && e != FL_MOVE) { if (e == FL_PUSH) set_cursor(-1); return 1; } #endif switch (e) { case FL_SHOW: case FL_HIDE: return 0; // prevent fltk from messing things up case FL_ENTER: #if !CLICK_TO_TYPE if (Fl::pushed() || Fl::grab()) return 1; if (activate()) { #ifdef AUTO_RAISE Fl::remove_timeout(auto_raise); Fl::add_timeout(AUTO_RAISE, auto_raise); #endif } #endif goto GET_CROSSINGS; case FL_LEAVE: #if !CLICK_TO_TYPE && !STICKY_FOCUS if (active()) { deactivate(); XSetInputFocus(fl_display, PointerRoot, RevertToPointerRoot, fl_event_time); active_ = 0; } #endif goto GET_CROSSINGS; case FL_MOVE: GET_CROSSINGS: // set cursor_inside to true when the mouse is inside a window // set it false when mouse is on a frame or outside a window. // fltk mangles the X enter/leave events, we need the original ones: switch (fl_xevent->type) { case LeaveNotify: if (fl_xevent->xcrossing.detail == NotifyInferior) { // cursor moved from frame to interior cursor_inside = this; break; } else { // cursor moved to another window return 1; } case EnterNotify: // see if cursor skipped over frame and directly to interior: if (fl_xevent->xcrossing.detail == NotifyVirtual || fl_xevent->xcrossing.detail == NotifyNonlinearVirtual) cursor_inside = this; else { // cursor is now pointing at frame: cursor_inside = 0; } } if (Fl::belowmouse() != this || cursor_inside == this) set_cursor(-1); else set_cursor(mouse_location()); return 1; case FL_PUSH: if (Fl::event_button() > 2) { set_cursor(-1); ShowMenu(); return 1; } ix = x(); iy = y(); iw = w(); ih = h(); if (!max_w_button.value() && !min_w_button.value()) { restore_x = ix+left; restore_w = iw-dwidth; } #if MINIMIZE_HEIGHT if (!min_w_button.value()) #endif if (!max_h_button.value()) { restore_y = iy+top; restore_h = ih-dwidth; } what = mouse_location(); if (Fl::event_button() > 1) what = 0; // middle button does drag dx = Fl::event_x_root()-ix; if (what & FL_ALIGN_RIGHT) dx -= iw; dy = Fl::event_y_root()-iy; if (what & FL_ALIGN_BOTTOM) dy -= ih; set_cursor(what); return 1; case FL_DRAG: if (Fl::event_is_click()) return 1; // don't drag yet case FL_RELEASE: if (Fl::event_is_click()) { if (Fl::grab()) return 1; #if CLICK_TO_TYPE if (activate()) { if (Fl::event_button() <= 1) raise(); return 1; } #endif if (Fl::event_button() > 1) lower(); else raise(); } else if (!what) { int nx = Fl::event_x_root()-dx; int W = Root->x()+Root->w(); if (nx+iw > W && nx+iw < W+SCREEN_SNAP) { int t = W+1-iw; if (iw >= Root->w() || x() > t || nx+iw >= W+EDGE_SNAP) t = W+(dwidth-left)-iw; if (t >= x() && t < nx) nx = t; } int X = Root->x(); if (nx < X && nx > X-SCREEN_SNAP) { int t = X-1; if (iw >= Root->w() || x() < t || nx <= X-EDGE_SNAP) t = X-BUTTON_LEFT; if (t <= x() && t > nx) nx = t; } int ny = Fl::event_y_root()-dy; int H = Root->y()+Root->h(); if (ny+ih > H && ny+ih < H+SCREEN_SNAP) { int t = H+1-ih; if (ih >= Root->h() || y() > t || ny+ih >= H+EDGE_SNAP) t = H+(dheight-top)-ih; if (t >= y() && t < ny) ny = t; } int Y = Root->y(); if (ny < Y && ny > Y-SCREEN_SNAP) { int t = Y-1; if (ih >= H || y() < t || ny <= Y-EDGE_SNAP) t = Y-top; if (t <= y() && t > ny) ny = t; } set_size(nx, ny, iw, ih); } else { int nx = ix; int ny = iy; int nw = iw; int nh = ih; if (what & FL_ALIGN_RIGHT) nw = Fl::event_x_root()-dx-nx; else if (what & FL_ALIGN_LEFT) nw = ix+iw-(Fl::event_x_root()-dx); else {nx = x(); nw = w();} if (what & FL_ALIGN_BOTTOM) nh = Fl::event_y_root()-dy-ny; else if (what & FL_ALIGN_TOP) nh = iy+ih-(Fl::event_y_root()-dy); else {ny = y(); nh = h();} if (flag(KEEP_ASPECT)) { if (nw-dwidth > nh-dwidth && (what&(FL_ALIGN_LEFT|FL_ALIGN_RIGHT)) || !(what&(FL_ALIGN_TOP|FL_ALIGN_BOTTOM))) nh = nw-dwidth+dheight; else nw = nh-dheight+dwidth; } int MINW = min_w+dwidth; if (nw <= dwidth && dwidth > TITLE_WIDTH) { nw = dwidth-1; #if MINIMIZE_HEIGHT restore_h = nh; #endif } else { if (inc_w > 1) nw = ((nw-MINW+inc_w/2)/inc_w)*inc_w+MINW; if (nw < MINW) nw = MINW; else if (max_w && nw > max_w+dwidth) nw = max_w+dwidth; } int MINH = min_h+dheight; const int MINH_B = BUTTON_H+BUTTON_TOP+BUTTON_BOTTOM; if (MINH_B > MINH) MINH = MINH_B; if (inc_h > 1) nh = ((nh-MINH+inc_h/2)/inc_h)*inc_h+MINH; if (nh < MINH) nh = MINH; else if (max_h && nh > max_h+dheight) nh = max_h+dheight; if (what & FL_ALIGN_LEFT) nx = ix+iw-nw; if (what & FL_ALIGN_TOP) ny = iy+ih-nh; set_size(nx,ny,nw,nh); } return 1; } return 0; } // Handle events that fltk did not recognize (mostly ones directed // at the desktop): int Frame::handle(const XEvent* ei) { switch (ei->type) { case ConfigureRequest: { const XConfigureRequestEvent* e = &(ei->xconfigurerequest); unsigned long mask = e->value_mask; if (mask & CWBorderWidth) app_border_width = e->border_width; // Try to detect if the application is really trying to move the // window, or is simply echoing it's postion, possibly with some // variation (such as echoing the parent window position), and // dont' move it in that case: int X = (mask & CWX && e->x != x()) ? e->x+app_border_width-left : x(); int Y = (mask & CWY && e->y != y()) ? e->y+app_border_width-top : y(); int W = (mask & CWWidth) ? e->width+dwidth : w(); int H = (mask & CWHeight) ? e->height+dheight : h(); // Generally we want to obey any application positioning of the // window, except when it appears the app is trying to position // the window "at the edge". if (!(mask & CWX) || (X >= -2*left && X < 0)) X = force_x_onscreen(X,W); if (!(mask & CWY) || (Y >= -2*top && Y < 0)) Y = force_y_onscreen(Y,H); // Fix Rick Sayre's program that resizes it's windows bigger than the // maximum size: if (W > max_w+dwidth) max_w = 0; if (H > max_h+dheight) max_h = 0; set_size(X, Y, W, H, 2); if (e->value_mask & CWStackMode && e->detail == Above && state()==NORMAL) raise(); return 1;} case MapRequest: { //const XMapRequestEvent* e = &(ei->xmaprequest); raise(); return 1;} case UnmapNotify: { const XUnmapEvent* e = &(ei->xunmap); if (e->window == window_ && !e->from_configure) { if (state_flags_&IGNORE_UNMAP) clear_state_flag(IGNORE_UNMAP); else state(UNMAPPED); } return 1;} case DestroyNotify: { //const XDestroyWindowEvent* e = &(ei->xdestroywindow); delete this; return 1;} case ReparentNotify: { const XReparentEvent* e = &(ei->xreparent); if (e->parent==fl_xid(this)) return 1; // echo if (e->parent==fl_xid(Root)) return 1; // app is trying to tear-off again? delete this; // guess they are trying to paste tear-off thing back? return 1;} case ClientMessage: { const XClientMessageEvent* e = &(ei->xclient); if (e->message_type == wm_change_state && e->format == 32) { if (e->data.l[0] == NormalState) raise(); else if (e->data.l[0] == IconicState) iconize(); } else // we may want to ignore _WIN_LAYER from xmms? Fl::warning("flwm: unexpected XClientMessageEvent, type 0x%lx, " "window 0x%lx\n", e->message_type, e->window); return 1;} case ColormapNotify: { const XColormapEvent* e = &(ei->xcolormap); if (e->c_new) { // this field is called "new" in the old C++-unaware Xlib colormap = e->colormap; if (active()) installColormap(); } return 1;} case PropertyNotify: { const XPropertyEvent* e = &(ei->xproperty); Atom a = e->atom; // case XA_WM_ICON_NAME: (do something similar to name) if (a == XA_WM_NAME) { getLabel(e->state == PropertyDelete); } else if (a == wm_state) { // it's not clear if I really need to look at this. Need to make // sure it is not seeing the state echoed by the application by // checking for it being different... switch (getIntProperty(wm_state, wm_state, state())) { case IconicState: if (state() == NORMAL || state() == OTHER_DESKTOP) iconize(); break; case NormalState: if (state() != NORMAL && state() != OTHER_DESKTOP) raise(); break; } } else if (a == wm_colormap_windows) { getColormaps(); if (active()) installColormap(); } else if (a == _motif_wm_hints) { // some #%&%$# SGI Motif programs change this after mapping the window! // :-( :=( :-( :=( :-( :=( :-( :=( :-( :=( :-( :=( if (getMotifHints()) { // returns true if any flags changed fix_transient_for(); updateBorder(); show_hide_buttons(); } } else if (a == wm_protocols) { getProtocols(); // get Motif hints since they may do something with QUIT: getMotifHints(); } else if (a == XA_WM_NORMAL_HINTS || a == XA_WM_SIZE_HINTS) { getSizes(); show_hide_buttons(); } else if (a == XA_WM_TRANSIENT_FOR) { XGetTransientForHint(fl_display, window_, &transient_for_xid); fix_transient_for(); show_hide_buttons(); } else if (a == XA_WM_COMMAND) { clear_state_flag(SAVE_PROTOCOL_WAIT); } return 1;} } return 0; } //////////////////////////////////////////////////////////////// // X utility routines: void* Frame::getProperty(Atom a, Atom type, int* np) const { return ::getProperty(window_, a, type, np); } void* getProperty(XWindow w, Atom a, Atom type, int* np) { Atom realType; int format; unsigned long n, extra; int status; uchar* prop; status = XGetWindowProperty(fl_display, w, a, 0L, 256L, False, type, &realType, &format, &n, &extra, &prop); if (status != Success) return 0; if (!prop) return 0; if (!n) {XFree(prop); return 0;} if (np) *np = (int)n; return (void*)prop; } int Frame::getIntProperty(Atom a, Atom type, int deflt) const { return ::getIntProperty(window_, a, type, deflt); } int getIntProperty(XWindow w, Atom a, Atom type, int deflt) { void* prop = getProperty(w, a, type); if (!prop) return deflt; int r = int(*(long*)prop); XFree(prop); return r; } void setProperty(XWindow w, Atom a, Atom type, int v) { long prop = v; XChangeProperty(fl_display, w, a, type, 32, PropModeReplace, (uchar*)&prop,1); } void Frame::setProperty(Atom a, Atom type, int v) const { ::setProperty(window_, a, type, v); } void Frame::sendMessage(Atom a, Atom l) const { XEvent ev; long mask; memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.window = window_; ev.xclient.message_type = a; ev.xclient.format = 32; ev.xclient.data.l[0] = long(l); ev.xclient.data.l[1] = long(fl_event_time); mask = 0L; XSendEvent(fl_display, window_, False, mask, &ev); } flwm-1.02+cvs20080422/Frame.H0000644000175000017500000001360110132424626012742 0ustar meme// Frame.H // Each X window being managed by fltk has one of these #ifndef Frame_H #define Frame_H #include #include #include #include #if FL_MAJOR_VERSION<2 # define XWindow Window #endif // The state is an enumeration of reasons why the window may be invisible. // Only if it is NORMAL is the window visible. enum { UNMAPPED = 0, // unmap command from app (X calls this WithdrawnState) NORMAL = 1, // window is visible //SHADED = 2, // acts like NORMAL ICONIC = 3, // hidden/iconized OTHER_DESKTOP = 4 // normal but on another desktop }; // values for flags: // The flags are constant and are turned on by information learned // from the Gnome, KDE, and/or Motif window manager hints. Flwm will // ignore attempts to change these hints after the window is mapped. enum { NO_FOCUS = 0x0001, // does not take focus CLICK_TO_FOCUS = 0x0002, // must click on window to give it focus NO_BORDER = 0x0004, // raw window with no border THIN_BORDER = 0x0008, // just resize border NO_RESIZE = 0x0010, // don't resize even if sizehints say its ok NO_CLOSE = 0x0040, // don't put a close box on it TAKE_FOCUS_PROTOCOL = 0x0080, // send junk when giving window focus DELETE_WINDOW_PROTOCOL= 0x0100, // close box sends a message KEEP_ASPECT = 0x0200, // aspect ratio from sizeHints MODAL = 0x0400, // grabs focus from transient_for window ICONIZE = 0x0800, // transient_for_ actually means group :-( QUIT_PROTOCOL = 0x1000, // Irix 4DWM "quit" menu item SAVE_PROTOCOL = 0x2000 // "WM_SAVE_YOURSELF" stuff }; // values for state_flags: // These change over time enum { IGNORE_UNMAP = 0x01, // we did something that echos an UnmapNotify SAVE_PROTOCOL_WAIT = 0x02 }; class FrameButton : public Fl_Button { void draw(); public: FrameButton(int X, int Y, int W, int H, const char* L=0) : Fl_Button(X,Y,W,H,L) {} }; class Desktop; class Frame : public Fl_Window { XWindow window_; short state_; // X server state: iconic, withdrawn, normal short state_flags_; // above state flags void set_state_flag(short i) {state_flags_ |= i;} void clear_state_flag(short i) {state_flags_&=~i;} int flags_; // above constant flags void set_flag(int i) {flags_ |= i;} void clear_flag(int i) {flags_&=~i;} int restore_x, restore_w; // saved size when min/max width is set int restore_y, restore_h; // saved size when max height is set int min_w, max_w, inc_w; // size range and increment int min_h, max_h, inc_h; // size range and increment int app_border_width; // value of border_width application tried to set int left, top, dwidth, dheight; // current thickness of border int label_y, label_h; // location of label int label_w; // measured width of printed label XWindow transient_for_xid; // value from X Frame* transient_for_; // the frame for that xid, if found Frame* revert_to; // probably the xterm this was run from Colormap colormap; // this window's colormap int colormapWinCount; // list of other windows to install colormaps for XWindow *colormapWindows; Colormap *window_Colormaps; // their colormaps Desktop* desktop_; FrameButton close_button; FrameButton iconize_button; FrameButton max_h_button; FrameButton max_w_button; FrameButton min_w_button; int maximize_width(); int maximize_height(); int force_x_onscreen(int X, int W); int force_y_onscreen(int Y, int H); void place_window(); void sendMessage(Atom, Atom) const; void sendConfigureNotify() const; void setStateProperty() const; void* getProperty(Atom, Atom = AnyPropertyType, int* length = 0) const; int getIntProperty(Atom, Atom = AnyPropertyType, int deflt = 0) const; void setProperty(Atom, Atom, int) const; void getLabel(int del = 0); void getColormaps(); int getSizes(); int getGnomeState(int&); void getProtocols(); int getMotifHints(); void updateBorder(); void fix_transient_for(); // called when transient_for_xid changes void installColormap() const; void set_size(int,int,int,int, int warp=0); void resize(int,int,int,int); void layout(); void show_hide_buttons(); int handle(int); // handle fltk events void set_cursor(int); int mouse_location(); void draw(); static Frame* active_; static void button_cb_static(Fl_Widget*, void*); void button_cb(Fl_Button*); void deactivate(); int activate_if_transient(); void _desktop(Desktop*); int border() const {return !(flags_&NO_BORDER);} int flags() const {return flags_;} int flag(int i) const {return flags_&i;} void throw_focus(int destructor = 0); void warp_pointer(); public: int handle(const XEvent*); static Frame* first; Frame* next; // stacking order, top to bottom Frame(XWindow, XWindowAttributes* = 0); ~Frame(); XWindow window() const {return window_;} Frame* transient_for() const {return transient_for_;} int is_transient_for(const Frame*) const; Desktop* desktop() const {return desktop_;} void desktop(Desktop*); void raise(); // also does map void lower(); void iconize(); void close(); void kill(); int activate(int warp = 0); // returns true if it actually sets active state short state() const {return state_;} void state(short); // don't call this unless you know what you are doing! int active() const {return active_==this;} static Frame* activeFrame() {return active_;} static void save_protocol(); // called when window manager exits // The following should be conditionally defined based on the // SHOW_CLOCK definition in config.h but that definition is not // available at the time we are evaluating this; it does no harm // to be present even if not SHOW_CLOCK. void redraw_clock(); }; // handy wrappers for those ugly X routines: void* getProperty(XWindow, Atom, Atom = AnyPropertyType, int* length = 0); int getIntProperty(XWindow, Atom, Atom = AnyPropertyType, int deflt = 0); void setProperty(XWindow, Atom, Atom, int); #endif flwm-1.02+cvs20080422/FrameWindow.C0000644000175000017500000000210507040736155014131 0ustar meme// FrameWindow.C // X does not echo back the window-map events (it probably should when // override_redirect is off). Unfortunately this means you have to use // this subclass if you want a "normal" fltk window, it will force a // Frame to be created and destroy it upon hide. // Warning: modal() does not work! Don't turn it on as it screws up the // interface with the window borders. You can use set_non_modal() to // disable the iconize box but the window manager must be written to // not be modal. #include #include "FrameWindow.H" #include "Frame.H" extern int dont_set_event_mask; void FrameWindow::show() { if (shown()) {Fl_Window::show(); return;} Fl_Window::show(); dont_set_event_mask = 1; frame = new Frame(fl_xid(this)); dont_set_event_mask = 0; } void FrameWindow::hide() { if (shown()) { Fl_Window::hide(); delete frame; } } int FrameWindow::handle(int e) { if (Fl_Window::handle(e)) return 1; // make Esc close the window: if (e == FL_SHORTCUT && Fl::event_key()==FL_Escape) { do_callback(); return 1; } return 0; } flwm-1.02+cvs20080422/FrameWindow.H0000644000175000017500000000156207040736155014144 0ustar meme// FrameWindow.H // X does not echo back the window-map events (it probably should when // override_redirect is off). Unfortunately this means you have to use // this subclass if you want a "normal" fltk window, it will force a // Frame to be created and destroy it upon hide. // Warning: modal() does not work! Don't turn it on as it screws up the // interface with the window borders. You can use set_non_modal() to // disable the iconize box but the window manager must be written to // not be modal. #ifndef FrameWindow_H #define FrameWindow_H #include class Frame; class FrameWindow : public Fl_Window { Frame* frame; public: void hide(); void show(); int handle(int); FrameWindow(int X, int Y, int W, int H, const char* L = 0) : Fl_Window(X,Y,W,H,L) {} FrameWindow(int W, int H, const char* L = 0) : Fl_Window(W,H,L) {} }; #endif flwm-1.02+cvs20080422/Hotkeys.C0000644000175000017500000001327510450700453013336 0ustar meme// Hotkeys.C // If you want to change what the hotkeys are, see the table at the bottom! #include "config.h" #include "Frame.H" #include "Desktop.H" #include extern void ShowMenu(); extern void ShowTabMenu(int tab); #if STANDARD_HOTKEYS static void NextWindow() { // Alt+Tab ShowTabMenu(1); } static void PreviousWindow() { // Alt+Shift+Tab ShowTabMenu(-1); } #endif #if DESKTOPS static void NextDesk() { if (Desktop::current()) { Desktop::current(Desktop::current()->next? Desktop::current()->next:Desktop::first); } else { Desktop::current(Desktop::first); } } static void PreviousDesk() { Desktop* search=Desktop::first; while (search->next && search->next!=Desktop::current()){ search=search->next; } Desktop::current(search); } // warning: this assummes it is bound to Fn key: static void DeskNumber() { Desktop::current(Desktop::number(Fl::event_key()-FL_F, 1)); } #endif #if WMX_HOTKEYS || CDE_HOTKEYS static void Raise() { // Alt+Up Frame* f = Frame::activeFrame(); if (f) f->raise(); } static void Lower() { // Alt+Down Frame* f = Frame::activeFrame(); if (f) f->lower(); } static void Iconize() { // Alt+Enter Frame* f = Frame::activeFrame(); if (f) f->iconize(); else ShowMenu(); // so they can deiconize stuff } static void Close() { // Alt+Delete Frame* f = Frame::activeFrame(); if (f) f->close(); } #endif //////////////////////////////////////////////////////////////// static struct {int key; void (*func)();} keybindings[] = { #if STANDARD_HOTKEYS || MINIMUM_HOTKEYS // these are very common and tend not to conflict, due to Windoze: {FL_ALT+FL_Escape, ShowMenu}, {FL_ALT+FL_Menu, ShowMenu}, #endif #if STANDARD_HOTKEYS {FL_ALT+FL_Tab, NextWindow}, {FL_ALT+FL_SHIFT+FL_Tab,PreviousWindow}, {FL_ALT+FL_SHIFT+0xfe20,PreviousWindow}, // XK_ISO_Left_Tab #endif #if KWM_HOTKEYS && DESKTOPS // KWM uses these to switch desktops // {FL_CTRL+FL_Tab, NextDesk}, // {FL_CTRL+FL_SHIFT+FL_Tab,PreviousDesk}, // {FL_CTRL+FL_SHIFT+0xfe20,PreviousDesk}, // XK_ISO_Left_Tab {FL_CTRL+FL_F+1, DeskNumber}, {FL_CTRL+FL_F+2, DeskNumber}, {FL_CTRL+FL_F+3, DeskNumber}, {FL_CTRL+FL_F+4, DeskNumber}, {FL_CTRL+FL_F+5, DeskNumber}, {FL_CTRL+FL_F+6, DeskNumber}, {FL_CTRL+FL_F+7, DeskNumber}, {FL_CTRL+FL_F+8, DeskNumber}, {FL_CTRL+FL_F+9, DeskNumber}, {FL_CTRL+FL_F+10, DeskNumber}, {FL_CTRL+FL_F+11, DeskNumber}, {FL_CTRL+FL_F+12, DeskNumber}, #endif #if WMX_HOTKEYS // wmx also sets all these, they seem pretty useful: {FL_ALT+FL_Up, Raise}, {FL_ALT+FL_Down, Lower}, {FL_ALT+FL_Enter, Iconize}, {FL_ALT+FL_Delete, Close}, //{FL_ALT+FL_Page_Up, ToggleMaxH}, //{FL_ALT+FL_Page_Down,ToggleMaxW}, #endif #if WMX_DESK_HOTKEYS && DESKTOPS // these wmx keys are not set by default as they break NetScape: {FL_ALT+FL_Left, PreviousDesk}, {FL_ALT+FL_Right, NextDesk}, #endif #if CDE_HOTKEYS // CDE hotkeys (or at least what SGI's 4DWM uses): {FL_ALT+FL_F+1, Raise}, //{FL_ALT+FL_F+2, unknown}, // KWM uses this to run a typed-in command {FL_ALT+FL_F+3, Lower}, {FL_ALT+FL_F+4, Close}, // this matches KWM //{FL_ALT+FL_F+5, Restore}, // useless because no icons visible //{FL_ALT+FL_F+6, unknown}, // ? //{FL_ALT+FL_F+7, Move}, // grabs the window for movement //{FL_ALT+FL_F+8, Resize}, // grabs the window for resizing {FL_ALT+FL_F+9, Iconize}, //{FL_ALT+FL_F+10, Maximize}, //{FL_ALT+FL_F+11, unknown}, // ? {FL_ALT+FL_F+12, Close}, // actually does "quit" #else #if DESKTOPS && DESKTOP_HOTKEYS // seem to be common to Linux window managers {FL_ALT+FL_F+1, DeskNumber}, {FL_ALT+FL_F+2, DeskNumber}, {FL_ALT+FL_F+3, DeskNumber}, {FL_ALT+FL_F+4, DeskNumber}, {FL_ALT+FL_F+5, DeskNumber}, {FL_ALT+FL_F+6, DeskNumber}, {FL_ALT+FL_F+7, DeskNumber}, {FL_ALT+FL_F+8, DeskNumber}, {FL_ALT+FL_F+9, DeskNumber}, {FL_ALT+FL_F+10, DeskNumber}, {FL_ALT+FL_F+11, DeskNumber}, {FL_ALT+FL_F+12, DeskNumber}, #endif #endif {0}}; #if FL_MAJOR_VERSION > 1 // Define missing function, this should get put in fltk2.0: namespace fltk { int test_shortcut(int shortcut) { if (!shortcut) return 0; int shift = Fl::event_state(); // see if any required shift flags are off: if ((shortcut&shift) != (shortcut&0x7fff0000)) return 0; // record shift flags that are wrong: int mismatch = (shortcut^shift)&0x7fff0000; // these three must always be correct: if (mismatch&(FL_META|FL_ALT|FL_CTRL)) return 0; int key = shortcut & 0xffff; // if shift is also correct, check for exactly equal keysyms: if (!(mismatch&(FL_SHIFT)) && unsigned(key) == Fl::event_key()) return 1; // try matching ascii, ignore shift: if (key == event_text()[0]) return 1; // kludge so that Ctrl+'_' works (as opposed to Ctrl+'^_'): if ((shift&FL_CTRL) && key >= 0x3f && key <= 0x5F && event_text()[0]==(key^0x40)) return 1; return 0; } } #endif int Handle_Hotkey() { for (int i = 0; keybindings[i].key; i++) { if (Fl::test_shortcut(keybindings[i].key) || (keybindings[i].key & 0xFFFF) == FL_Delete && Fl::event_key() == FL_BackSpace// fltk bug? ) { keybindings[i].func(); return 1; } } return 0; } extern Fl_Window* Root; void Grab_Hotkeys() { XWindow root = fl_xid(Root); for (int i = 0; keybindings[i].key; i++) { int k = keybindings[i].key; int keycode = XKeysymToKeycode(fl_display, k & 0xFFFF); if (!keycode) continue; // Silly X! we need to ignore caps lock & numlock keys by grabbing // all the combinations: XGrabKey(fl_display, keycode, k>>16, root, 0, 1, 1); XGrabKey(fl_display, keycode, (k>>16)|2, root, 0, 1, 1); // CapsLock XGrabKey(fl_display, keycode, (k>>16)|16, root, 0, 1, 1); // NumLock XGrabKey(fl_display, keycode, (k>>16)|18, root, 0, 1, 1); // both } } flwm-1.02+cvs20080422/Makefile0000644000175000017500000000370110654364646013255 0ustar memeSHELL=/bin/sh PROGRAM = flwm VERSION = 1.02 CXXFILES = main.C Frame.C Rotated.C Menu.C FrameWindow.C Desktop.C Hotkeys.C MANPAGE = 1 ################################################################ OBJECTS = $(CXXFILES:.C=.o) all: makeinclude $(PROGRAM) $(PROGRAM) : $(OBJECTS) $(CXX) $(LDFLAGS) -o $(PROGRAM) $(OBJECTS) $(LIBS) makeinclude: configure ./configure include makeinclude .SUFFIXES : .fl .do .C .c .H .C.o : $(CXX) $(CXXFLAGS) -c $< .C : $(CXX) $(CXXFLAGS) -c $< .fl.C : -fluid -c $< .fl.H : -fluid -c $< clean : -@ rm -f *.o $(PROGRAM) $(CLEAN) core *~ makedepend @touch makedepend depend: $(MAKEDEPEND) -I.. $(CXXFLAGS) $(CXXFILES) $(CFILES) > makedepend makedepend: touch makedepend include makedepend install: $(PROGRAM) $(INSTALL) -s $(PROGRAM) $(bindir)/$(PROGRAM) $(INSTALL) $(PROGRAM).$(MANPAGE) $(mandir)/man$(MANPAGE)/$(PROGRAM).$(MANPAGE) uninstall: -@ rm -f $(bindir)/$(PROGRAM) -@ rm -f $(mandir)/man$(MANPAGE)/$(PROGRAM).$(MANPAGE) dist: cat /dev/null > makedepend -@mkdir $(PROGRAM)-$(VERSION) -@ln README Makefile configure install-sh makedepend *.C *.H *.h *.in *.fl $(PROGRAM).$(MANPAGE) flwm_wmconfig $(PROGRAM)-$(VERSION) tar -cvzf $(PROGRAM)-$(VERSION).tgz $(PROGRAM)-$(VERSION) -@rm -r $(PROGRAM)-$(VERSION) exedist: -@mkdir $(PROGRAM)-$(VERSION)-x86 -@ln README $(PROGRAM) $(PROGRAM).$(MANPAGE) flwm_wmconfig $(PROGRAM)-$(VERSION)-x86 tar -cvzf $(PROGRAM)-$(VERSION)-x86.tgz $(PROGRAM)-$(VERSION)-x86 -@rm -r $(PROGRAM)-$(VERSION)-x86 ################################################################ PROGRAM_D = $(PROGRAM)_d debug: $(PROGRAM_D) OBJECTS_D = $(CXXFILES:.C=.do) $(CFILES:.c=.do) .C.do : $(CXX) -I.. $(CXXFLAGS) -DDEBUG -c -o $@ $< .c.do : $(CC) -I.. $(CFLAGS) -DDEBUG -o $@ $< $(PROGRAM_D) : $(OBJECTS_D) $(CXX) $(LDFLAGS) -o $(PROGRAM_D) $(OBJECTS_D) $(LIBS) rotated_test: Rotated.o rotated_test.C $(CXX) $(CXXFLAGS) $(LDFLAGS) -o rotated_test rotated_test.C Rotated.o $(LIBS) $(LIBS) flwm-1.02+cvs20080422/Menu.C0000644000175000017500000004060210654537565012630 0ustar meme// Menu.cxx #include "config.h" #include "Frame.H" #if DESKTOPS #include "Desktop.H" #endif #include #include #include #include #include #include #include #include #include #include "FrameWindow.H" #include #include #include // it is possible for the window to be deleted or withdrawn while // the menu is up. This will detect that case (with reasonable // reliability): static int window_deleted(Frame* c) { return c->state() != NORMAL && c->state() != ICONIC && c->state() != OTHER_DESKTOP; } static void frame_callback(Fl_Widget*, void*d) { Frame* c = (Frame*)d; if (window_deleted(c)) return; c->raise(); c->activate(2); } #if DESKTOPS // raise it but also put it on the current desktop: static void move_frame_callback(Fl_Widget*, void*d) { Frame* c = (Frame*)d; if (window_deleted(c)) return; c->desktop(Desktop::current()); c->raise(); c->activate(2); } #endif #define SCREEN_DX 1 // offset to corner of contents area #define SCREEN_W (MENU_ICON_W-2) // size of area to draw contents in #define SCREEN_H (MENU_ICON_H-2) // size of area to draw contents in #define MAX_NESTING_DEPTH 32 extern Fl_Window* Root; #if FL_MAJOR_VERSION < 2 static void frame_label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) { Frame* f = (Frame*)(o->value); if (window_deleted(f)) return; fl_draw_box(FL_THIN_DOWN_BOX, X, Y, MENU_ICON_W, MENU_ICON_H, FL_GRAY); for (Frame* c = Frame::first; c; c = c->next) { if (c->state() != UNMAPPED && (c==f || c->is_transient_for(f))) { int x = ((c->x()-Root->x())*SCREEN_W+Root->w()/2)/Root->w(); int w = (c->w()*SCREEN_W+Root->w()-1)/Root->w(); if (w > SCREEN_W) w = SCREEN_W; if (w < 3) w = 3; if (x+w > SCREEN_W) x = SCREEN_W-w; if (x < 0) x = 0; int y = ((c->y()-Root->y())*SCREEN_H+Root->h()/2)/Root->h(); int h = (c->h()*SCREEN_H+Root->h()-1)/Root->h(); if (h > SCREEN_H) h = SCREEN_H; if (h < 3) h = 3; if (y+h > SCREEN_H) y = SCREEN_H-h; if (y < 0) y = 0; fl_color(FL_FOREGROUND_COLOR); if (c->state() == ICONIC) fl_rect(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h); else fl_rectf(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h); } } fl_font(o->font, o->size); fl_color((Fl_Color)o->color); const char* l = f->label(); if (!l) l = "unnamed"; // double any ampersands to turn off the underscores: char buf[256]; if (strchr(l,'&')) { char* t = buf; while (t < buf+254 && *l) { if (*l=='&') *t++ = *l; *t++ = *l++; } *t = 0; l = buf; } fl_draw(l, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align); } static void frame_label_measure(const Fl_Label* o, int& W, int& H) { Frame* f = (Frame*)(o->value); if (window_deleted(f)) {W = MENU_ICON_W+3; H = MENU_ICON_H; return;} const char* l = f->label(); if (!l) l = "unnamed"; fl_font(o->font, o->size); fl_measure(l, W, H); W += MENU_ICON_W+3; if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH; if (H < MENU_ICON_H) H = MENU_ICON_H; } // This labeltype is used for non-frame items so the text can line // up with the icons: static void label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) { fl_font(o->font, o->size); fl_color((Fl_Color)o->color); fl_draw(o->value, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align); } static void label_measure(const Fl_Label* o, int& W, int& H) { fl_font(o->font, o->size); fl_measure(o->value, W, H); W += MENU_ICON_W+3; if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH; if (H < MENU_ICON_H) H = MENU_ICON_H; } #define FRAME_LABEL FL_FREE_LABELTYPE #define TEXT_LABEL Fl_Labeltype(FL_FREE_LABELTYPE+1) #endif // FL_MAJOR_VERSION < 2 //////////////////////////////////////////////////////////////// static void cancel_cb(Fl_Widget* w, void*) { w->window()->hide(); } #if DESKTOPS static void desktop_cb(Fl_Widget*, void* v) { Desktop::current((Desktop*)v); } static void delete_desktop_cb(Fl_Widget*, void* v) { delete (Desktop*)v; } #if ASK_FOR_NEW_DESKTOP_NAME static Fl_Input* new_desktop_input = 0; static void new_desktop_ok_cb(Fl_Widget* w, void*) { w->window()->hide(); Desktop::current(new Desktop(new_desktop_input->value(), Desktop::available_number())); } static void new_desktop_cb(Fl_Widget*, void*) { if (!new_desktop_input) { FrameWindow* w = new FrameWindow(190,90); new_desktop_input = new Fl_Input(10,30,170,25,"New desktop name:"); new_desktop_input->align(FL_ALIGN_TOP_LEFT); new_desktop_input->labelfont(FL_BOLD); Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK"); b->callback(new_desktop_ok_cb); Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel"); b2->callback(cancel_cb); w->set_non_modal(); w->end(); } char buf[120]; sprintf(buf, "Desktop %d", Desktop::available_number()); new_desktop_input->value(buf); new_desktop_input->window()->hotspot(new_desktop_input); new_desktop_input->window()->show(); } #else // !ASK_FOR_NEW_DESKTOP_NAME static void new_desktop_cb(Fl_Widget*, void*) { char buf[120]; int i = Desktop::available_number(); sprintf(buf, "Desktop %d", i); Desktop::current(new Desktop(buf, i)); } #endif #endif //////////////////////////////////////////////////////////////// static void exit_cb(Fl_Widget*, void*) { printf("exit_cb\n"); Frame::save_protocol(); exit(0); } static void logout_cb(Fl_Widget*, void*) { static FrameWindow* w = 0; if (!w) { w = new FrameWindow(190,90); Fl_Box* l = new Fl_Box(0, 0, 190, 60, "Really log out?"); l->labelfont(FL_BOLD); Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK"); b->callback(exit_cb); Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel"); b2->callback(cancel_cb); w->set_non_modal(); w->end(); } w->hotspot(w); w->show(); } //////////////////////////////////////////////////////////////// #include #include #include #if XTERM_MENU_ITEM || WMX_MENU_ITEMS static const char* xtermname = "xterm"; static void spawn_cb(Fl_Widget*, void*n) { char* name = (char*)n; // strange code thieved from 9wm to avoid leaving zombies if (fork() == 0) { if (fork() == 0) { close(ConnectionNumber(fl_display)); if (name == xtermname) execlp(name, name, "-ut", (void*)0); else execl(name, name, (void*)0); fprintf(stderr, "flwm: can't run %s, %s\n", name, strerror(errno)); XBell(fl_display, 70); exit(1); } exit(0); } wait((int *) 0); } #endif static Fl_Menu_Item other_menu_items[] = { #if XTERM_MENU_ITEM {"New xterm", 0, spawn_cb, (void*)xtermname, 0, 0, 0, MENU_FONT_SIZE}, #endif #if DESKTOPS {"New desktop", 0, new_desktop_cb, 0, 0, 0, 0, MENU_FONT_SIZE}, #endif {"Logout", 0, logout_cb, 0, 0, 0, 0, MENU_FONT_SIZE}, {0}}; #define num_other_items (sizeof(other_menu_items)/sizeof(Fl_Menu_Item)) // use this to fill in a menu location: static void init(Fl_Menu_Item& m, const char* data) { #ifdef HAVE_STYLES m.style = 0; #endif m.label(data); #if FL_MAJOR_VERSION > 2 m.flags = fltk::RAW_LABEL; #else m.flags = 0; #endif m.labeltype(FL_NORMAL_LABEL); m.shortcut(0); m.labelfont(MENU_FONT_SLOT); m.labelsize(MENU_FONT_SIZE); m.labelcolor(FL_FOREGROUND_COLOR); } #if WMX_MENU_ITEMS // wmx commands are read from ~/.wmx, // and stored null-separated here by scan_wmx_dir: // The strings are kept in this single buffer for memory efficiency and // to avoid freeing and fragmentation as the scan is done many times: // Each string has a leading character for the nesting level. static char* wmxbuffer = NULL; static int wmxbufsize = 0; static int num_wmx = 0; static time_t wmx_time = 0; static int wmx_pathlen = 0; static int scan_wmx_dir (char *path, int bufindex, int nest) { DIR* dir = opendir(path); struct stat st; int pathlen = strlen (path); if (dir) { struct dirent* ent; while ((ent=readdir(dir))) { if (ent->d_name[0] == '.') continue; strcpy(path+pathlen, ent->d_name); if (stat(path, &st) < 0) continue; int len = pathlen+strlen(ent->d_name); while (bufindex+len+2 > wmxbufsize) { // worst-case alloc needs wmxbufsize = wmxbufsize ? 2*wmxbufsize : 1024; wmxbuffer = (char*)realloc(wmxbuffer, wmxbufsize); } int start = bufindex; // remember where it started so we can delete it wmxbuffer[bufindex++] = nest; // remember nesting level strcpy(wmxbuffer+bufindex, path); bufindex += len+1; num_wmx++; if (S_ISDIR(st.st_mode) && (st.st_mode & 0555) && nest toupper(*pB)) return(1); if (toupper(*pA) < toupper(*pB)) return(-1); pA++; pB++; } if (*pA) return(1); if (*pB) return(-1); return(0); } void load_wmx() { const char* home=getenv("HOME"); if (!home) home = "."; char path[1024]; strcpy(path, home); if (path[strlen(path)-1] != '/') strcat(path, "/"); strcat(path, ".wmx/"); struct stat st; if (stat(path, &st) < 0) return; if (st.st_mtime == wmx_time) return; wmx_time = st.st_mtime; num_wmx = 0; wmx_pathlen = strlen(path); scan_wmx_dir(path, 0, 0); // Build wmxlist if (num_wmx > wmxlistsize) { if (wmxlist) delete [] wmxlist; wmxlist = new char *[num_wmx]; wmxlistsize = num_wmx; } for (int i=0; itransient_for()) if (a == c) return 1; return 0; } void ShowTabMenu(int tab) { static char beenhere; if (!beenhere) { beenhere = 1; #if FL_MAJOR_VERSION < 2 Fl::set_labeltype(FRAME_LABEL, frame_label_draw, frame_label_measure); Fl::set_labeltype(TEXT_LABEL, label_draw, label_measure); #endif if (exit_flag) { Fl_Menu_Item* m = other_menu_items+num_other_items-2; m->label("Exit"); m->callback(exit_cb); } } static Fl_Menu_Item* menu = 0; static int arraysize = 0; #if DESKTOPS int one_desktop = !Desktop::first->next; #endif // count up how many items are on the menu: int n = num_other_items; #if WMX_MENU_ITEMS load_wmx(); if (num_wmx) { n -= 1; // delete "new xterm" // count the wmx items, plus an extra for submenu terminators: int level = 0; for (int i=0; i level) level++; n++; } } #endif #if DESKTOPS // count number of items per desktop in these variables: int numsticky = 0; Desktop* d; for (d = Desktop::first; d; d = d->next) d->junk = 0; #endif // every frame contributes 1 item: Frame* c; for (c = Frame::first; c; c = c->next) { if (c->state() == UNMAPPED || c->transient_for()) continue; #if DESKTOPS if (!c->desktop()) { numsticky++; } else { c->desktop()->junk++; } #endif n++; } #if DESKTOPS if (!one_desktop) { // add the sticky "desktop": n += 2; if (!numsticky) n++; if (Desktop::current()) { n += numsticky; Desktop::current()->junk += numsticky; } // every desktop contributes menu title, null terminator, // and possible delete: for (d = Desktop::first; d; d = d->next) { n += 2; if (!d->junk) n++; } } #endif if (n > arraysize) { delete[] menu; menu = new Fl_Menu_Item[arraysize = n]; } // build the menu: n = 0; const Fl_Menu_Item* preset = 0; const Fl_Menu_Item* first_on_desk = 0; #if DESKTOPS if (one_desktop) { #endif for (c = Frame::first; c; c = c->next) { if (c->state() == UNMAPPED || c->transient_for()) continue; #if FL_MAJOR_VERSION < 2 init(menu[n],(char*)c); menu[n].labeltype(FRAME_LABEL); #else init(menu[n],c->label()); #endif menu[n].callback(frame_callback, c); if (is_active_frame(c)) preset = menu+n; n++; } if (n > 0) first_on_desk = menu; #if DESKTOPS } else for (d = Desktop::first; ; d = d->next) { // this loop adds the "sticky" desktop last, when d==0 if (d == Desktop::current()) preset = menu+n; init(menu[n], d ? d->name() : "Sticky"); menu[n].callback(desktop_cb, d); menu[n].flags = FL_SUBMENU; n++; if (d && !d->junk) { init(menu[n],"delete this desktop"); menu[n].callback(delete_desktop_cb, d); n++; } else if (!d && !numsticky) { init(menu[n],"(empty)"); menu[n].callback_ = 0; menu[n].deactivate(); n++; } else { if (d == Desktop::current()) first_on_desk = menu+n; for (c = Frame::first; c; c = c->next) { if (c->state() == UNMAPPED || c->transient_for()) continue; if (c->desktop() == d || !c->desktop() && d == Desktop::current()) { init(menu[n],(char*)c); #if FL_MAJOR_VERSION < 2 init(menu[n],(char*)c); menu[n].labeltype(FRAME_LABEL); #else init(menu[n],c->label()); #endif menu[n].callback(d == Desktop::current() ? frame_callback : move_frame_callback, c); if (d == Desktop::current() && is_active_frame(c)) preset = menu+n; n++; } } } menu[n].label(0); n++; // terminator for submenu if (!d) break; } #endif // For ALT+Tab, move the selection forward or backward: if (tab > 0 && first_on_desk) { if (!preset) preset = first_on_desk; else { preset++; if (!preset->label() || preset->callback_ != frame_callback) preset = first_on_desk; } } else if (tab < 0 && first_on_desk) { if (preset && preset != first_on_desk) preset--; else { // go to end of menu preset = first_on_desk; while (preset[1].label() && preset[1].callback_ == frame_callback) preset++; } } #if WMX_MENU_ITEMS // put wmx-style commands above that: if (num_wmx > 0) { char* cmd; int pathlen[MAX_NESTING_DEPTH]; int level = 0; pathlen[0] = wmx_pathlen; for (int i = 0; i < num_wmx; i++) { cmd = wmxlist[i]+1; // skip level number init(menu[n], cmd+pathlen[level]); menu[n].callback(spawn_cb, cmd); #if FL_MAJOR_VERSION < 2 #if DESKTOPS if (one_desktop) #endif if (!level) menu[n].labeltype(TEXT_LABEL); #endif int nextlev = (i==num_wmx-1) ? 0 : wmxlist[i+1][0]; if (nextlev < level) { // add null terminators to turn off levels for (; level>nextlev; level--) init(menu[++n], 0); } else if (nextlev > level) { // This should be made a submenu pathlen[++level] = strlen(cmd)+1; // extra for next trailing / menu[n].flags = FL_SUBMENU; menu[n].callback((Fl_Callback*)0); } n++; } } // put the fixed menu items at the bottom: #if XTERM_MENU_ITEM if (num_wmx) // if wmx commands, delete the built-in xterm item: memcpy(menu+n, other_menu_items+1, sizeof(other_menu_items)-sizeof(Fl_Menu_Item)); else #endif #endif memcpy(menu+n, other_menu_items, sizeof(other_menu_items)); #if FL_MAJOR_VERSION < 2 #if DESKTOPS if (one_desktop) #endif // fix the menus items so they are indented to align with window names: while (menu[n].label()) menu[n++].labeltype(TEXT_LABEL); #endif const Fl_Menu_Item* picked = menu->popup(Fl::event_x(), Fl::event_y(), 0, preset); #if FL_MAJOR_VERSION < 2 if (picked && picked->callback()) picked->do_callback(0); #endif } void ShowMenu() {ShowTabMenu(0);} flwm-1.02+cvs20080422/README0000644000175000017500000000765207270601040012464 0ustar memeflwm Version 0.25 ---------------------------------------------------------------- How to compile flwm: ---------------------------------------------------------------- You need fltk. If you do not have it yet, download it from http://www.fltk.org, and compile and install it. To customize flwm (for instance to turn on click-to-type), edit the config.h file. Type "./configure" (not necessary if you have gmake) Type "make" Become superuser and type "make install" If you wish to edit the code, type "make depend" ---------------------------------------------------------------- How to run flwm: ---------------------------------------------------------------- To run flwm as your login script, you need to create or replace ~/.xinitrc or ~/.xsession (or both). Newer Linux systems with a login panel use .xsession, older systems where X was started after login use .xinitrc. You may also have to pick "default" from the "type of session" popup in your login window. The .xinitrc or .xsession file should look like this: #!/bin/sh xsetroot -solid \#006060 xrdb .Xresources # xset, xmodmap, other configuration programs flwm & WindowManager=$! # xterm, other automatically-launched programs wait $WindowManager ALLOWING THE WINDOW MANAGER TO EXIT W/O LOGOUT: That is the most user-friendly but it logs you out when flwm exits, which means it logs out if flwm crashes (:-)) and you cannot switch window managers. Another possibility is to run another program last so flwm can exit, by putting lines like this at the end: /usr/local/bin/flwm -x & exec rxvt -geometry 80x11+8-8 -C -T "Ctrl-D_to_logout" The -x tells flwm to put "exit" on the menu rather than "logout". REDHAT USERS: You may want to run the program "./flwm_wmconfig". This will read RedHat's window manager menu configuration files and build an initial .wmx directory so you have a large set of menu items that run programs. SGI IRIX: You need to edit the file ~/.xsession instead of ~/.xinitrc. SGI's version of XDM has a nice feature so that the window manager can still have a logout command, but you are not logged out if it crashes. This is done by running the programs "reaper" and "endsession", as in this sample .xsession file: #! /bin/sh xsetroot -solid \#004040 xrdb .Xresources reaper flwm -x & xwsh -console -t console -iconic & Also create the file "~/.wmx/Logout" with these contents: #! /bin/sh endsession The result will be that flwm has a menu itme "Logout" that logs you out. ---------------------------------------------------------------- Usage: ---------------------------------------------------------------- Type "man flwm" for the manual page. ---------------------------------------------------------------- Acknoledgements ---------------------------------------------------------------- This program was inspired by and much code copied from the "wm2" window manager by Chris Cannam Code contributions by Steve );Hara-Smith ---------------------------------------------------------------- Copyright (C) 1998-1999 Bill Spitzak ---------------------------------------------------------------- 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 library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. Written by Bill Spitzak spitzak@d2.com ---------------------------------------------------------------- END ---------------------------------------------------------------- flwm-1.02+cvs20080422/Rotated.C0000644000175000017500000003142510313440237013306 0ustar meme// Rotated text drawing with X. // Original code: // Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) */ // // Modifications for fltk: // Copyright (c) 1997 Bill Spitzak (spitzak@d2.com) // Modifications are to draw using the current fl_font. All fonts // used are cached in local structures. This can get real expensive, // use " /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ // if not defined then portions not used by flwm are included: #define FLWM 1 /* ********************************************************************** */ #include #if FL_MAJOR_VERSION < 2 # define XWindow Window #endif #include #include "Rotated.H" #include #include #include struct BitmapStruct { int bit_w; int bit_h; Pixmap bm; }; struct XRotCharStruct { int ascent; int descent; int lbearing; int rbearing; int width; BitmapStruct glyph; }; struct XRotFontStruct { int dir; int height; int max_ascent; int max_descent; int max_char; int min_char; XFontStruct* xfontstruct; XRotCharStruct per_char[256]; }; /* *** Load the rotated version of a given font *** */ static XRotFontStruct* XRotLoadFont(Display *dpy, XFontStruct* fontstruct, int dir) { char val; XImage *I1, *I2; Pixmap canvas; XWindow root; int screen; GC font_gc; char text[3];/*, errstr[300];*/ XRotFontStruct *rotfont; int ichar, i, j, index, boxlen = 60; int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len; int min_char, max_char; unsigned char *vertdata, *bitdata; int ascent, descent, lbearing, rbearing; int on = 1, off = 0; /* useful macros ... */ screen = DefaultScreen(dpy); root = DefaultRootWindow(dpy); /* create the depth 1 canvas bitmap ... */ canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1); /* create a GC ... */ font_gc = XCreateGC(dpy, canvas, 0, 0); XSetBackground(dpy, font_gc, off); XSetFont(dpy, font_gc, fontstruct->fid); /* allocate space for rotated font ... */ rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct)); /* determine which characters are defined in font ... */ min_char = fontstruct->min_char_or_byte2; if (min_char<0) min_char = 0; rotfont->min_char = min_char; max_char = fontstruct->max_char_or_byte2; if (max_char>255) max_char = 255; rotfont->max_char = max_char; /* some overall font data ... */ rotfont->dir = dir; rotfont->max_ascent = fontstruct->max_bounds.ascent; rotfont->max_descent = fontstruct->max_bounds.descent; rotfont->height = rotfont->max_ascent+rotfont->max_descent; rotfont->xfontstruct = fontstruct; /* remember xfontstruct for `normal' text ... */ if (dir != 0) { /* font needs rotation ... */ /* loop through each character ... */ for (ichar = min_char; ichar <= max_char; ichar++) { index = ichar-fontstruct->min_char_or_byte2; XCharStruct* charstruct; if (fontstruct->per_char) charstruct = fontstruct->per_char+index; else charstruct = &fontstruct->min_bounds; /* per char dimensions ... */ ascent = rotfont->per_char[ichar].ascent = charstruct->ascent; descent = rotfont->per_char[ichar].descent = charstruct->descent; lbearing = rotfont->per_char[ichar].lbearing = charstruct->lbearing; rbearing = rotfont->per_char[ichar].rbearing = charstruct->rbearing; rotfont->per_char[ichar].width = charstruct->width; /* some space chars have zero body, but a bitmap can't have ... */ if (!ascent && !descent) ascent = rotfont->per_char[ichar].ascent = 1; if (!lbearing && !rbearing) rbearing = rotfont->per_char[ichar].rbearing = 1; /* glyph width and height when vertical ... */ vert_w = rbearing-lbearing; vert_h = ascent+descent; /* width in bytes ... */ vert_len = (vert_w-1)/8+1; XSetForeground(dpy, font_gc, off); XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen); /* draw the character centre top right on canvas ... */ sprintf(text, "%c", ichar); XSetForeground(dpy, font_gc, on); XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing, boxlen/2 - descent, text, 1); /* reserve memory for first XImage ... */ vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h)); /* create the XImage ... */ I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)vertdata, vert_w, vert_h, 8, 0); // if (I1 == NULL) ... do something here I1->byte_order = I1->bitmap_bit_order = MSBFirst; /* extract character from canvas ... */ XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h, vert_w, vert_h, 1, XYPixmap, I1, 0, 0); I1->format = XYBitmap; /* width, height of rotated character ... */ if (dir == 2) { bit_w = vert_w; bit_h = vert_h; } else { bit_w = vert_h; bit_h = vert_w; } /* width in bytes ... */ bit_len = (bit_w-1)/8 + 1; rotfont->per_char[ichar].glyph.bit_w = bit_w; rotfont->per_char[ichar].glyph.bit_h = bit_h; /* reserve memory for the rotated image ... */ bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1); /* create the image ... */ I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)bitdata, bit_w, bit_h, 8, 0); // if (I2 == NULL) ... error I2->byte_order = I2->bitmap_bit_order = MSBFirst; /* map vertical data to rotated character ... */ for (j = 0; j < bit_h; j++) { for (i = 0; i < bit_w; i++) { /* map bits ... */ if (dir == 1) val = vertdata[i*vert_len + (vert_w-j-1)/8] & (128>>((vert_w-j-1)%8)); else if (dir == 2) val = vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8)); else val = vertdata[(vert_h-i-1)*vert_len + j/8] & (128>>(j%8)); if (val) bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] | (128>>(i%8)); } } /* create this character's bitmap ... */ rotfont->per_char[ichar].glyph.bm = XCreatePixmap(dpy, root, bit_w, bit_h, 1); /* put the image into the bitmap ... */ XPutImage(dpy, rotfont->per_char[ichar].glyph.bm, font_gc, I2, 0, 0, 0, 0, bit_w, bit_h); /* free the image and data ... */ XDestroyImage(I1); XDestroyImage(I2); /* free((char *)bitdata); -- XDestroyImage does this free((char *)vertdata);*/ } } for (ichar = 0; ichar < min_char; ichar++) rotfont->per_char[ichar] = rotfont->per_char[int('?')]; for (ichar = max_char+1; ichar < 256; ichar++) rotfont->per_char[ichar] = rotfont->per_char[int('?')]; /* free pixmap and GC ... */ XFreePixmap(dpy, canvas); XFreeGC(dpy, font_gc); return rotfont; } /* *** Free the resources associated with a rotated font *** */ static void XRotUnloadFont(Display *dpy, XRotFontStruct *rotfont) { int ichar; if (rotfont->dir != 0) { /* loop through each character, freeing its pixmap ... */ for (ichar = rotfont->min_char; ichar <= rotfont->max_char; ichar++) XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm); } /* rotfont should never be referenced again ... */ free((char *)rotfont); } /* ---------------------------------------------------------------------- */ /* *** A front end to XRotPaintString : mimics XDrawString *** */ static void XRotDrawString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable, GC gc, int x, int y, const char *str, int len) { int i, xp, yp, dir, ichar; if (str == NULL || len<1) return; dir = rotfont->dir; /* a horizontal string is easy ... */ if (dir == 0) { XSetFont(dpy, gc, rotfont->xfontstruct->fid); XDrawString(dpy, drawable, gc, x, y, str, len); return; } /* vertical or upside down ... */ XSetFillStyle(dpy, gc, FillStippled); /* loop through each character in string ... */ for (i = 0; iper_char[ichar].ascent; yp = y-rotfont->per_char[ichar].rbearing; } else if (dir == 2) { xp = x-rotfont->per_char[ichar].rbearing; yp = y-rotfont->per_char[ichar].descent+1; } else { xp = x-rotfont->per_char[ichar].descent+1; yp = y+rotfont->per_char[ichar].lbearing; } /* draw the glyph ... */ XSetStipple(dpy, gc, rotfont->per_char[ichar].glyph.bm); XSetTSOrigin(dpy, gc, xp, yp); XFillRectangle(dpy, drawable, gc, xp, yp, rotfont->per_char[ichar].glyph.bit_w, rotfont->per_char[ichar].glyph.bit_h); /* advance position ... */ if (dir == 1) y -= rotfont->per_char[ichar].width; else if (dir == 2) x -= rotfont->per_char[ichar].width; else y += rotfont->per_char[ichar].width; } XSetFillStyle(dpy, gc, FillSolid); } #ifndef FLWM /* *** Return the width of a string *** */ static int XRotTextWidth(XRotFontStruct *rotfont, const char *str, int len) { int i, width = 0, ichar; if (str == NULL) return 0; if (rotfont->dir == 0) width = XTextWidth(rotfont->xfontstruct, str, strlen(str)); else for (i = 0; iper_char[((unsigned char*)str)[i]].width; } return width; } #endif /* ---------------------------------------------------------------------- */ // the public functions use the fltk global variables for font & gc: static XRotFontStruct* font; static void setrotfont(int angle) { /* make angle positive ... */ if (angle < 0) do angle += 360; while (angle < 0); /* get nearest vertical or horizontal direction ... */ int dir = ((angle+45)/90)%4; if (font) { if (font->xfontstruct == fl_xfont && font->dir == dir) return; XRotUnloadFont(fl_display, font); } font = XRotLoadFont(fl_display, fl_xfont, dir); } void draw_rotated(const char* text, int n, int x, int y, int angle) { if (!text || !*text) return; setrotfont(angle); XRotDrawString(fl_display, font, fl_window, fl_gc, x, y, text, n); } #if !defined(FLWM) || FL_MAJOR_VERSION>=2 void draw_rotated(const char* text, int x, int y, int angle) { if (!text || !*text) return; draw_rotated(text, strlen(text), x, y, angle); } #endif static void draw_rot90(const char* str, int n, int x, int y) { draw_rotated(str, n, y, -x, 90); } void draw_rotated90( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { if (!str || !*str) return; if (w && h && !fl_not_clipped(x, y, w, h)) return; if (align & FL_ALIGN_CLIP) fl_clip(x, y, w, h); #if FL_MAJOR_VERSION>1 setrotfont(90); int a = font->xfontstruct->ascent; int d = font->xfontstruct->descent; XRotDrawString(fl_display, font, fl_window, fl_gc, x+(w+a-d+1)/2, y+h, str, strlen(str)); #else int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_TOP; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_RIGHT; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_LEFT; fl_draw(str, -(y+h), x, h, w, (Fl_Align)a1, draw_rot90); #endif if (align & FL_ALIGN_CLIP) fl_pop_clip(); } #ifndef FLWM static void draw_rot180(const char* str, int n, int x, int y) { draw_rotated(str, n, -x, -y, 180); } void draw_rotated180( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_RIGHT; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_LEFT; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_TOP; fl_draw(str, -(x+w), -(y+h), w, h, (Fl_Align)a1, draw_rot180); } static void draw_rot270(const char* str, int n, int x, int y) { draw_rotated(str, n, -y, x, 270); } void draw_rotated270( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_TOP; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_LEFT; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_RIGHT; fl_draw(str, y, -(x+w), h, w, (Fl_Align)a1, draw_rot270); } #endif flwm-1.02+cvs20080422/Rotated.H0000644000175000017500000000112407040736155013316 0ustar meme// Rotated text drawing with X. // Original code: // Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) */ // // Modifications for fltk: // Copyright (c) 1997 Bill Spitzak (spitzak@d2.com) #ifndef Rotated_H #define Rotated_H void draw_rotated(const char* text, int n, int x, int y, int angle); void draw_rotated(const char* text, int x, int y, int angle); void draw_rotated90(const char*, int x, int y, int w, int h, Fl_Align); void draw_rotated270(const char*, int x, int y, int w, int h, Fl_Align); void draw_rotated180(const char*, int x, int y, int w, int h, Fl_Align); #endif flwm-1.02+cvs20080422/config.h0000644000175000017500000001345710132424626013226 0ustar meme// config.h // You can edit these symbols to change the behavior & appearance of flwm. // Turning off features will make flwm smaller too! //////////////////////////////////////////////////////////////// // BEHAVIOR: // Turn this on for click-to-type (rather than point-to-type). // On: clicking on the window gives it focus // Off: pointing at the window gives it the focus. #define CLICK_TO_TYPE 0 // Most window managers consider this and click-to-type equivalent. // On: clicking anywhere on window raises it // Off: you have to click on the border to raise window #define CLICK_RAISES CLICK_TO_TYPE // For point-to-type, sticky focus means you don't lose the focus // until you move the cursor to another window that wants focus. // If this is off you lose focus as soon as the cursor goes outside // the window (such as to the desktop): #define STICKY_FOCUS 1 // For point-to-type, after this many seconds the window is raised, // nothing is done if this is not defined: //#define AUTO_RAISE 0.5 // Perform "smart" autoplacement. // New windows are put at positions where they cover as few existing windows // as possible. A brute force algorithm is used, so it consumes quite a bit // of CPU time. #define SMART_PLACEMENT 1 // set this to zero to remove the multiple-desktop code. This will // make flwm about 20K smaller #define DESKTOPS 1 // set this to zero for "new desktop" to just create one without asking // for a name. This saves 12K or so of fltk input field code: #define ASK_FOR_NEW_DESKTOP_NAME 1 // wm2 has no close box, for good reasons. Unfortunately too many programs // assume there is one and have no other way to close a window. For a more // "pure" implementation set this to zero: #define CLOSE_BOX 1 // set this to zero to remove the minimize/window-shade button: #define MINIMIZE_BOX 1 // If this is false the minimize button only changes the width of the // window, so it acts like a Mac window shade. This was the original // behavior, the new version makes it smaller vertically so it is just // big enough to show the window title: #define MINIMIZE_HEIGHT 1 // Read links from ~/.wmx to make menu items to run programs: #define WMX_MENU_ITEMS 1 // Menu item to run a new xterm (if no wmx items found): #define XTERM_MENU_ITEM 1 // Hotkeys (see Hotkeys.C for exactly what they do): #define STANDARD_HOTKEYS 1 // alt+esc, alt+tab, alt+shift+tab #define KWM_HOTKEYS 1 // ctrl+tab and ctrl+Fn for desktop switching #define CDE_HOTKEYS defined(__sgi) // alt+fn do actions like raise/lower/close #define WMX_HOTKEYS 1 // alt+up/down/enter/delete #define WMX_DESK_HOTKEYS 0 // alt+left/right (conflict with Netscape) #define DESKTOP_HOTKEYS 0 // alt+fn goes to desktop n //////////////////////////////////////////////////////////////// // APPEARANCE: // Color for active window title bar (also for selected menu items): // If not defined, no active window title highlighting is done. #if CLICK_TO_TYPE #define ACTIVE_COLOR 0xF0F0F0 #endif //#define ACTIVE_COLOR 0x000080 // thickness of the border edge on each side (includes XBORDER): #define LEFT 3 #define RIGHT 4 #define TOP 3 #define BOTTOM 4 // font for titles (if not set, helvetica bold is used): // If this name is specific enough the font size is ignored. //#define TITLE_FONT "-*-helvetica-bold-r-normal--*" #define TITLE_FONT_SIZE 12 // thickness of title bar (LEFT is added to it): #define TITLE_WIDTH (TITLE_FONT_SIZE+3) // size & position of buttons (must fit in title bar): #define BUTTON_W TITLE_WIDTH #define BUTTON_H BUTTON_W #define BUTTON_LEFT LEFT #define BUTTON_TOP TOP #define BUTTON_BOTTOM BOTTOM // how many pixels from edge for resize handle: #define RESIZE_EDGE 5 // set this to zero to disable resizing by grabbing left edge: #define RESIZE_LEFT 1 // must drag window this far off screen to snap the border off the screen: #define EDGE_SNAP 50 // must drag window this far off screen to actually move it off screen: #define SCREEN_SNAP 100 // button decorations: #define CLOSE_X 1 // windoze-style X in close button #define CLOSE_HITTITE_LIGHTNING 0 // The ancient Hittite symbol for lightning #define ICONIZE_BOX 0 // small box in iconize button #define MINIMIZE_ARROW 0 // minimize button draws a <- rather than | // default colors for cursor: #ifdef __sgi #define CURSOR_FG_COLOR 0xff0000 #else #define CURSOR_FG_COLOR 0x000000 #endif #define CURSOR_BG_COLOR 0xffffff // "Clock in the title bar" code contributed by Kevin Quick // : // Add a clock to the active window's title bar using specified // strftime fmt Note: in keeping with the minimalistic, fast, and // small philosophy of the flwm, the clock will only be updated // once/minute so any display of seconds is frivolous. //#define SHOW_CLOCK "%I:%M %p %Z" // We also support the concept of a clock alarm. The alarm is // triggered by delivering SIGALRM to flwm and cleared by delivering // SIGCONT to flwm. When the alarm is active, the foreground and // background colors of the clock display are determined by the // following settings. (The following are unused if SHOW_CLOCK is not // defined). #define ALARM_FG_COLOR 0x00ffff #define ALARM_BG_COLOR 0xff0000 //////////////////////////////////////////////////////////////// // MENU APPEARANCE: #define MAX_MENU_WIDTH 300 // size of the little pictures in the menu: #define MENU_ICON_W 18 #define MENU_ICON_H 15 // font to use in menus (if not set helvetica is used): //#define MENU_FONT "-*-helvetica-medium-r-normal--*" #define MENU_FONT_SIZE 12 //////////////////////////////////////////////////////////////// // You probably don't want to change any of these: #ifdef TITLE_FONT #define TITLE_FONT_SLOT FL_FREE_FONT #else #define TITLE_FONT_SLOT FL_BOLD #endif #ifdef MENU_FONT #define MENU_FONT_SLOT Fl_Font(FL_FREE_FONT+1) #else #define MENU_FONT_SLOT FL_HELVETICA #endif #define CURSOR_BG_SLOT Fl_Color(30) #define CURSOR_FG_SLOT Fl_Color(31) flwm-1.02+cvs20080422/configure.in0000644000175000017500000000321510654364646014126 0ustar memednl# -*- sh -*- dnl# the "configure" script is made from this by running GNU "autoconf" AC_INIT(Frame.C) AC_PROG_CC AC_PROG_CXX AC_PROG_INSTALL AC_PATH_XTRA echo "Ignoring libraries \"$X_PRE_LIBS\" requested by configure." dnl# LIBS="$LIBS$X_LIBS$X_PRE_LIBS" LIBS="$LIBS$X_LIBS" AC_ARG_ENABLE(fltk2,[ --enable-fltk2 use fltk2 (default=no)]) if test x$enable_fltk2 = xyes; then LIBS="-lfltk2 -lXft -lXinerama -lXi $LIBS" CXXFLAGS="$CXXFLAGS -I/usr/local/include/fltk/compat" else LIBS="-lfltk -lXft -lXinerama $LIBS" fi MAKEDEPEND="\$(CXX) -M" dnl# add warnings and optimization to compiler switches: dnl# do this last so messing with switches does not break tests if test -n "$GXX"; then # GNU C compiler # -Wno-return-type is necessary for Xlib header files on many systems: CFLAGS="$CFLAGS -Wall -Wno-return-type $X_CFLAGS" CXXFLAGS="$CXXFLAGS -Wall -Wno-return-type $X_CFLAGS" else if test "`(uname) 2>/dev/null`" = IRIX; then if expr "`(uname -r)`" \>= 6.2; then # turn on new "n32" Irix compiler: CXX="CC -n32" CC="cc -n32" LD="ld -n32" # but -M is broken so use old compiler: MAKEDEPEND="CC -M" # -woff 3322 is necessary due to errors in Xlib headers on IRIX CFLAGS="$CFLAGS -fullwarn -O2 $X_CFLAGS" CXXFLAGS="$CXXFLAGS -fullwarn -woff 3322 -O2 $X_CFLAGS" else # old Irix compiler: CFLAGS="$CFLAGS -O2 $X_CFLAGS" CXXFLAGS="$CXXFLAGS +w +pp -O2 $X_CFLAGS" fi else # generic C compiler: CFLAGS="$CFLAGS $X_CFLAGS" CXXFLAGS="$CXXFLAGS $X_CFLAGS" fi fi AC_SUBST(MAKEDEPEND) dnl# AC_CONFIG_HEADER(config.h:configh.in) AC_OUTPUT(makeinclude) dnl# end of configure.in flwm-1.02+cvs20080422/flwm.10000644000175000017500000001731110450700453012626 0ustar meme.\"Man page for flwm, by Bill Spitzak. .TH flwm 1 "15 May 1999" .SH NAME \fIflwm\fR - The Fast Light Window Manager .SH SYNOPSIS .B flwm [-d[isplay] host:n.n] [-g[eometry] WxH+X+Y] [-fg color] [-bg color] [-bg2 color] .SH DESCRIPTION .I flwm is a very small and fast X window manager, featuring .I no icons and "sideways" title bars. .SH .xinitrc / .xsession To run flwm as your login script, you need to create or replace ~/.xinitrc or ~/.xsession (or both). Newer Linux systems with a login panel use .xsession, older systems where X was started after login use .xinitrc. You may also have to pick "default" from the "type of session" popup in your login window. The .xinitrc or .xsession file should look like this: .nf #!/bin/sh xsetroot -solid \\#006060 xrdb .Xresources # xset, xmodmap, other configuration programs flwm & WindowManager=$! # xterm, other automatically-launched programs wait $WindowManager .fi .SH SWITCHES .B -d[isplay] host:#.# Sets the display and screen for flwm to manage .B -v[isual] # Visual number to use (probably only works for non-color-mapped ones) .B -g[eometry] WxH+X+Y Flwm will act as though the screen is only the specified area. It will constrain initial window positions to this area and stop them at the edges when dragging them around. This can be used to surround the screen with fixed "toolbars" that are never covered by windows. These toolbars must be created by a program using override-redirect so that flwm does not try to move them. .B -m[aximum] WxH Set the size of windows when the maximize buttons are pushed. Normally this is the size of the screen. This is useful for XFree86 servers that are run with a smaller screen than display memory. .B -x The menu will say "Exit" instead of "Logout" and will not ask for confirmation. This is a good idea if you are running flwm in some other way than with exec at the end of .xinitrc, since it won't log you out then. .B -fg color, -bg color Set the label color and the color of the window frames and the menu. .B -c[ursor] # What cursor to use on the desktop (you will have to experiment to find out what each number means) .B -cfg color, -cbg color Colors for the desktop and window resizing cursors In addition to these switches there is much customization that can be done by editing the config.h file in the source code and recompiling. GCC is your friend. .SH MENU ITEMS Flwm can launch programs from its menu. This is controlled by files in the directory .B ~/.wmx (this was chosen to be compatible with wmx and wm2). Each executable file in ~/.wmx is a program to run. Usually these are symbolic links to the real program or very short shell scripts. Each subdirectory creates a child menu so you can build a hierarchy (up to 10 deep). Cut and paste the following lines you your shell to create some example files: .nf mkdir ~/.wmx ln -s /usr/bin/gimp ~/.wmx/"The Gimp" cat << EOF > ~/.wmx/"Terminal" #! /bin/sh /usr/local/bin/rxvt -ut EOF chmod +x !* .fi RedHat users can run the program .B flwm_wmconfig to read the /etc/X11/wmconfig directory and produce an initial set of menu items. .SH MOUSE USAGE .B Left-click on a window border raises window. .B Left-drag will move the window when in the title bar, and will resize it in the edges. If the window cannot be resized then it will always move the window. What it will do is indicated by the cursor shape. .B Middle-click on a window border lowers it to bottom. .B Middle-drag anywhere on window border will move the window. When you move a window it will stop at the edges of the screen. Dragging about 150 pixels further will unstick it and let you drag it off the screen. .B Right-click on a window border pops up the menu. .B Any button on the desktop will pop up the menu. .SH BUTTONS The empty button "iconizes" the window: it will completely vanish. To get it back use the menu. The vertical-bar button "shades" (or "Venetian blinds"?) the window. Click it again to restore the window. You can also resize the shaded window to a new height or "open" it by resizing horizontally. The two buttons below it toggle maximum height and/or maximum width. The X button at the bottom closes the window. .SH MENU .B Right-click on window border, or .B any-click on the desktop, or typing .B Alt+Esc or .B Alt+Tab or .B Alt+Shift+Tab will pop up the menu. Releasing Alt will pick the current menu item. This makes flwm work very much (exactly?) like the Windows 95 shortcuts. Each main window is a menu item. If the window is "iconized" the little picture shows an open rectangle, otherwise it shows a filled rectangle. Picking a menu item deiconizes and raises that window and warps the pointer so it is current. .B New desktop asks for a name of a new desktop and makes it current. The desktop will initially be empty (except for sticky items). To move windows to the current desktop, pop up the menu and pick windows off of other desktops (if using the keyboard, use left arrow to go to the desktop names, move up and down to the other desktop, and use right arrow to enter that desktop). The window will be moved from the other desktop to the current one. To switch to another desktop, pick the title of the desktop (if using the keyboard, use left arrow to go to the desktop names, move up and down to the other desktop). If a desktop is empty you can delete it. Its sub menu will show .B delete this desktop. Pick that and the desktop is gone. .B Sticky is a special "desktop": windows on it appear on all desktops. To make a window "sticky" switch to the Sticky desktop and pick the window off its current desktop (thus "moving" it to the Sticky desktop). To "unstick" a window go to another desktop and pick the window off the sticky desktop menu. .B New xterm will run a new xterm on the current desktop. Useful if you accidentally close everything. This item does not appear if a ~/.wmx directory exists. .B Logout will ask for confirmation and if so flwm will exit. .B Exit will exit flwm without confirmation. This item will appear if flwm was run with the -x switch. .SH HOT KEYS These are the defaults, the hot keys may be different depending on how flwm was compiled: .B Alt+Escape Pops up the menu with the current window preselected .B Alt+Tab Pops up the menu with the next window preselected .B Alt+Shift+Tab Pops up the menu with the previous window preselected .B Ctrl+Tab Switch to the next desktop. .B Ctrl+Shift+Tab Switch to the previous desktop. .B Ctrl+Function key Switch to desktop N. .B Alt+Up Raise the current window. .B Alt+Down Lower the current window. .B Alt+Delete Close the current window (same as clicking close box). .B Alt+Enter "Iconizes" (hides) the current window. .SH BUGS It is impossible to move windows smaller than 100 pixels off the screen. Only obeys "keep aspect" if the aspect ratio is 1x1. .SH ACKNOWLEDGEMENTS This program was inspired by and much code copied from the "wm2" window manager by Chris Cannam Thanks to Ron Koerner for the recursive .wmx directory reading code. .SH COPYRIGHT Copyright (C) 1999 Bill Spitzak 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 library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. .SH AUTHORS Written by Bill Spitzak spitzak@d2.com flwm-1.02+cvs20080422/flwm_wmconfig0000755000175000017500000000307107270601040014357 0ustar meme#! /usr/bin/tcl # flwm_wmconfig reads the RedHat "/etc/X11/wmconfig" directory (and # the ~/.wmconfig directory) and builds a ~/.wmx directory from it so # that you have a big complex menu in flwm! set count 0 proc read_wmfile {fname} { global count global env if [catch {set f [open $fname]} message] { puts $message } else { set group "" set name "" set exec "" while {[gets $f list]>=0} { set n 0 catch {set n [llength $list]} if $n<3 continue set tag [lindex $list 1] set value [lrange $list 2 1000] if [llength $value]==1 {set value [lindex $value 0]} if {$tag=="group"} {set group $value} if {$tag=="name"} {set name $value} if {$tag=="exec"} {set exec $value} } close $f if {$group=="" || $name == "" || $exec == ""} { puts "$fname is missing necessary data" return } set dir $env(HOME)/.wmx/$group set exec [string trimright $exec "& "] catch {mkdir [list $dir]} if [llength $exec]==1 { if [catch {set command [exec which $exec]}] { puts "$fname : can't find the program $exec" return } else { catch {unlink [list $dir/$name]} link -sym $command $dir/$name } } else { set f [open $dir/$name "w"] puts $f "#! /bin/sh" puts $f "exec $exec" close $f chmod +x [list $dir/$name] } incr count } } if ![catch {set l [glob /etc/X11/wmconfig/*]}] { foreach f $l {read_wmfile $f} } if ![catch {set l [glob $env(HOME)/.wmconfig/*]}] { foreach f $l {read_wmfile $f} } if !$count { error "No files found in /etc/X11/wmconfig or ~/.wmconfig" } flwm-1.02+cvs20080422/install-sh0000755000175000017500000001124407270601040013600 0ustar meme#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 flwm-1.02+cvs20080422/main.C0000644000175000017500000003022410450700453012625 0ustar meme// Define "TEST" and it will compile to make a single fake window so // you can test the window controls. //#define TEST 1 #include "Frame.H" #include #include #include #include #include #include "config.h" #ifdef SHOW_CLOCK #include #include #endif //////////////////////////////////////////////////////////////// static const char* program_name; static int initializing; static int xerror_handler(Display* d, XErrorEvent* e) { if (initializing && (e->request_code == X_ChangeWindowAttributes) && e->error_code == BadAccess) Fl::fatal("Another window manager is running. You must exit it before running %s.", program_name); #ifndef DEBUG if (e->error_code == BadWindow) return 0; if (e->error_code == BadColor) return 0; #endif char buf1[128], buf2[128]; sprintf(buf1, "XRequest.%d", e->request_code); XGetErrorDatabaseText(d,"",buf1,buf1,buf2,128); XGetErrorText(d, e->error_code, buf1, 128); Fl::warning("%s: %s: %s 0x%lx", program_name, buf2, buf1, e->resourceid); return 0; } //////////////////////////////////////////////////////////////// // The Fl_Root class looks like a window to fltk but is actually the // screen's root window. This is done by using set_xid to "show" it // rather than have fltk create the window. class Fl_Root : public Fl_Window { int handle(int); public: Fl_Root() : Fl_Window(0,0,Fl::w(),Fl::h()) { #if FL_MAJOR_VERSION > 1 clear_double_buffer(); #endif } void show() { if (!shown()) Fl_X::set_xid(this, RootWindow(fl_display, fl_screen)); } void flush() {} }; Fl_Window *Root; extern void ShowMenu(); extern int Handle_Hotkey(); extern void Grab_Hotkeys(); int Fl_Root::handle(int e) { if (e == FL_PUSH) { ShowMenu(); return 1; } return 0; } #if CLICK_RAISES || CLICK_TO_TYPE extern void click_raise(Frame*); #endif // fltk calls this for any events it does not understand: static int flwm_event_handler(int e) { if (!e) { // XEvent that fltk did not understand. XWindow window = fl_xevent->xany.window; // unfortunately most of the redirect events put the interesting // window id in a different place: switch (fl_xevent->type) { case CirculateNotify: case CirculateRequest: case ConfigureNotify: case ConfigureRequest: case CreateNotify: case DestroyNotify: case GravityNotify: case MapNotify: case MapRequest: case ReparentNotify: case UnmapNotify: window = fl_xevent->xmaprequest.window; } for (Frame* c = Frame::first; c; c = c->next) if (c->window() == window || fl_xid(c) == window) #if CLICK_RAISES || CLICK_TO_TYPE if (fl_xevent->type == ButtonPress) {click_raise(c); return 1;} else #endif return c->handle(fl_xevent); switch (fl_xevent->type) { case ButtonPress: printf("got a button press in main\n"); return 0; case ConfigureRequest: { const XConfigureRequestEvent *e = &(fl_xevent->xconfigurerequest); XConfigureWindow(fl_display, e->window, e->value_mask&~(CWSibling|CWStackMode), (XWindowChanges*)&(e->x)); return 1;} case MapRequest: { const XMapRequestEvent* e = &(fl_xevent->xmaprequest); (void)new Frame(e->window); return 1;} #if FL_MAJOR_VERSION<2 // this was needed for *some* earlier versions of fltk case KeyRelease: if (!Fl::grab()) return 0; Fl::e_keysym = XKeycodeToKeysym(fl_display, fl_xevent->xkey.keycode, 0); goto KEYUP; #endif } } else if (e == FL_KEYUP) { #if FL_MAJOR_VERSION<2 KEYUP: #endif if (!Fl::grab()) return 0; // when alt key released, pretend they hit enter & pick menu item if (Fl::event_key()==FL_Alt_L || Fl::event_key()==FL_Alt_R) { Fl::e_keysym = FL_Enter; #if FL_MAJOR_VERSION>1 return Fl::modal()->handle(FL_KEYBOARD); #else return Fl::grab()->handle(FL_KEYBOARD); #endif } return 0; } else if (e == FL_SHORTCUT || e == FL_KEYBOARD) { #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0 && FL_PATCH_VERSION < 3 // make the tab keys work in the menus in older fltk's: // (they do not cycle around however, so a new fltk is a good idea) if (Fl::grab()) { // make fltk's menus resond to tab + shift+tab: if (Fl::event_key() == FL_Tab) { if (Fl::event_state() & FL_SHIFT) goto J1; Fl::e_keysym = FL_Down; } else if (Fl::event_key() == 0xFE20) { J1: Fl::e_keysym = FL_Up; } else return 0; return Fl::grab()->handle(FL_KEYBOARD); } #endif return Handle_Hotkey(); } return 0; } #if DESKTOPS extern void init_desktops(); extern Atom _win_workspace; extern Atom _win_workspace_count; extern Atom _win_workspace_names; #endif extern Atom _win_state; extern Atom _win_hints; #ifdef SHOW_CLOCK int clock_period = 1; int clock_oldmin = 61; int clock_alarm_on = 0; char clock_buf[80]; struct sigaction flwm_clock_alarm_start = {0,}, flwm_clock_alarm_stop = {0,}; void flwm_update_clock(void*) { time_t newtime; struct tm *tm_p; // get current time time(&newtime); tm_p = localtime(&newtime); // Update a window frame if necessary if (Frame::activeFrame() && tm_p->tm_min != clock_oldmin) { if (clock_oldmin != 61) clock_period = 60; // now that we're in sync, only update 1/minute clock_oldmin = tm_p->tm_min; strftime(clock_buf, 80, SHOW_CLOCK, tm_p); Frame::activeFrame()->redraw_clock(); } // Now reschedule the timeout Fl::remove_timeout(flwm_update_clock); Fl::add_timeout(clock_period, flwm_update_clock); } void flwm_clock_alarm_on(int) { clock_alarm_on = 1; Frame::activeFrame()->redraw_clock(); } void flwm_clock_alarm_off(int) { clock_alarm_on = 0; Frame::activeFrame()->redraw_clock(); } #endif static const char* cfg, *cbg; #if FL_MAJOR_VERSION>1 static fltk::Cursor* cursor = FL_CURSOR_ARROW; extern FL_API fltk::Color fl_cursor_fg; extern FL_API fltk::Color fl_cursor_bg; #else static int cursor = FL_CURSOR_ARROW; #endif static void initialize() { Display* d = fl_display; #ifdef TEST XWindow w = XCreateSimpleWindow(d, RootWindow(d, fl_screen), 100, 100, 200, 300, 10, BlackPixel(fl_display, 0), // WhitePixel(fl_display, 0)); 0x1234); Frame* frame = new Frame(w); frame->label("flwm test window"); XSelectInput(d, w, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | FocusChangeMask | KeymapStateMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask /*|PointerMotionMask*/ ); #else Fl::add_handler(flwm_event_handler); // setting attributes on root window makes me the window manager: initializing = 1; XSelectInput(d, fl_xid(Root), SubstructureRedirectMask | SubstructureNotifyMask | ColormapChangeMask | PropertyChangeMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | KeyPressMask | KeyReleaseMask | KeymapStateMask); #if FL_MAJOR_VERSION>1 Root->cursor(cursor); #else Root->cursor((Fl_Cursor)cursor, CURSOR_FG_SLOT, CURSOR_BG_SLOT); #endif Fl::visible_focus(0); #ifdef TITLE_FONT Fl::set_font(TITLE_FONT_SLOT, TITLE_FONT); #endif #ifdef MENU_FONT Fl::set_font(MENU_FONT_SLOT, MENU_FONT); #endif #ifdef ACTIVE_COLOR Fl::set_color(FL_SELECTION_COLOR, ACTIVE_COLOR<<8); #endif // Gnome crap: // First create a window that can be watched to see if wm dies: Atom a = XInternAtom(d, "_WIN_SUPPORTING_WM_CHECK", False); XWindow win = XCreateSimpleWindow(d, fl_xid(Root), -200, -200, 5, 5, 0, 0, 0); CARD32 val = win; XChangeProperty(d, fl_xid(Root), a, XA_CARDINAL, 32, PropModeReplace, (uchar*)&val, 1); XChangeProperty(d, win, a, XA_CARDINAL, 32, PropModeReplace, (uchar*)&val, 1); // Next send a list of Gnome stuff we understand: a = XInternAtom(d, "_WIN_PROTOCOLS", 0); Atom list[10]; unsigned int i = 0; //list[i++] = XInternAtom(d, "_WIN_LAYER", 0); list[i++] = _win_state = XInternAtom(d, "_WIN_STATE", 0); list[i++] = _win_hints = XInternAtom(d, "_WIN_HINTS", 0); //list[i++] = XInternAtom(d, "_WIN_APP_STATE", 0); //list[i++] = XInternAtom(d, "_WIN_EXPANDED_SIZE", 0); //list[i++] = XInternAtom(d, "_WIN_ICONS", 0); #if DESKTOPS list[i++] = _win_workspace = XInternAtom(d, "_WIN_WORKSPACE", 0); list[i++] = _win_workspace_count = XInternAtom(d, "_WIN_WORKSPACE_COUNT", 0); list[i++] = _win_workspace_names = XInternAtom(d, "_WIN_WORKSPACE_NAMES", 0); #endif //list[i++] = XInternAtom(d, "_WIN_FRAME_LIST", 0); XChangeProperty(d, fl_xid(Root), a, XA_ATOM, 32, PropModeReplace, (uchar*)list, i); Grab_Hotkeys(); #ifdef SHOW_CLOCK Fl::add_timeout(clock_period, flwm_update_clock); flwm_clock_alarm_start.sa_handler = &flwm_clock_alarm_on; flwm_clock_alarm_stop.sa_handler = &flwm_clock_alarm_off; sigaction(SIGALRM, &flwm_clock_alarm_start, NULL); sigaction(SIGCONT, &flwm_clock_alarm_stop, NULL); #endif XSync(d, 0); initializing = 0; #if DESKTOPS init_desktops(); #endif // find all the windows and create a Frame for each: unsigned int n; XWindow w1, w2, *wins; XWindowAttributes attr; XQueryTree(d, fl_xid(Root), &w1, &w2, &wins, &n); for (i = 0; i < n; ++i) { XGetWindowAttributes(d, wins[i], &attr); if (attr.override_redirect || !attr.map_state) continue; (void)new Frame(wins[i],&attr); } XFree((void *)wins); #endif } //////////////////////////////////////////////////////////////// extern int exit_flag; extern int max_w_switch; extern int max_h_switch; // consume a switch from argv. Returns number of words eaten, 0 on error: int arg(int argc, char **argv, int &i) { const char *s = argv[i]; if (s[0] != '-') return 0; s++; // do single-word switches: if (!strcmp(s,"x")) { exit_flag = 1; i++; return 1; } // do switches with a value: const char *v = argv[i+1]; if (i >= argc-1 || !v) return 0; // all the rest need an argument, so if missing it is an error if (!strcmp(s, "cfg")) { cfg = v; } else if (!strcmp(s, "cbg")) { cbg = v; #if FL_MAJOR_VERSION < 2 } else if (*s == 'c') { cursor = atoi(v); #endif } else if (*s == 'v') { int visid = atoi(v); fl_open_display(); XVisualInfo templt; int num; templt.visualid = visid; fl_visual = XGetVisualInfo(fl_display, VisualIDMask, &templt, &num); if (!fl_visual) Fl::fatal("No visual with id %d",visid); fl_colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), fl_visual->visual, AllocNone); } else if (*s == 'm') { max_w_switch = atoi(v); while (*v && *v++ != 'x'); max_h_switch = atoi(v); } else return 0; // unrecognized // return the fact that we consumed 2 switches: i += 2; return 2; } #if FL_MAJOR_VERSION<2 static void color_setup(Fl_Color slot, const char* arg, ulong value) { if (arg) { XColor x; if (XParseColor(fl_display, fl_colormap, arg, &x)) value = ((x.red>>8)<<24)|((x.green>>8)<<16)|((x.blue)); } Fl::set_color(slot, value); } #endif int main(int argc, char** argv) { program_name = fl_filename_name(argv[0]); int i; if (Fl::args(argc, argv, i, arg) < argc) Fl::error( "options are:\n" " -d[isplay] host:#.#\tX display & screen to use\n" " -v[isual] #\t\tvisual to use\n" " -g[eometry] WxH+X+Y\tlimits windows to this area\n" " -m[aximum] WxH\t\tsize of maximized windows\n" " -x\t\t\tmenu says Exit instead of logout\n" " -bg color\t\tFrame color\n" " -fg color\t\tLabel color\n" " -bg2 color\t\tText field color\n" " -c[ursor] #\t\tCursor number for root\n" " -cfg color\t\tCursor color\n" " -cbg color\t\tCursor outline color" ); #ifndef FL_NORMAL_SIZE // detect new versions of fltk where this is a variable FL_NORMAL_SIZE = 12; #endif #if FL_MAJOR_VERSION>1 if (cfg) fl_cursor_fg = fltk::color(cfg); if (cbg) fl_cursor_bg = fltk::color(cbg); #else fl_open_display(); color_setup(CURSOR_FG_SLOT, cfg, CURSOR_FG_COLOR<<8); color_setup(CURSOR_BG_SLOT, cbg, CURSOR_BG_COLOR<<8); Fl::set_color(FL_SELECTION_COLOR,0,0,128); #endif Fl_Root root; Root = &root; #if FL_MAJOR_VERSION>1 // show() is not a virtual function in fltk2.0, this fools it: fltk::load_theme(); root.show(); #endif Root->show(argc,argv); // fools fltk into using -geometry to set the size XSetErrorHandler(xerror_handler); initialize(); return Fl::run(); } flwm-1.02+cvs20080422/makeinclude.in0000644000175000017500000000062210654364646014425 0ustar meme# @configure_input@ prefix =@prefix@ exec_prefix =@exec_prefix@ bindir =@bindir@ mandir =@mandir@ includedir =@includedir@ libdir =@libdir@ srcdir =@srcdir@ VPATH =@srcdir@ # compiler names: CXX =@CXX@ CC =@CC@ MAKEDEPEND =@MAKEDEPEND@ # flags for C++ compiler: CFLAGS =@CFLAGS@ CXXFLAGS =@CXXFLAGS@ # libraries to link with: LIBS =@LIBS@ -lX11 -lXext @X_EXTRA_LIBS@ -lm INSTALL =@INSTALL@ flwm-1.02+cvs20080422/rotated_test.C0000644000175000017500000000611707040736155014417 0ustar meme// Test the xvertext routines for rotated text #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////// #include "Rotated.H" class RotText : public Fl_Box { void draw(); public: RotText(int X, int Y, int W, int H, const char* L = 0) : Fl_Box(X,Y,W,H,L) {} }; void RotText::draw() { draw_box(); fl_color(FL_BLACK); fl_font(labelfont(), labelsize()); draw_rotated90(label(), x(), y(), w(), h(), align()); } //////////////////////////////////////////////////////////////// Fl_Toggle_Button *leftb,*rightb,*topb,*bottomb,*insideb,*clipb,*wrapb; RotText *text; Fl_Input *input; Fl_Hor_Value_Slider *fonts; Fl_Hor_Value_Slider *sizes; Fl_Double_Window *window; void button_cb(Fl_Widget *,void *) { int i = 0; if (leftb->value()) i |= FL_ALIGN_LEFT; if (rightb->value()) i |= FL_ALIGN_RIGHT; if (topb->value()) i |= FL_ALIGN_TOP; if (bottomb->value()) i |= FL_ALIGN_BOTTOM; if (insideb->value()) i |= FL_ALIGN_INSIDE; if (clipb->value()) i |= FL_ALIGN_CLIP; if (wrapb->value()) i |= FL_ALIGN_WRAP; text->align(i); window->redraw(); } void font_cb(Fl_Widget *,void *) { text->labelfont(int(fonts->value())); window->redraw(); } void size_cb(Fl_Widget *,void *) { text->labelsize(int(sizes->value())); window->redraw(); } void input_cb(Fl_Widget *,void *) { text->label(input->value()); window->redraw(); } int main(int argc, char **argv) { window = new Fl_Double_Window(400,400); input = new Fl_Input(50,0,350,25); input->static_value("The quick brown fox jumped over the lazy dog."); input->when(FL_WHEN_CHANGED); input->callback(input_cb); sizes= new Fl_Hor_Value_Slider(50,25,350,25,"Size:"); sizes->align(FL_ALIGN_LEFT); sizes->bounds(1,64); sizes->step(1); sizes->value(14); sizes->callback(size_cb); fonts=new Fl_Hor_Value_Slider(50,50,350,25,"Font:"); fonts->align(FL_ALIGN_LEFT); fonts->bounds(0,15); fonts->step(1); fonts->value(0); fonts->callback(font_cb); Fl_Group *g = new Fl_Group(0,0,0,0); leftb = new Fl_Toggle_Button(50,75,50,25,"left"); leftb->callback(button_cb); rightb = new Fl_Toggle_Button(100,75,50,25,"right"); rightb->callback(button_cb); topb = new Fl_Toggle_Button(150,75,50,25,"top"); topb->callback(button_cb); bottomb = new Fl_Toggle_Button(200,75,50,25,"bottom"); bottomb->callback(button_cb); insideb = new Fl_Toggle_Button(250,75,50,25,"inside"); insideb->callback(button_cb); wrapb = new Fl_Toggle_Button(300,75,50,25,"wrap"); wrapb->callback(button_cb); clipb = new Fl_Toggle_Button(350,75,50,25,"clip"); clipb->callback(button_cb); g->resizable(insideb); g->forms_end(); text= new RotText(100,225,200,100,input->value()); text->box(FL_FRAME_BOX); text->align(FL_ALIGN_CENTER); window->resizable(text); window->forms_end(); window->show(argc,argv); return Fl::run(); } // // End of "$Id: rotated_test.C,v 1.1 2000/01/18 01:05:49 spitzak Exp $". //