Commit 5cef9b37 authored by Axel Beckert's avatar Axel Beckert

Imported Upstream version 1.02+cvs20080422

// Desktop.C
#include "config.h"
#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;
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;
Desktop::~Desktop() {
// remove from list:
for (Desktop** p = &first; *p; p = &((*p)->next))
if (*p == this) {*p = next; break;}
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);
void Desktop::name(const char* l) {
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());
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;
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;
if (!current_num) current_num = 1;
Desktop::current(Desktop::number(current_num, 1));
dont_send = 0;
// Desktop.H
class Desktop {
const char* name_;
int number_;
static Desktop* current_;
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);
int junk; // for temporary storage by menu builder
This diff is collapsed.
// 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>
# define XWindow Window
// 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
// values for state_flags:
// These change over time
enum {
IGNORE_UNMAP = 0x01, // we did something that echos an UnmapNotify
class FrameButton : public Fl_Button {
void draw();
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();
int handle(const XEvent*);
static Frame* first;
Frame* next; // stacking order, top to bottom
Frame(XWindow, XWindowAttributes* = 0);
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);
// 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;}
dont_set_event_mask = 1;
frame = new Frame(fl_xid(this));
dont_set_event_mask = 0;
void FrameWindow::hide() {
if (shown()) {
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) {
return 1;
return 0;
// 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;
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) {}
// 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);
static void NextWindow() { // Alt+Tab
static void PreviousWindow() { // Alt+Shift+Tab
static void NextDesk() {
if (Desktop::current()) {
} else {
static void PreviousDesk() {
Desktop* search=Desktop::first;
while (search->next && search->next!=Desktop::current()){
// warning: this assummes it is bound to Fn key:
static void DeskNumber() {
Desktop::current(Desktop::number(Fl::event_key()-FL_F, 1));
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();
static struct {int key; void (*func)();} keybindings[] = {
// these are very common and tend not to conflict, due to Windoze:
{FL_ALT+FL_Escape, ShowMenu},
{FL_ALT+FL_Menu, ShowMenu},
{FL_ALT+FL_Tab, NextWindow},
{FL_ALT+FL_SHIFT+0xfe20,PreviousWindow}, // XK_ISO_Left_Tab
#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},
// 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},
// these wmx keys are not set by default as they break NetScape:
{FL_ALT+FL_Left, PreviousDesk},
{FL_ALT+FL_Right, NextDesk},
// 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"
// 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},
// 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;
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?
) {
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
PROGRAM = flwm
VERSION = 1.02
CXXFILES = main.C Frame.C Rotated.C Menu.C FrameWindow.C Desktop.C Hotkeys.C
all: makeinclude $(PROGRAM)
makeinclude: 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
touch makedepend
include makedepend
install: $(PROGRAM)
$(INSTALL) -s $(PROGRAM) $(bindir)/$(PROGRAM)
-@ rm -f $(bindir)/$(PROGRAM)
-@ rm -f $(mandir)/man$(MANPAGE)/$(PROGRAM).$(MANPAGE)
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)
-@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
debug: $(PROGRAM_D)
OBJECTS_D = $( $( :
$(CXX) -I.. $(CXXFLAGS) -DDEBUG -c -o $@ $< :
$(CC) -I.. $(CFLAGS) -DDEBUG -o $@ $<
rotated_test: Rotated.o rotated_test.C
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o rotated_test rotated_test.C Rotated.o $(LIBS) $(LIBS)
This diff is collapsed.
flwm Version 0.25