Initial checkin of the code to sourceforge.

This commit is contained in:
Bill Spitzak
2000-01-18 01:05:49 +00:00
commit fd0e9884cb
18 changed files with 4537 additions and 0 deletions

149
Desktop.C Normal file
View File

@ -0,0 +1,149 @@
// Desktop.C
#include "config.h"
#if DESKTOPS
#include "Frame.H"
#include "Desktop.H"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
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() : "<deleted>";
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

22
Desktop.H Normal file
View File

@ -0,0 +1,22 @@
// 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
};

1726
Frame.C Normal file

File diff suppressed because it is too large Load Diff

192
Frame.H Normal file
View File

@ -0,0 +1,192 @@
// Frame.H
// Each X window being managed by fltk has one of these
#ifndef Frame_H
#define Frame_H
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/x.H>
// 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 {
Window 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
Window 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
Window *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 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 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(Window, XWindowAttributes* = 0);
~Frame();
Window 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(Window, Atom, Atom = AnyPropertyType, int* length = 0);
int getIntProperty(Window, Atom, Atom = AnyPropertyType, int deflt = 0);
void setProperty(Window, Atom, Atom, int);
#endif

42
FrameWindow.C Normal file
View File

@ -0,0 +1,42 @@
// 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 <FL/Fl.H>
#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;
}

31
FrameWindow.H Normal file
View File

@ -0,0 +1,31 @@
// 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 <FL/Fl_Window.H>
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

181
Hotkeys.C Normal file
View File

@ -0,0 +1,181 @@
// 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 <stdio.h>
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}};
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() {
Window 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
}
}

84
Makefile Normal file
View File

@ -0,0 +1,84 @@
SHELL=/bin/sh
PROGRAM = flwm
VERSION = 0.25
CXXFILES = main.C Frame.C Rotated.C Menu.C FrameWindow.C Desktop.C Hotkeys.C
LIBS = -lfltk
MANPAGE = 1
################################################################
OBJECTS = $(CXXFILES:.C=.o)
all: $(PROGRAM)
$(PROGRAM) : $(OBJECTS)
$(CXX) $(LDFLAGS) -o $(PROGRAM) $(OBJECTS) $(LIBS) $(LDLIBS)
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_D) -c -o $@ $<
.c.do :
$(CC) -I.. $(CFLAGS_D) -c -o $@ $<
$(PROGRAM_D) : $(OBJECTS_D)
$(CXX) $(LDFLAGS) -o $(PROGRAM_D) $(OBJECTS_D) $(LIBS) $(LDLIBS)
rotated_test: Rotated.o rotated_test.C
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o rotated_test rotated_test.C Rotated.o $(LIBS) $(LDLIBS)

627
Menu.C Normal file
View File

@ -0,0 +1,627 @@
// Menu.cxx
#include "config.h"
#include "Frame.H"
#if DESKTOPS
#include "Desktop.H"
#endif
#include <FL/Fl_Box.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "FrameWindow.H"
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
// 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;
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_BLACK);
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";
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)
////////////////////////////////////////////////////////////////
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;
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*)
{
Frame::save_protocol();
exit(0);
}
static void
logout_cb(Fl_Widget*, void*)
{
static FrameWindow* w;
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 <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#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", 0);
else execl(name, name, 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, 12},
#endif
#if DESKTOPS
{"New desktop", 0, new_desktop_cb, 0, 0, 0, 0, 12},
#endif
{"Logout", 0, logout_cb, 0, 0, 0, 0, 12},
{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);
m.flags = 0;
m.labeltype(FL_NORMAL_LABEL);
m.shortcut(0);
m.labelfont(MENU_FONT_SLOT);
m.labelsize(MENU_FONT_SIZE);
m.labelcolor(FL_BLACK);
}
#if WMX_MENU_ITEMS
// wmxlist is an array of char* pointers (for efficient sorting purposes),
// which are stored in wmxbuffer (for memory efficiency and to avoid
// freeing and fragmentation)
static char** wmxlist = NULL;
static int wmxlistsize = 0;
// wmx commands are read from ~/.wmx,
// they are stored null-separated here:
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);
// worst-case alloc needs
if (bufindex+len+nest+1 > wmxbufsize)
wmxbuffer = (char*)realloc(wmxbuffer, (wmxbufsize+=1024));
for (int i=0; i<nest; i++)
wmxbuffer[bufindex++] = '/'; // extra slash marks menu titles
if (S_ISDIR(st.st_mode) && (st.st_mode & 0555) && nest<MAX_NESTING_DEPTH){
strcpy(wmxbuffer+bufindex, path);
bufindex += len+1;
strcat(path, "/");
bufindex = scan_wmx_dir (path, bufindex, nest+1);
num_wmx++;
} else if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) {
// make sure it exists and is an executable file:
strcpy(wmxbuffer+bufindex, path);
bufindex += len+1;
num_wmx++;
}
}
closedir(dir);
}
return bufindex;
}
// comparison for qsort
// We keep submenus together by noting that they're proper superstrings
static int
wmxCompare(const void *A, const void *B)
{
char *pA, *pB;
pA = *(char **)A;
pB = *(char **)B;
pA += strspn(pA, "/");
pB += strspn(pB, "/");
// caseless compare
while (*pA && *pB) {
if (toupper(*pA) > toupper(*pB))
return(1);
if (toupper(*pA) < toupper(*pB))
return(-1);
pA++;
pB++;
}
if (*pA)
return(1);
if (*pB)
return(-1);
return(0);
}
static 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; i<num_wmx; i++) {
char* cmd = wmxbuffer;
for (int j = 0; j < num_wmx; j++) {
wmxlist[j] = cmd;
cmd += strlen(cmd)+1;
}
}
qsort(wmxlist, num_wmx, sizeof(char *), wmxCompare);
}
#endif
////////////////////////////////////////////////////////////////
int exit_flag; // set by the -x switch
static int is_active_frame(Frame* c) {
for (Frame* a = Frame::activeFrame(); a; a = a->transient_for())
if (a == c) return 1;
return 0;
}
void
ShowTabMenu(int tab)
{
static char beenhere;
if (!beenhere) {
beenhere = 1;
Fl::set_labeltype(FRAME_LABEL, frame_label_draw, frame_label_measure);
Fl::set_labeltype(TEXT_LABEL, label_draw, label_measure);
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"
// add wmx items
int level = 0;
for (int i=0; i<num_wmx; i++) {
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1;
if (nextlev < level) {
n += level-nextlev;
level = nextlev;
} else if (nextlev > 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;
init(menu[n],(char*)c);
menu[n].labeltype(FRAME_LABEL);
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);
menu[n].labeltype(FRAME_LABEL);
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];
cmd += strspn(cmd, "/")-1;
init(menu[n], cmd+pathlen[level]);
#if DESKTOPS
if (one_desktop)
#endif
if (!level)
menu[n].labeltype(TEXT_LABEL);
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1;
if (nextlev < level) {
menu[n].callback(spawn_cb, cmd);
// Close 'em off
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);
} else {
menu[n].callback(spawn_cb, cmd);
}
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 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);
const Fl_Menu_Item* picked =
menu->popup(Fl::event_x(), Fl::event_y(), 0, preset);
if (picked && picked->callback()) picked->do_callback(0);
}
void ShowMenu() {ShowTabMenu(0);}

121
README Normal file
View File

@ -0,0 +1,121 @@
flwm Version 0.25
----------------------------------------------------------------
How to compile flwm:
----------------------------------------------------------------
You need fltk. If you do not have it yet, download it from
http://fltk.easysw.com, 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:
----------------------------------------------------------------
Flwm should be run by X when it logs you in. This is done by putting
a call to flwm into the file ~/.xinitrc. With any luck you already
have this file. If not try copying /usr/X11/lib/X11/xinit/xinitrc.
Edit the file and try to remove any call to another window manager
(these are usually near the end).
Recommended contents of ~/.xinitrc:
#!/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 <cannam@zands.demon.co.uk>
Code contributions by Steve );Hara-Smith <steveo@iol.ie>
----------------------------------------------------------------
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
----------------------------------------------------------------

427
Rotated.C Normal file
View File

@ -0,0 +1,427 @@
// 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 <FL/x.H>
#include <FL/fl_draw.H>
#include "Rotated.H"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
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;
Window 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;
/* per char dimensions ... */
ascent = rotfont->per_char[ichar].ascent =
fontstruct->per_char[index].ascent;
descent = rotfont->per_char[ichar].descent =
fontstruct->per_char[index].descent;
lbearing = rotfont->per_char[ichar].lbearing =
fontstruct->per_char[index].lbearing;
rbearing = rotfont->per_char[ichar].rbearing =
fontstruct->per_char[index].rbearing;
rotfont->per_char[ichar].width =
fontstruct->per_char[index].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['?'];
for (ichar = max_char+1; ichar < 256; ichar++)
rotfont->per_char[ichar] = rotfont->per_char['?'];
/* 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; i<len; i++) {
ichar = ((unsigned char*)str)[i];
/* suitable offset ... */
if (dir == 1) {
xp = x-rotfont->per_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; i<len; i++) {
width += rotfont->per_char[((unsigned char*)str)[i]].width;
}
return width;
}
#endif
/* ---------------------------------------------------------------------- */
// the public functions use the fltk global variables for font & gc:
static XRotFontStruct* font;
void draw_rotated(const char* text, int n, int x, int y, int angle) {
if (!text || !*text) return;
/* 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 && font->xfontstruct == fl_xfont && font->dir == dir) {
;
} else {
if (font) XRotUnloadFont(fl_display, font);
font = XRotLoadFont(fl_display, fl_xfont, dir);
}
XRotDrawString(fl_display, font, fl_window, fl_gc, x, y, text, n);
}
#ifndef FLWM
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);
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);
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

18
Rotated.H Normal file
View File

@ -0,0 +1,18 @@
// 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

60
configure.in Normal file
View File

@ -0,0 +1,60 @@
dnl# -*- 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"
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 -O2 $X_CFLAGS"
CFLAGS_D="$CFLAGS -Wall -Wno-return-type -g -DDEBUG $X_CFLAGS"
CXXFLAGS="$CXXFLAGS -Wall -Wno-return-type -O2 $X_CFLAGS"
CXXFLAGS_D="$CXXFLAGS -Wall -Wno-return-type -g -DDEBUG $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"
CFLAGS_D="$CFLAGS -fullwarn -gslim -DDEBUG $X_CFLAGS"
CXXFLAGS="$CXXFLAGS -fullwarn -woff 3322 -O2 $X_CFLAGS"
CXXFLAGS_D="$CXXFLAGS -fullwarn -woff 3322 -gslim -DDEBUG $X_CFLAGS"
else
# old Irix compiler:
CFLAGS="$CFLAGS -O2 $X_CFLAGS"
CFLAGS_D="$CFLAGS -g -DDEBUG $X_CFLAGS"
CXXFLAGS="$CXXFLAGS +w +pp -O2 $X_CFLAGS"
CXXFLAGS_D="$CXXFLAGS +w +pp -g -DDEBUG $X_CFLAGS"
fi
else
# generic C compiler:
CFLAGS="$CFLAGS -O $X_CFLAGS"
CFLAGS_D="$CFLAGS -g -DDEBUG $X_CFLAGS"
CXXFLAGS="$CXXFLAGS -O $X_CFLAGS"
CXXFLAGS_D="$CXXFLAGS -g -DDEBUG $X_CFLAGS"
fi
fi
AC_SUBST(MAKEDEPEND)
AC_SUBST(CFLAGS_D)
AC_SUBST(CXXFLAGS_D)
dnl# AC_CONFIG_HEADER(config.h:configh.in)
AC_OUTPUT(makeinclude)
dnl# end of configure.in

274
flwm.1 Normal file
View File

@ -0,0 +1,274 @@
.\"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
Recommened contents of your ~/.xinitrc file:
.nf
#!/bin/sh
xsetroot -solid \#006060
xrdb .Xresources
# <xset, xmodmap, other configuration programs>
flwm &
WindowManager=$!
# <xterm, other automatically-launched programs>
wait $WindowManager
.fi
You may instead use the standard of running the window manager last with
an "exec flwm" statement at the end of .xinitrc.
.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 it's 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. It's 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
it's 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 <cannam@zands.demon.co.uk>
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

65
flwm_wmconfig Executable file
View File

@ -0,0 +1,65 @@
#! /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} {
if [llength $list]<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"
}

374
main.C Normal file
View File

@ -0,0 +1,374 @@
// 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 <X11/Xproto.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <FL/filename.H>
#include "config.h"
#ifdef SHOW_CLOCK
#include <time.h>
#include <signal.h>
#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()) {}
void show() {
if (!shown()) Fl_X::set_xid(this, RootWindow(fl_display, fl_screen));
}
};
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.
Window 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;}
case KeyRelease: {
if (!Fl::grab()) return 0;
// see if they released the alt key:
unsigned long keysym =
XKeycodeToKeysym(fl_display, fl_xevent->xkey.keycode, 0);
if (keysym == FL_Alt_L || keysym == FL_Alt_R) {
Fl::e_keysym = FL_Enter;
return Fl::grab()->handle(FL_KEYBOARD);
}
return 0;}
}
} else if (e == FL_SHORTCUT) {
#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;
static int cursor = FL_CURSOR_ARROW;
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);
}
static void initialize() {
Display* d = fl_display;
#ifdef TEST
Window w = XCreateSimpleWindow(d, root,
100, 100, 200, 300, 10,
BlackPixel(fl_display, 0),
// WhitePixel(fl_display, 0));
0x1234);
Frame* frame = new Frame(w);
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);
color_setup(CURSOR_FG_SLOT, cfg, CURSOR_FG_COLOR<<8);
color_setup(CURSOR_BG_SLOT, cbg, CURSOR_BG_COLOR<<8);
Root->cursor((Fl_Cursor)cursor, CURSOR_FG_SLOT, CURSOR_BG_SLOT);
#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);
Window 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;
Window 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;
} else if (*s == 'c') {
cursor = atoi(v);
} 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;
}
int main(int argc, char** argv) {
program_name = 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"
);
Root = new Fl_Root();
Root->show(argc,argv); // fools fltk into using -geometry to set the size
XSetErrorHandler(xerror_handler);
initialize();
return Fl::run();
}

26
makeinclude.in Normal file
View File

@ -0,0 +1,26 @@
# @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@
CFLAGS_D =@CFLAGS_D@
CXXFLAGS =@CXXFLAGS@
CXXFLAGS_D =@CXXFLAGS_D@
# libraries to link with:
LDLIBS =@LIBS@ -lX11 -lXext @X_EXTRA_LIBS@ -lm
INSTALL =@INSTALL@

118
rotated_test.C Normal file
View File

@ -0,0 +1,118 @@
// Test the xvertext routines for rotated text
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Hor_Value_Slider.H>
#include <FL/Fl_Toggle_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Choice.H>
#include <FL/fl_draw.H>
////////////////////////////////////////////////////////////////
#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$".
//