+++ /dev/null
-Makefile
-Makefile.in
-.deps
-otk_test
-otk_wrap.cc
-.libs
-application.lo
-appwidget.lo
-button.lo
-color.lo
-configuration.lo
-display.lo
-eventdispatcher.lo
-eventhandler.lo
-focuslabel.lo
-focuswidget.lo
-font.lo
-gccache.lo
-image.lo
-imagecontrol.lo
-label.lo
-libotk.la
-otk_wrap.lo
-property.lo
-rect.lo
-screeninfo.lo
-style.lo
-texture.lo
-timer.lo
-timerqueuemanager.lo
-truerendercontrol.lo
-pseudorendercontrol.lo
-util.lo
-widget.lo
-ustring.lo
-surface.lo
-rendertexture.lo
-rendertest
-renderstyle.lo
-messagedialog.lo
-rendercontrol.lo
-rendercolor.lo
-otk.py
-otk.pc
-otk.lo
+++ /dev/null
-buttonsdir = $(pkgdatadir)/buttons
-includeotkdir = $(includedir)/otk
-pkgconfigdir = $(libdir)/pkgconfig
-
-CPPFLAGS=$(XFT_CFLAGS) @CPPFLAGS@ -DBUTTONSDIR=\"$(buttonsdir)\"
-
-lib_LTLIBRARIES=libotk.la
-
-libotk_la_SOURCES=rendercontrol.cc truerendercontrol.cc surface.cc util.cc \
- renderstyle.cc rendercolor.cc pseudorendercontrol.cc \
- display.cc font.cc property.cc timer.cc \
- eventdispatcher.cc eventhandler.cc ustring.cc \
- widget.cc application.cc label.cc appwidget.cc button.cc \
- otk.cc messagedialog.cc
-
-#focuswidget.cc focuslabel.cc
-
-includeotk_HEADERS=application.hh appwidget.hh assassin.hh button.hh \
- display.hh eventdispatcher.hh eventhandler.hh font.hh \
- label.hh otk.hh point.hh property.hh pseudorendercontrol.hh\
- rect.hh rendercolor.hh rendercontrol.hh renderstyle.hh \
- rendertexture.hh size.hh strut.hh surface.hh \
- timer.hh truerendercontrol.hh ustring.hh util.hh widget.hh \
- messagedialog.hh ../config.h
-
-EXTRA_DIST = otk.pc.in
-
-DISTCLEANFILES = otk.pc
-MAINTAINERCLEANFILES= Makefile.in
-
-pkgconfig_DATA = otk.pc
-
-otk.pc: otk.pc.in
- @regex_cmd@ -e "s,\@prefix\@,$(prefix)," \
- -e "s,\@version\@,$(VERSION)," \
- @srcdir@/$^ > $@
-
-distclean-local:
- $(RM) *\~ *.orig *.rej .\#*
-
-uninstall-am:
- -rmdir -p $(includeotkdir)
- -rmdir -p $(pkgconfigdir)
-
-otk_test: libotk.la otk_test.cc
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DHAVE_CONFIG_H -I. -I. -I.. -I../src $(XFT_CFLAGS) -Wall -W -pedantic -DNDEBUG -g -O2 -o otk_test otk_test.cc $(XFT_LIBS) -L. -lotk @LIBS@
-
-rendertest: libotk.la rendertest.cc
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DHAVE_CONFIG_H -I. -I. -I.. -I../src $(XFT_CFLAGS) -Wall -W -pedantic -DNDEBUG -g -O2 -o $@ rendertest.cc $(XFT_LIBS) -L. -lotk @LIBS@
-
-# local dependencies
+++ /dev/null
-* Implement borders and border overlapping in widget
- the widget has a outer geometry(that of the border) and a inner one
- (the current geometry)
- if the overlap flag is true, the inner widgets' borders are overlapped
- as much as possible while the widgets are still entirely visible.
-
-* make OtkButton do pixmaps
-
-* OtkMenu
- this can wait, probably
-
-* OtkWidget
- see about focus()
- focus() on widgets means 'highlight', not take Focus. solve this mess
-
-* OtkTextWidget
- widget that holds text that can be justified and whatnot
- the button should prolly be modified to subclass this
-
-* OtkApplication
- do all derty work init display/screen/style/image control etc
- event loop
- do docking
- close app, clean up crap
- watch for style properties on the root window, update crap
- on the fly.
-
-* widget factory for openbox
- singleton that fetches widgets to openbox so that openbox
- doesn't need to do useless work in creating/initializing/etc
-
-* cleanup image code
- less deps on screen and display
- what's this thing about 8bpp being busticatered
-
-* cleanups
- name classes OtkBummy instead of OB... or B...
- make Style hold pointers to colors and textures
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "application.hh"
-#include "eventhandler.hh"
-#include "timer.hh"
-#include "property.hh"
-#include "rendercolor.hh"
-#include "renderstyle.hh"
-#include "display.hh"
-
-#include <cstdlib>
-#include <iostream>
-
-namespace otk {
-
-extern void initialize();
-extern void destroy();
-
-Application::Application(int argc, char **argv)
- : EventDispatcher(),
- _dockable(false),
- _appwidget_count(0)
-{
- (void)argc;
- (void)argv;
-
- otk::initialize();
-
- _screen = DefaultScreen(**display);
-
- loadStyle();
-}
-
-Application::~Application()
-{
- otk::destroy();
-}
-
-void Application::loadStyle(void)
-{
- // XXX: find the style name as a property
- std::string style = "/usr/local/share/openbox/styles/artwiz";
- //_style->load(style);
- otk::RenderStyle::setStyle(_screen, style);
-}
-
-void Application::run(void)
-{
- if (_appwidget_count <= 0) {
- std::cerr << "ERROR: No main widgets exist. You must create and show() " <<
- "an AppWidget for the Application before calling " <<
- "Application::run().\n";
- ::exit(1);
- }
-
- while (_appwidget_count > 0) {
- dispatchEvents();
- if (_appwidget_count > 0)
- Timer::dispatchTimers(); // fire pending events
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __application_hh
-#define __application_hh
-
-#include "eventdispatcher.hh"
-
-namespace otk {
-
-class AppWidget;
-
-class Application : public EventDispatcher {
-
-public:
-
- Application(int argc, char **argv);
- virtual ~Application();
-
- inline int screen() const { return _screen; }
-
- virtual void run(void);
- // more bummy cool functionality
-
- void setDockable(bool dockable) { _dockable = dockable; }
- inline bool isDockable(void) const { return _dockable; }
-
-private:
- void loadStyle(void);
-
- int _screen;
- bool _dockable;
-
- int _appwidget_count;
-
- friend class AppWidget;
-};
-
-}
-
-#endif
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "appwidget.hh"
-#include "application.hh"
-#include "property.hh"
-#include "renderstyle.hh"
-#include "display.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-namespace otk {
-
-AppWidget::AppWidget(Application *app, Direction direction, int bevel)
- : Widget(app->screen(), app, direction, bevel),
- _application(app)
-{
- assert(app);
-
- // set WM Protocols on the window
- Atom protocols[2];
- protocols[0] = Property::atoms.wm_protocols;
- protocols[1] = Property::atoms.wm_delete_window;
- XSetWMProtocols(**display, window(), protocols, 2);
-}
-
-AppWidget::~AppWidget()
-{
-}
-
-void AppWidget::show()
-{
- if (!visible())
- _application->_appwidget_count++;
- Widget::show(true);
-}
-
-void AppWidget::hide()
-{
- if (visible())
- _application->_appwidget_count--;
- Widget::hide();
-}
-
-void AppWidget::clientMessageHandler(const XClientMessageEvent &e)
-{
- EventHandler::clientMessageHandler(e);
- if (e.message_type == Property::atoms.wm_protocols &&
- static_cast<Atom>(e.data.l[0]) == Property::atoms.wm_delete_window)
- hide();
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __appwidget_hh
-#define __appwidget_hh
-
-#include "widget.hh"
-
-namespace otk {
-
-class Application;
-
-class AppWidget : public Widget {
-
-public:
- AppWidget(Application *app, Direction direction = Horizontal, int bevel = 0);
- virtual ~AppWidget();
-
- virtual void show();
- virtual void hide();
-
- virtual void clientMessageHandler(const XClientMessageEvent &e);
-
-private:
-
- Application *_application;
-};
-
-}
-
-#endif // __appwidget_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __assassin_hh
-#define __assassin_hh
-
-namespace otk {
-
-struct PointerAssassin {
- template<typename T>
- inline void operator()(const T ptr) const {
- delete ptr;
- }
-};
-
-}
-
-#endif // __assassin_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "button.hh"
-
-namespace otk {
-
-Button::Button(Widget *parent)
- : Label(parent),
- _pressed(false)
-{
- setHorizontalJustify(RenderStyle::CenterJustify);
- setVerticalJustify(RenderStyle::CenterJustify);
- styleChanged(*RenderStyle::style(screen()));
-}
-
-Button::~Button()
-{
-}
-
-void Button::press(unsigned int mouse_button)
-{
- if (_pressed) return;
-
- _pressed = true;
- _mouse_button = mouse_button;
-
- styleChanged(*RenderStyle::style(screen()));
- refresh();
-}
-
-void Button::release(unsigned int mouse_button)
-{
- if (!_pressed || _mouse_button != mouse_button) return; // wrong button
-
- _pressed = false;
-
- styleChanged(*RenderStyle::style(screen()));
- refresh();
-}
-
-void Button::buttonPressHandler(const XButtonEvent &e)
-{
- Widget::buttonPressHandler(e);
- press(e.button);
-}
-
-void Button::buttonReleaseHandler(const XButtonEvent &e)
-{
- Widget::buttonReleaseHandler(e);
- bool p = _pressed;
- release(e.button);
- if (p && !_pressed && e.x > 0 && e.y > 0 &&
- e.x < area().width() && e.y < area().height())
- clickHandler(_mouse_button);
-}
-
-void Button::styleChanged(const RenderStyle &style)
-{
- if (isHighlighted()) {
- if (_pressed)
- _texture = style.buttonPressFocusBackground();
- else
- _texture = style.buttonUnpressFocusBackground();
- _forecolor = style.buttonFocusColor();
- } else {
- if (_pressed)
- _texture = style.buttonPressUnfocusBackground();
- else
- _texture = style.buttonUnpressUnfocusBackground();
- _forecolor = style.buttonUnfocusColor();
- }
- refresh();
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __button_hh
-#define __button_hh
-
-#include "label.hh"
-
-namespace otk {
-
-class Button : public Label {
-
-public:
- Button(Widget *parent);
- virtual ~Button();
-
- virtual inline bool isPressed() const { return _pressed; }
-
- virtual void press(unsigned int mouse_button);
- virtual void release(unsigned int mouse_button);
-
- virtual void buttonPressHandler(const XButtonEvent &e);
- virtual void buttonReleaseHandler(const XButtonEvent &e);
-
- virtual void clickHandler(unsigned int button) {(void)button;}
-
- virtual void styleChanged(const RenderStyle &style);
-
-private:
- bool _pressed;
- unsigned int _mouse_button;
-};
-
-}
-
-#endif
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "display.hh"
-#include "util.hh"
-
-extern "C" {
-#include <X11/keysym.h>
-
-#ifdef XKB
-#include <X11/XKBlib.h>
-#endif // XKB
-
-#ifdef SHAPE
-#include <X11/extensions/shape.h>
-#endif // SHAPE
-
-#ifdef XINERAMA
-#include <X11/extensions/Xinerama.h>
-#endif // XINERAMA
-
-#ifdef HAVE_SIGNAL_H
-# include <signal.h>
-#endif // HAVE_SIGNAL_H
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif // HAVE_FCNTL_H
-
-#ifdef HAVE_UNISTD_H
-# include <sys/types.h>
-# include <unistd.h>
-#endif // HAVE_UNISTD_H
-
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdio>
-
-namespace otk {
-
-
-Display *display = (Display*) 0;
-
-static int xerrorHandler(::Display *d, XErrorEvent *e)
-{
- if (!display->ignoreErrors()) {
-#ifdef DEBUG
- char errtxt[128];
-
- //if (e->error_code != BadWindow)
- {
- XGetErrorText(d, e->error_code, errtxt, 127);
- printf("X Error: %s\n", errtxt);
- if (e->error_code != BadWindow)
- abort();
- }
-#else
- (void)d;
- (void)e;
-#endif
- }
- return false;
-}
-
-
-Display::Display(::Display *d)
- : _display(d),
- _xkb(false),
- _xkb_event_basep(0),
- _shape(false),
- _shape_event_basep(0),
- _xinerama(false),
- _xinerama_event_basep(0),
- _mask_list(),
- _num_lock_mask(0),
- _scroll_lock_mask(0),
- _grab_count(0)
-{
- int junk;
- (void)junk;
-
- assert(_display);
-
- display = this;
-
- if (fcntl(ConnectionNumber(_display), F_SETFD, 1) == -1) {
- printf(_("Couldn't mark display connection as close-on-exec.\n\n"));
- ::exit(1);
- }
- if (!XSupportsLocale())
- printf(_("X server does not support locale.\n"));
- if (!XSetLocaleModifiers(""))
- printf(_("Cannot set locale modifiers for the X server.\n"));
-
- // set our error handler for X errors
- XSetErrorHandler(xerrorHandler);
-
- // set the DISPLAY environment variable for any lauched children, to the
- // display we're using, so they open in the right place.
- putenv(std::string("DISPLAY=") + DisplayString(_display));
-
- // find the availability of X extensions we like to use
-#ifdef XKB
- _xkb = XkbQueryExtension(_display, &junk, &_xkb_event_basep, &junk, NULL,
- NULL);
-#endif
-
-#ifdef SHAPE
- _shape = XShapeQueryExtension(_display, &_shape_event_basep, &junk);
-#endif
-
-#ifdef XINERAMA
- _xinerama = XineramaQueryExtension(_display, &_xinerama_event_basep, &junk);
-#endif // XINERAMA
-
- // get lock masks that are defined by the display (not constant)
- _modmap = XGetModifierMapping(_display);
- assert(_modmap);
- if (_modmap && _modmap->max_keypermod > 0) {
- const int mask_table[] = {
- ShiftMask, LockMask, ControlMask, Mod1Mask,
- Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
- };
- const size_t size = (sizeof(mask_table) / sizeof(mask_table[0])) *
- _modmap->max_keypermod;
- // get the values of the keyboard lock modifiers
- // Note: Caps lock is not retrieved the same way as Scroll and Num lock
- // since it doesn't need to be.
- const KeyCode num_lock = XKeysymToKeycode(_display, XK_Num_Lock);
- const KeyCode scroll_lock = XKeysymToKeycode(_display, XK_Scroll_Lock);
-
- for (size_t cnt = 0; cnt < size; ++cnt) {
- if (! _modmap->modifiermap[cnt]) continue;
-
- if (num_lock == _modmap->modifiermap[cnt])
- _num_lock_mask = mask_table[cnt / _modmap->max_keypermod];
- if (scroll_lock == _modmap->modifiermap[cnt])
- _scroll_lock_mask = mask_table[cnt / _modmap->max_keypermod];
- }
- }
-
- _mask_list[0] = 0;
- _mask_list[1] = LockMask;
- _mask_list[2] = _num_lock_mask;
- _mask_list[3] = LockMask | _num_lock_mask;
- _mask_list[4] = _scroll_lock_mask;
- _mask_list[5] = _scroll_lock_mask | LockMask;
- _mask_list[6] = _scroll_lock_mask | _num_lock_mask;
- _mask_list[7] = _scroll_lock_mask | LockMask | _num_lock_mask;
-
- /*
- If the default depth is at least 8 we will use that,
- otherwise we try to find the largest TrueColor visual.
- Preference is given to 24 bit over larger depths if 24 bit is an option.
- */
-
- int screen = DefaultScreen(_display);
- _depth = DefaultDepth(_display, screen);
- _visual = DefaultVisual(_display, screen);
- _colormap = DefaultColormap(_display, screen);
-
- if (_depth < 8) {
- // search for a TrueColor Visual... if we can't find one...
- // we will use the default visual for the screen
- XVisualInfo vinfo_template, *vinfo_return;
- int vinfo_nitems;
- int best = -1;
-
- vinfo_template.screen = screen;
- vinfo_template.c_class = TrueColor;
-
- vinfo_return = XGetVisualInfo(_display,
- VisualScreenMask | VisualClassMask,
- &vinfo_template, &vinfo_nitems);
- if (vinfo_return) {
- int max_depth = 1;
- for (int i = 0; i < vinfo_nitems; ++i) {
- if (vinfo_return[i].depth > max_depth) {
- if (max_depth == 24 && vinfo_return[i].depth > 24)
- break; // prefer 24 bit over 32
- max_depth = vinfo_return[i].depth;
- best = i;
- }
- }
- if (max_depth < _depth) best = -1;
- }
-
- if (best != -1) {
- _depth = vinfo_return[best].depth;
- _visual = vinfo_return[best].visual;
- _colormap = XCreateColormap(_display, RootWindow(_display, screen),
- _visual, AllocNone);
- }
-
- XFree(vinfo_return);
- }
-}
-
-
-Display::~Display()
-{
- while (_grab_count > 0)
- ungrab();
-
- XFreeModifiermap(_modmap);
-
- XCloseDisplay(_display);
-}
-
-
-void Display::setIgnoreErrors(bool t)
-{
- // sync up so that anything already sent is/isn't ignored!
- XSync(_display, false);
- _ignore_errors = t;
-}
-
-void Display::grab()
-{
- if (_grab_count == 0) {
- XGrabServer(_display);
- XSync(_display, false); // make sure it kicks in
- }
- _grab_count++;
-}
-
-
-void Display::ungrab()
-{
- if (_grab_count == 0) return;
- _grab_count--;
- if (_grab_count == 0) {
- XUngrabServer(_display);
- XFlush(_display); // ungrab as soon as possible
- }
-}
-
-
-
-
-
-
-
-/*
- * Grabs a button, but also grabs the button in every possible combination
- * with the keyboard lock keys, so that they do not cancel out the event.
-
- * if allow_scroll_lock is true then only the top half of the lock mask
- * table is used and scroll lock is ignored. This value defaults to false.
- */
-void Display::grabButton(unsigned int button, unsigned int modifiers,
- Window grab_window, bool owner_events,
- unsigned int event_mask, int pointer_mode,
- int keyboard_mode, Window confine_to,
- Cursor cursor, bool allow_scroll_lock) const
-{
- unsigned int length = (allow_scroll_lock) ? 8 / 2:
- 8;
- for (size_t cnt = 0; cnt < length; ++cnt)
- XGrabButton(_display, button, modifiers | _mask_list[cnt],
- grab_window, owner_events, event_mask, pointer_mode,
- keyboard_mode, confine_to, cursor);
-}
-
-
-/*
- * Releases the grab on a button, and ungrabs all possible combinations of the
- * keyboard lock keys.
- */
-void Display::ungrabButton(unsigned int button, unsigned int modifiers,
- Window grab_window) const
-{
- for (size_t cnt = 0; cnt < 8; ++cnt)
- XUngrabButton(_display, button, modifiers | _mask_list[cnt],
- grab_window);
-}
-
-void Display::grabKey(unsigned int keycode, unsigned int modifiers,
- Window grab_window, bool owner_events,
- int pointer_mode, int keyboard_mode,
- bool allow_scroll_lock) const
-{
- unsigned int length = (allow_scroll_lock) ? 8 / 2:
- 8;
- for (size_t cnt = 0; cnt < length; ++cnt)
- XGrabKey(_display, keycode, modifiers | _mask_list[cnt],
- grab_window, owner_events, pointer_mode, keyboard_mode);
-}
-
-void Display::ungrabKey(unsigned int keycode, unsigned int modifiers,
- Window grab_window) const
-{
- for (size_t cnt = 0; cnt < 8; ++cnt)
- XUngrabKey(_display, keycode, modifiers | _mask_list[cnt],
- grab_window);
-}
-
-void Display::ungrabAllKeys(Window grab_window) const
-{
- XUngrabKey(_display, AnyKey, AnyModifier, grab_window);
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __display_hh
-#define __display_hh
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-namespace otk {
-
-class RenderControl;
-
-class Display;
-
-//! The display instance for the library
-extern Display *display;
-
-//! Manages a single X11 display.
-class Display
-{
-private:
- //! The X display
- ::Display *_display;
-
- //! Does the display have the XKB extension?
- bool _xkb;
- //! Base for events for the XKB extension
- int _xkb_event_basep;
-
- //! Does the display have the Shape extension?
- bool _shape;
- //! Base for events for the Shape extension
- int _shape_event_basep;
-
- //! Does the display have the Xinerama extension?
- bool _xinerama;
- //! Base for events for the Xinerama extension
- int _xinerama_event_basep;
-
- //! A list of all possible combinations of keyboard lock masks
- unsigned int _mask_list[8];
-
- //! The value of the mask for the NumLock modifier
- unsigned int _num_lock_mask;
-
- //! The value of the mask for the ScrollLock modifier
- unsigned int _scroll_lock_mask;
-
- //! The key codes for the modifier keys
- XModifierKeymap *_modmap;
-
- //! The number of requested grabs on the display
- int _grab_count;
-
- //! When true, X errors will be ignored. Use with care.
- bool _ignore_errors;
-
- //! The optimal visual for the display
- Visual *_visual;
-
- //! Our colormap built for the optimal visual
- Colormap _colormap;
-
- //! The depth of our optimal visual
- int _depth;
-
-public:
- //! Wraps an open Display connection
- /*!
- @param d An open Display connection.
- */
- Display(::Display *d);
- //! Destroys the class, closes the X display
- ~Display();
-
- //! Returns if the display has the xkb extension available
- inline bool xkb() const { return _xkb; }
- //! Returns the xkb extension's event base
- inline int xkbEventBase() const { return _xkb_event_basep; }
-
- //! Returns if the display has the shape extension available
- inline bool shape() const { return _shape; }
- //! Returns the shape extension's event base
- inline int shapeEventBase() const { return _shape_event_basep; }
- //! Returns if the display has the xinerama extension available
- inline bool xinerama() const { return _xinerama; }
-
- inline unsigned int numLockMask() const { return _num_lock_mask; }
- inline unsigned int scrollLockMask() const { return _scroll_lock_mask; }
- const XModifierKeymap *modifierMap() const { return _modmap; }
-
- inline ::Display* operator*() const { return _display; }
-
- //! When true, X errors will be ignored.
- inline bool ignoreErrors() const { return _ignore_errors; }
- //! Set whether X errors should be ignored. Use with care.
- void setIgnoreErrors(bool t);
-
- //! Grabs the display
- void grab();
-
- //! Ungrabs the display
- void ungrab();
-
-
-
- /* TEMPORARY */
- void grabButton(unsigned int button, unsigned int modifiers,
- Window grab_window, bool owner_events,
- unsigned int event_mask, int pointer_mode,
- int keyboard_mode, Window confine_to, Cursor cursor,
- bool allow_scroll_lock) const;
- void ungrabButton(unsigned int button, unsigned int modifiers,
- Window grab_window) const;
- void grabKey(unsigned int keycode, unsigned int modifiers,
- Window grab_window, bool owner_events,
- int pointer_mode, int keyboard_mode,
- bool allow_scroll_lock) const;
- void ungrabKey(unsigned int keycode, unsigned int modifiers,
- Window grab_window) const;
- void ungrabAllKeys(Window grab_window) const;
-};
-
-}
-
-#endif // __display_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "eventdispatcher.hh"
-#include "display.hh"
-
-#include <cstdio>
-#include <iostream>
-
-namespace otk {
-
-EventDispatcher::EventDispatcher()
- : _fallback(0), _master(0)
-{
-}
-
-EventDispatcher::~EventDispatcher()
-{
-}
-
-void EventDispatcher::clearAllHandlers(void)
-{
- _map.clear();
-}
-
-void EventDispatcher::registerHandler(Window id, EventHandler *handler)
-{
- _map.insert(std::pair<Window, EventHandler*>(id, handler));
-}
-
-void EventDispatcher::clearHandler(Window id)
-{
- _map.erase(id);
-}
-
-void EventDispatcher::dispatchEvents(bool remote)
-{
- XEvent e;
-
- while (true) {
- /*
- There are slightly different event retrieval semantics here for local (or
- high bandwidth) versus remote (or low bandwidth) connections to the
- display/Xserver.
- */
- if (remote) {
- if (!XPending(**display))
- return;
- } else {
- /*
- This XSync allows for far more compression of events, which makes
- things like Motion events perform far far better. Since it also means
- network traffic for every event instead of every X events (where X is
- the number retrieved at a time), it probably should not be used for
- setups where Openbox is running on a remote/low bandwidth
- display/Xserver.
- */
- XSync(**display, false);
- if (!XEventsQueued(**display, QueuedAlready))
- return;
- }
- XNextEvent(**display, &e);
-
-#if 0//defined(DEBUG)
- printf("Event %d window %lx\n", e.type, e.xany.window);
-#endif
-
- if (e.type == FocusIn || e.type == FocusOut) {
- // focus events are a beast all their own.. yuk, hate, etc.
- dispatchFocus(e);
- } else {
- Window win;
-
- // pick a window
- switch (e.type) {
- case UnmapNotify:
- win = e.xunmap.window;
- break;
- case DestroyNotify:
- win = e.xdestroywindow.window;
- break;
- case ConfigureRequest:
- win = e.xconfigurerequest.window;
- break;
- default:
- win = e.xany.window;
- }
-
- // grab the lasttime and hack up the modifiers
- switch (e.type) {
- case ButtonPress:
- case ButtonRelease:
- _lasttime = e.xbutton.time;
- e.xbutton.state &= ~(LockMask | display->numLockMask() |
- display->scrollLockMask());
- break;
- case KeyPress:
- e.xkey.state &= ~(LockMask | display->numLockMask() |
- display->scrollLockMask());
- break;
- case MotionNotify:
- _lasttime = e.xmotion.time;
- e.xmotion.state &= ~(LockMask | display->numLockMask() |
- display->scrollLockMask());
- break;
- case PropertyNotify:
- _lasttime = e.xproperty.time;
- break;
- case EnterNotify:
- case LeaveNotify:
- _lasttime = e.xcrossing.time;
- if (e.xcrossing.mode != NotifyNormal)
- continue; // skip me!
- break;
- }
-
- dispatch(win, e);
- }
- }
-}
-
-void EventDispatcher::dispatchFocus(const XEvent &e)
-{
-// printf("focus %s detail %d -> 0x%lx\n",
-// (e.xfocus.type == FocusIn ? "IN" : "OUT"),
-// e.xfocus.detail, e.xfocus.window);
- // ignore focus changes from grabs
- if (e.xfocus.mode == NotifyGrab) //|| e.xfocus.mode == NotifyUngrab ||
- // From Metacity, from WindowMaker, ignore all funky pointer root events
- // its commented out cuz I don't think we need this at all. If problems
- // arise we can look into it
- //e.xfocus.detail > NotifyNonlinearVirtual)
- return;
-
- if (e.type == FocusIn) {
- //printf("Got FocusIn!\n");
-
- // send a FocusIn to whatever was just focused
- dispatch(e.xfocus.window, e);
- //printf("Sent FocusIn 0x%lx\n", e.xfocus.window);
-
- } else if (e.type == FocusOut) {
- //printf("Got FocusOut!\n");
-
- // FocusOut events just make us look for FocusIn events. They are ignored
- // otherwise.
- XEvent fi;
- if (XCheckTypedEvent(**display, FocusIn, &fi)) {
- //printf("Found FocusIn\n");
- dispatchFocus(fi);
- // dont unfocus the window we just focused!
- if (fi.xfocus.window == e.xfocus.window)
- return;
- }
-
- dispatch(e.xfocus.window, e);
- //printf("Sent FocusOut 0x%lx\n", e.xfocus.window);
- }
-}
-
-void EventDispatcher::dispatch(Window win, const XEvent &e)
-{
- EventHandler *handler = 0;
- EventMap::iterator it;
-
- // master gets everything first
- if (_master)
- _master->handle(e);
-
- // find handler for the chosen window
- it = _map.find(win);
-
- if (it != _map.end()) {
- // if we found a handler
- handler = it->second;
- } else if (e.type == ConfigureRequest) {
- // unhandled configure requests must be used to configure the window
- // directly
- XWindowChanges xwc;
-
- xwc.x = e.xconfigurerequest.x;
- xwc.y = e.xconfigurerequest.y;
- xwc.width = e.xconfigurerequest.width;
- xwc.height = e.xconfigurerequest.height;
- xwc.border_width = e.xconfigurerequest.border_width;
- xwc.sibling = e.xconfigurerequest.above;
- xwc.stack_mode = e.xconfigurerequest.detail;
-
-#ifdef DEBUG
- printf("Proxying configure event for 0x%lx\n", e.xconfigurerequest.window);
-#endif
-
- // we are not to be held responsible if someone sends us an invalid
- // request!
- display->setIgnoreErrors(true);
- XConfigureWindow(**display, e.xconfigurerequest.window,
- e.xconfigurerequest.value_mask, &xwc);
- display->setIgnoreErrors(false);
- } else {
- // grab a falback if it exists
- handler = _fallback;
- }
-
- if (handler)
- handler->handle(e);
-}
-
-EventHandler *EventDispatcher::findHandler(Window win)
-{
- EventMap::iterator it = _map.find(win);
- if (it != _map.end())
- return it->second;
- return 0;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __eventdispatcher
-#define __eventdispatcher
-
-#include "eventhandler.hh"
-#include <map>
-#include <utility>
-
-namespace otk {
-
-typedef std::map<unsigned int, EventHandler *> EventMap;
-
-class EventDispatcher {
-public:
-
- EventDispatcher();
- virtual ~EventDispatcher();
-
- virtual void clearAllHandlers(void);
- virtual void registerHandler(Window id, EventHandler *handler);
- virtual void clearHandler(Window id);
- //! Dispatch events from the X server to the appropriate EventHandlers
- /*!
- @param remote Is the Xserver on a remote (low bandwidth) connection or on a
- local (high bandwidth) connection. This allows you to specify
- 'false' in which case slightly different semantics are used
- for event retrieval.<br>
- The default is 'true' since this should generally be used,
- only the Openbox window manager should need to specify
- 'false' here.
- */
- virtual void dispatchEvents(bool remote = true);
-
- inline void setFallbackHandler(EventHandler *fallback)
- { _fallback = fallback; }
- EventHandler *getFallbackHandler(void) const { return _fallback; }
-
- //! Sets an event handler that gets all events for all handlers after
- //! any specific handlers have received them
- inline void setMasterHandler(EventHandler *master)
- { _master = master; }
- EventHandler *getMasterHandler(void) const { return _master; }
-
- EventHandler *findHandler(Window win);
-
- inline Time lastTime() const { return _lasttime; }
-
-private:
- EventMap _map;
- EventHandler *_fallback;
- EventHandler *_master;
-
- //! The time at which the last XEvent with a time was received
- Time _lasttime;
-
- void dispatch(Window win, const XEvent &e);
- void dispatchFocus(const XEvent &e);
-};
-
-}
-
-#endif
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "display.hh"
-#include "eventhandler.hh"
-
-namespace otk {
-
-EventHandler::EventHandler()
-{
-}
-
-
-EventHandler::~EventHandler()
-{
-}
-
-
-void EventHandler::handle(const XEvent &e)
-{
- switch(e.type){
- case KeyPress:
- return keyPressHandler(e.xkey);
- case KeyRelease:
- return keyReleaseHandler(e.xkey);
- case ButtonPress:
- return buttonPressHandler(e.xbutton);
- case ButtonRelease:
- return buttonReleaseHandler(e.xbutton);
- case MotionNotify:
- return motionHandler(e.xmotion);
- case EnterNotify:
- return enterHandler(e.xcrossing);
- case LeaveNotify:
- return leaveHandler(e.xcrossing);
- case FocusIn:
- return focusHandler(e.xfocus);
- case FocusOut:
- return unfocusHandler(e.xfocus);
- case Expose:
- return exposeHandler(e.xexpose);
- case GraphicsExpose:
- return graphicsExposeHandler(e.xgraphicsexpose);
- case NoExpose:
- return noExposeEventHandler(e.xnoexpose);
- case CirculateRequest:
- return circulateRequestHandler(e.xcirculaterequest);
- case ConfigureRequest:
- return configureRequestHandler(e.xconfigurerequest);
- case MapRequest:
- return mapRequestHandler(e.xmaprequest);
- case ResizeRequest:
- return resizeRequestHandler(e.xresizerequest);
- case CirculateNotify:
- return circulateHandler(e.xcirculate);
- case ConfigureNotify:
- return configureHandler(e.xconfigure);
- case CreateNotify:
- return createHandler(e.xcreatewindow);
- case DestroyNotify:
- return destroyHandler(e.xdestroywindow);
- case GravityNotify:
- return gravityHandler(e.xgravity);
- case MapNotify:
- return mapHandler(e.xmap);
- case MappingNotify:
- return mappingHandler(e.xmapping);
- case ReparentNotify:
- return reparentHandler(e.xreparent);
- case UnmapNotify:
- return unmapHandler(e.xunmap);
- case VisibilityNotify:
- return visibilityHandler(e.xvisibility);
- case ColormapNotify:
- return colorMapHandler(e.xcolormap);
- case ClientMessage:
- return clientMessageHandler(e.xclient);
- case PropertyNotify:
- return propertyHandler(e.xproperty);
- case SelectionClear:
- return selectionClearHandler(e.xselectionclear);
- case SelectionNotify:
- return selectionHandler(e.xselection);
- case SelectionRequest:
- return selectionRequestHandler(e.xselectionrequest);
- default:
-#ifdef SHAPE
- if (e.type == display->shapeEventBase())
- return shapeHandler((*(XShapeEvent*)&e));
-#endif // SHAPE
-#ifdef XKB
- if (e.type == display->xkbEventBase())
- return xkbHandler((*(XkbEvent*)&e));
-#endif // XKB
- ;
- }
-}
-
-
-void EventHandler::clientMessageHandler(const XClientMessageEvent &)
-{
-
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __eventhandler__hh
-#define __eventhandler__hh
-
-extern "C" {
-#include <X11/Xlib.h>
-
-#ifdef SHAPE
-#include <X11/extensions/shape.h>
-#endif // SHAPE
-
-#ifdef XKB
-#include <X11/XKBlib.h>
-#endif // XKB
-
-}
-
-namespace otk {
-
-class EventHandler {
-public:
- //! Dispatches events to one of the other handlers based on their type.
- virtual void handle(const XEvent &e);
-
- //! Called whenever any key is pressed.
- virtual void keyPressHandler(const XKeyEvent &) {}
-
- //! Called whenever any key is released.
- virtual void keyReleaseHandler(const XKeyEvent &) {}
-
- //! Called whenever a button of the pointer is pressed.
- virtual void buttonPressHandler(const XButtonEvent &) {}
-
- //! Called whenever a button of the pointer is released.
- virtual void buttonReleaseHandler(const XButtonEvent &) {}
-
- //! Called whenever the pointer moved
- virtual void motionHandler(const XMotionEvent &) {}
-
- //! Called whenever the pointer enters a window.
- virtual void enterHandler(const XCrossingEvent &) {}
-
- //! Called whenever the pointer leaves a window.
- virtual void leaveHandler(const XCrossingEvent &) {}
-
- //! Called when a window gains focus.
- virtual void focusHandler(const XFocusChangeEvent &) {}
-
- //! Called when a window looses focus.
- virtual void unfocusHandler(const XFocusChangeEvent &) {}
-
- //! Called when a window becomes visible to the user.
- virtual void exposeHandler(const XExposeEvent &) {}
-
- //! Called to handle GraphicsExpose events.
- virtual void graphicsExposeHandler(const XGraphicsExposeEvent &) {}
-
- //! Called to handle NoExpose events.
- virtual void noExposeEventHandler(const XNoExposeEvent &) {}
-
- //! Called when the window requests a change in its z-order.
- virtual void circulateRequestHandler(const XCirculateRequestEvent &)
- {}
-
- //! Called when a different client initiates a configure window request.
- virtual void configureRequestHandler(const XConfigureRequestEvent &)
- {}
-
- //! Called when a different client tries to map a window.
- virtual void mapRequestHandler(const XMapRequestEvent &) {}
-
- //! Called when another client attemps to change the size of a window.
- virtual void resizeRequestHandler(const XResizeRequestEvent &) {}
-
- //! Called when the z-order of the window has changed.
- virtual void circulateHandler(const XCirculateEvent &) {}
-
- //! Called when the window as been reconfigured.
- virtual void configureHandler(const XConfigureEvent &) {}
-
- //! Called when a window is created.
- virtual void createHandler(const XCreateWindowEvent &) {}
-
- //! Called when a window is destroyed.
- virtual void destroyHandler(const XDestroyWindowEvent &) {}
-
- //! Called when a window is moved because of a change in the size of its
- //! parent.
- virtual void gravityHandler(const XGravityEvent &) {}
-
- //! Called when a window is mapped.
- virtual void mapHandler(const XMapEvent &) {}
-
- //! Called when the server generats a MappingNotify event
- virtual void mappingHandler(const XMappingEvent &) {}
-
- //! Called when a window is reparented
- virtual void reparentHandler(const XReparentEvent &) {}
-
- //! Called when a window is unmapped
- virtual void unmapHandler(const XUnmapEvent &) {}
-
- //! Called when a the visibilty of a window changes
- virtual void visibilityHandler(const XVisibilityEvent &) {}
-
- //! Called when the colormap changes, or is installed or unistalled
- virtual void colorMapHandler(const XColormapEvent &) {}
-
- //! Called when a property of a window changes
- virtual void propertyHandler(const XPropertyEvent &) {}
-
- //! Called when the client loses ownership of a selection
- virtual void selectionClearHandler(const XSelectionClearEvent &) {}
-
- //! Called when a ConvertSelection protocol request is sent
- virtual void selectionHandler(const XSelectionEvent &) {}
-
- //! Called when a SelectionEvent occurs
- virtual void selectionRequestHandler(const XSelectionRequestEvent &) {}
-
- //! Called when a client calls XSendEvent
- /*!
- Some types of client messages are filtered out and sent to more specific
- event handler functions.
- */
- virtual void clientMessageHandler(const XClientMessageEvent &);
-
-#if defined(SHAPE) || defined(DOXYGEN_IGNORE)
- //! Called when a shape extension event fires
- virtual void shapeHandler(const XShapeEvent &) {}
-#endif // SHAPE
-
-#if defined(XKB) || defined(DOXYGEN_IGNORE)
- //! Called when an xkb extension event fires
- virtual void xkbHandler(const XkbEvent &) {}
-#endif // XKB
-
- virtual ~EventHandler();
-
-protected:
- /*! Constructor for the EventHandler class.
- This is protected so that EventHandlers can't be instantiated on their
- own.
- */
- EventHandler();
-
-private:
-};
-
-}
-
-#endif
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "font.hh"
-#include "surface.hh"
-#include "util.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-
-extern "C" {
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdio>
-#include <cstdlib>
-#include <iostream>
-#include <algorithm>
-
-namespace otk {
-
-bool Font::_xft_init = false;
-
-Font::Font(int screen_num, const std::string &fontstring,
- bool shadow, unsigned char offset, unsigned char tint)
- : _screen_num(screen_num),
- _fontstring(fontstring),
- _shadow(shadow),
- _offset(offset),
- _tint(tint),
- _xftfont(0)
-{
- assert(screen_num >= 0);
- assert(tint <= CHAR_MAX);
-
- if (!_xft_init) {
- if (!XftInit(0)) {
- printf(_("Couldn't initialize Xft.\n\n"));
- ::exit(3);
- }
-#ifdef DEBUG
- int version = XftGetVersion();
- printf("Using Xft %d.%d.%d (Built against %d.%d.%d).\n",
- version / 10000 % 100, version / 100 % 100, version % 100,
- XFT_MAJOR, XFT_MINOR, XFT_REVISION);
-#endif
- _xft_init = true;
- }
-
- if ((_xftfont = XftFontOpenName(**display, _screen_num,
- _fontstring.c_str())))
- return;
-
- printf(_("Unable to load font: %s\n"), _fontstring.c_str());
- printf(_("Trying fallback font: %s\n"), "fixed");
-
- if ((_xftfont = XftFontOpenName(**display, _screen_num,
- "fixed")))
- return;
-
- printf(_("Unable to load font: %s\n"), "fixed");
- printf(_("Aborting!.\n"));
-
- ::exit(3); // can't continue without a font
-}
-
-
-Font::~Font(void)
-{
- if (_xftfont)
- XftFontClose(**display, _xftfont);
-}
-
-
-int Font::measureString(const ustring &string) const
-{
- XGlyphInfo info;
-
- if (string.utf8())
- XftTextExtentsUtf8(**display, _xftfont,
- (FcChar8*)string.c_str(), string.bytes(), &info);
- else
- XftTextExtents8(**display, _xftfont,
- (FcChar8*)string.c_str(), string.bytes(), &info);
-
- return (signed) info.xOff + (_shadow ? _offset : 0);
-}
-
-
-int Font::height(void) const
-{
- return (signed) _xftfont->height + (_shadow ? _offset : 0);
-}
-
-
-int Font::maxCharWidth(void) const
-{
- return (signed) _xftfont->max_advance_width;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __font_hh
-#define __font_hh
-
-#include "ustring.hh"
-#include "truerendercontrol.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-#define _XFT_NO_COMPAT_ // no Xft 1 API
-#include <X11/Xft/Xft.h>
-}
-
-#include <cassert>
-
-namespace otk {
-
-class Color;
-class Surface;
-
-class Font {
- /*
- * static members
- */
-private:
- static bool _xft_init;
-
- int _screen_num;
-
- std::string _fontstring;
-
- bool _shadow;
- unsigned char _offset;
- unsigned char _tint;
-
- XftFont *_xftfont;
-
- bool createXftFont(void);
-
-public:
- // loads an Xft font
- Font(int screen_num, const std::string &fontstring, bool shadow,
- unsigned char offset, unsigned char tint);
- virtual ~Font();
-
- inline const std::string &fontstring() const { return _fontstring; }
-
- int height() const;
- int maxCharWidth() const;
-
- int measureString(const ustring &string) const;
-
- // The RenderControl classes use the internal data to render the fonts, but
- // noone else needs it, so its private.
- friend class RenderControl;
-};
-
-}
-
-#endif // __font_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "label.hh"
-#include "display.hh"
-#include "rendercontrol.hh"
-
-#include <string>
-
-namespace otk {
-
-Label::Label(int screen, EventDispatcher *ed, int bevel)
- : Widget(screen, ed, Widget::Horizontal, bevel, true),
- _text(""),
- _font(0),
- _justify_horz(RenderStyle::LeftTopJustify),
- _justify_vert(RenderStyle::LeftTopJustify),
- _highlight(false)
-{
- styleChanged(*RenderStyle::style(screen));
-}
-
-Label::Label(Widget *parent)
- : Widget(parent),
- _text(""),
- _font(0),
- _justify_horz(RenderStyle::LeftTopJustify),
- _justify_vert(RenderStyle::LeftTopJustify),
- _highlight(false)
-{
- styleChanged(*RenderStyle::style(screen()));
-}
-
-Label::~Label()
-{
-}
-
-void Label::setHorizontalJustify(RenderStyle::Justify j)
-{
- _justify_horz = j;
- refresh();
-}
-
-void Label::setVerticalJustify(RenderStyle::Justify j)
-{
- _justify_vert = j;
- refresh();
-}
-
-void Label::setHighlighted(bool h)
-{
- _highlight = h;
- styleChanged(*RenderStyle::style(screen()));
- refresh();
-}
-
-void Label::setText(const ustring &text)
-{
- bool utf = text.utf8();
- std::string s = text.c_str(); // use a normal string, for its functionality
-
- _parsedtext.clear();
- _text = text;
-
- // parse it into multiple lines
- std::string::size_type p = 0;
- while (p != std::string::npos) {
- std::string::size_type p2 = s.find('\n', p);
- std::string s(s.substr(p, (p2==std::string::npos?p2:p2-p)));
-
- // turn tabs into spaces (multiples of 8)
- std::string::size_type t;
- while ((t = s.find('\t')) != std::string::npos)
- s.replace(t, 1, std::string(8 - t % 8, ' '));
-
- _parsedtext.push_back(s);
- _parsedtext.back().setUtf8(utf);
- p = (p2==std::string::npos?p2:p2+1);
- }
- calcDefaultSizes();
-}
-
-void Label::setFont(const Font *f)
-{
- _font = f;
- calcDefaultSizes();
-}
-
-void Label::calcDefaultSizes()
-{
- int longest = 0;
- // find the longest line
- std::vector<ustring>::iterator it, end = _parsedtext.end();
- for (it = _parsedtext.begin(); it != end; ++it) {
- int length = _font->measureString(*it);
- if (length < 0) continue; // lines too long get skipped
- if (length > longest) longest = length;
- }
- setMinSize(Size(longest + borderWidth() * 2 + bevel() * 4,
- _parsedtext.size() * _font->height() + borderWidth() * 2 +
- bevel() * 2));
-}
-
-void Label::styleChanged(const RenderStyle &style)
-{
- if (_highlight) {
- _texture = style.labelFocusBackground();
- _forecolor = style.textFocusColor();
- } else {
- _texture = style.labelUnfocusBackground();
- _forecolor = style.textUnfocusColor();
- }
- if (_font != style.labelFont()) {
- _font = style.labelFont();
- calcDefaultSizes();
- }
-}
-
-void Label::renderForeground(Surface &surface)
-{
- const RenderControl *control = display->renderControl(screen());
- int sidemargin = bevel() * 2;
- int y = bevel();
- int w = area().width() - borderWidth() * 2 - sidemargin * 2;
- int h = area().height() - borderWidth() * 2 - bevel() * 2;
-
- switch (_justify_vert) {
- case RenderStyle::RightBottomJustify:
- y += h - (_parsedtext.size() * _font->height());
- if (y < bevel()) y = bevel();
- break;
- case RenderStyle::CenterJustify:
- y += (h - (_parsedtext.size() * _font->height())) / 2;
- if (y < bevel()) y = bevel();
- break;
- case RenderStyle::LeftTopJustify:
- break;
- }
-
- if (w <= 0) return; // can't fit anything
-
- std::vector<ustring>::iterator it, end = _parsedtext.end();
- for (it = _parsedtext.begin(); it != end; ++it, y += _font->height()) {
- ustring t = *it; // the actual text to draw
- int x = sidemargin; // x coord for the text
-
- // find a string that will fit inside the area for text
- ustring::size_type text_len = t.size();
- int length;
-
- do {
- t.resize(text_len);
- length = _font->measureString(t);
- } while (length > w && text_len-- > 0);
- if (length < 0) continue; // lines too long get skipped
-
- if (text_len <= 0) continue; // won't fit anything
-
- // justify the text
- switch (_justify_horz) {
- case RenderStyle::RightBottomJustify:
- x += w - length;
- break;
- case RenderStyle::CenterJustify:
- x += (w - length) / 2;
- break;
- case RenderStyle::LeftTopJustify:
- break;
- }
-
- control->drawString(surface, *_font, x, y, *_forecolor, t);
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __label_hh
-#define __label_hh
-
-#include "widget.hh"
-#include "ustring.hh"
-#include "renderstyle.hh"
-#include "font.hh"
-
-#include <vector>
-
-namespace otk {
-
-class Label : public Widget {
-
-public:
- Label(int screen, EventDispatcher *ed, int bevel = 3);
- Label(Widget *parent);
- virtual ~Label();
-
- inline const ustring& text(void) const { return _text; }
- void setText(const ustring &text);
-
- virtual inline bool isHighlighted() const { return _highlight; }
- virtual void setHighlighted(bool h);
-
- RenderStyle::Justify horizontalJustify() const { return _justify_horz; }
- virtual void setHorizontalJustify(RenderStyle::Justify j);
- RenderStyle::Justify verticalJustify() const { return _justify_vert; }
- virtual void setVerticalJustify(RenderStyle::Justify j);
-
- const Font *font() const { return _font; }
- virtual void setFont(const Font *f);
-
- virtual void styleChanged(const RenderStyle &style);
-
- virtual void renderForeground(Surface &surface);
-
-protected:
- virtual void calcDefaultSizes();
-
- //! The color the label will use for rendering its text
- RenderColor *_forecolor;
-
-private:
- //! Text to be displayed in the label
- ustring _text;
- //! Text to be displayed, parsed into its separate lines
- std::vector<ustring> _parsedtext;
- //! The actual text being shown, may be a subset of _text
- ustring _drawtext;
- //! The font the text will be rendered with
- const Font *_font;
- //! The horizontal justification used for drawing text
- RenderStyle::Justify _justify_horz;
- //! The vertical justification used for drawing text
- RenderStyle::Justify _justify_vert;
- //! The drawing offset for the text
- int _drawx;
- //! If the widget is highlighted or not
- bool _highlight;
-};
-
-}
-
-#endif
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "messagedialog.hh"
-#include "assassin.hh"
-#include "button.hh"
-#include "label.hh"
-#include "display.hh"
-#include "property.hh"
-#include "eventdispatcher.hh"
-#include "timer.hh"
-
-#include <algorithm>
-
-namespace otk {
-
-class DialogButtonWidget : public Button {
- MessageDialog *_dia;
-public:
- DialogButtonWidget(Widget *parent, MessageDialog *dia,
- const DialogButton &b)
- : Button(parent),
- _dia(dia)
- {
- assert(dia);
- setBevel(1);
- setMaxSize(Size(0,0));
- setText(b.label());
- setHighlighted(b.isDefault());
- show();
- }
-
- virtual void buttonPressHandler(const XButtonEvent &e) {
- // limit to the left button
- if (e.button == Button1)
- Button::buttonPressHandler(e);
- }
- virtual void clickHandler(unsigned int) {
- _dia->setResult(DialogButton(text(), isHighlighted()));
- _dia->hide();
- }
-};
-
-MessageDialog::MessageDialog(int screen, EventDispatcher *ed, ustring title,
- ustring caption)
- : Widget(screen, ed, Widget::Vertical),
- _result("", false)
-{
- init(title, caption);
-}
-
-MessageDialog::MessageDialog(EventDispatcher *ed, ustring title,
- ustring caption)
- : Widget(DefaultScreen(**display), ed, Widget::Vertical),
- _result("", false)
-{
- init(title, caption);
-}
-
-MessageDialog::MessageDialog(Widget *parent, ustring title, ustring caption)
- : Widget(parent, Widget::Vertical),
- _result("", false)
-{
- init(title, caption);
-}
-
-void MessageDialog::init(const ustring &title, const ustring &caption)
-{
- _label = new Label(this);
- _label->show();
- _label->setHighlighted(true);
- _button_holder = new Widget(this, Widget::Horizontal);
- _button_holder->show();
- _return = XKeysymToKeycode(**display, XStringToKeysym("Return"));
- _escape = XKeysymToKeycode(**display, XStringToKeysym("Escape"));
-
- setEventMask(eventMask() | KeyPressMask);
- _label->setText(caption);
- if (title.utf8())
- otk::Property::set(window(), otk::Property::atoms.net_wm_name,
- otk::Property::utf8, title);
- otk::Property::set(window(), otk::Property::atoms.wm_name,
- otk::Property::ascii, otk::ustring(title.c_str(), false));
-
- // set WM Protocols on the window
- Atom protocols[2];
- protocols[0] = Property::atoms.wm_protocols;
- protocols[1] = Property::atoms.wm_delete_window;
- XSetWMProtocols(**display, window(), protocols, 2);
-}
-
-MessageDialog::~MessageDialog()
-{
- if (visible()) hide();
- delete _button_holder;
- delete _label;
-}
-
-const DialogButton& MessageDialog::run()
-{
- if (!visible())
- show();
-
- while (visible()) {
- dispatcher()->dispatchEvents();
- if (visible())
- Timer::dispatchTimers(); // fire pending events
- }
- return _result;
-}
-
-void MessageDialog::addButton(const DialogButton &b)
-{
- _button_widgets.push_back(new DialogButtonWidget(_button_holder,
- this, b));
-}
-
-void MessageDialog::focus()
-{
- if (visible())
- XSetInputFocus(**display, window(), None, CurrentTime);
-}
-
-void MessageDialog::show()
-{
- Rect r;
-
- if (parent())
- r = parent()->area();
- else
- r = Rect(Point(0, 0), display->screenInfo(screen())->size());
-
- XSizeHints size;
- size.flags = PMinSize | PPosition | PWinGravity;
- size.min_width = minSize().width();
- size.min_height = minSize().height();
- size.win_gravity = CenterGravity;
-
- Size dest = minSize();
- if (dest.width() < 200 || dest.height() < 100) {
- if (dest.width() < 200 && dest.height() < 100) dest = Size(200, 100);
- else if (dest.width() < 200) dest = Size(200, dest.height());
- else dest = Size(dest.width(), 100);
- resize(dest);
- }
-
- // center it above its parent
- move(Point(r.x() + (r.width() - dest.width()) / 2,
- r.y() + (r.height() - dest.height()) / 2));
-
- XSetWMNormalHints(**display, window(), &size);
-
- Widget::show();
-}
-
-void MessageDialog::hide()
-{
- Widget::hide();
- std::for_each(_button_widgets.begin(), _button_widgets.end(),
- PointerAssassin());
-}
-
-void MessageDialog::keyPressHandler(const XKeyEvent &e)
-{
- if (e.keycode == _return) {
- std::vector<Button *>::const_iterator it, end = _button_widgets.end();
- for (it = _button_widgets.begin(); it != end; ++it)
- if ((*it)->isHighlighted()) {
- _result = DialogButton((*it)->text(), true);
- hide();
- break;
- }
- } else if (e.keycode == _escape) {
- hide();
- }
-}
-
-void MessageDialog::clientMessageHandler(const XClientMessageEvent &e)
-{
- EventHandler::clientMessageHandler(e);
- if (e.message_type == Property::atoms.wm_protocols &&
- static_cast<Atom>(e.data.l[0]) == Property::atoms.wm_delete_window)
- hide();
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __messagedialog_hh
-#define __messagedialog_hh
-
-#include "widget.hh"
-#include "ustring.hh"
-
-#include <vector>
-
-namespace otk {
-
-class Button;
-class Label;
-
-class DialogButton {
- ustring _label;
- bool _default;
-public:
- DialogButton(ustring label) : _label(label), _default(false)
- {}
- DialogButton(ustring label, bool def) : _label(label), _default(def)
- {}
- inline const ustring& label() const { return _label; }
- inline const bool& isDefault() const { return _default; }
-
- bool operator==(const DialogButton &o) const { return _label == o._label; }
- bool operator!=(const DialogButton &o) const { return!(_label == o._label); }
-};
-
-class MessageDialog : public Widget {
-public:
- MessageDialog(int screen, EventDispatcher *ed, ustring title,
- ustring caption);
- MessageDialog(EventDispatcher *ed, ustring title, ustring caption);
- MessageDialog(Widget *parent, ustring title, ustring caption);
- virtual ~MessageDialog();
-
- virtual void addButton(const DialogButton &b);
-
- virtual const DialogButton& run();
-
- virtual void show();
- virtual void hide();
- virtual void focus();
-
- virtual const DialogButton& result() const { return _result; }
- virtual void setResult(const DialogButton &result) { _result = result; }
-
- virtual void keyPressHandler(const XKeyEvent &e);
- virtual void clientMessageHandler(const XClientMessageEvent &e);
-
-private:
- void init(const ustring &title, const ustring &caption);
-
-protected:
- std::vector<Button *> _button_widgets;
- Label *_label;
- Widget *_button_holder;
- KeyCode _return;
- KeyCode _escape;
- DialogButton _result;
-};
-
-}
-
-#endif // __messagedialog_hh
+++ /dev/null
-#include "display.hh"
-#include "timer.hh"
-#include "renderstyle.hh"
-#include "property.hh"
-
-namespace otk {
-
-void initialize()
-{
- new Display();
- Timer::initialize();
- RenderColor::initialize();
- RenderStyle::initialize();
- Property::initialize();
-}
-
-void destroy()
-{
- RenderStyle::destroy();
- RenderColor::destroy();
- Timer::destroy();
- delete display;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __otk_hh
-#define __otk_hh
-
-#include "config.h"
-
-#include "eventdispatcher.hh"
-#include "eventhandler.hh"
-#include "widget.hh"
-#include "appwidget.hh"
-#include "application.hh"
-#include "assassin.hh"
-#include "label.hh"
-#include "button.hh"
-#include "rendercolor.hh"
-#include "display.hh"
-#include "font.hh"
-#include "messagedialog.hh"
-#include "rendercontrol.hh"
-#include "size.hh"
-#include "point.hh"
-#include "property.hh"
-#include "rect.hh"
-#include "screeninfo.hh"
-#include "strut.hh"
-#include "renderstyle.hh"
-#include "surface.hh"
-#include "rendertexture.hh"
-#include "timer.hh"
-#include "util.hh"
-#include "ustring.hh"
-#include "widget.hh"
-
-namespace otk {
-void initialize();
-void destroy();
-}
-
-#endif // __otk_hh
+++ /dev/null
-prefix=@prefix@
-exec_prefix=${prefix}
-libdir=${exec_prefix}/lib
-includedir=${prefix}/include
-
-Name: otk
-Description: Openbox Toolkit
-Version: @version@
-Requires: xft
-Libs: -L${libdir} -lotk
-Cflags: -I${includedir}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "application.hh"
-#include "appwidget.hh"
-#include "label.hh"
-#include "button.hh"
-
-int main(int argc, char **argv) {
- otk::Application app(argc, argv);
-
- otk::AppWidget foo(&app, otk::Widget::Vertical, 3);
- otk::Label lab(&foo);
- otk::Label lab2(&foo);
- otk::Button but(&foo);
- otk::Button but2(&foo);
-
- foo.resize(otk::Size(100, 150));
-
- lab.setText("Hi, I'm a sexy\nlabel!!!");
- lab.setMaxSize(otk::Size(0,0));
- lab2.setText("Me too!!");
- lab2.setBorderWidth(10);
- lab2.setBorderColor(otk::RenderStyle::style(app.screen())->buttonFocusColor());
- but.setText("Im not the default button...");
- but2.setText("But I AM!!");
- but2.setHighlighted(true);
-
-
- foo.show();
-
- app.run();
-
- return 0;
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __point_hh
-#define __point_hh
-
-namespace otk {
-
-class Point {
- int _x, _y;
-public:
- Point() : _x(0), _y(0) {}
- Point(int x, int y) : _x(x), _y(y) {}
- Point(const Point &p) : _x(p._x), _y(p._y) {}
-
- inline int x() const { return _x; }
- inline int y() const { return _y; }
-
- bool operator==(const Point &o) const { return _x == o._x && _y == o._y; }
- bool operator!=(const Point &o) const { return _x != o._x || _y != o._y; }
-};
-
-}
-
-#endif // __point_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "property.hh"
-#include "display.hh"
-
-extern "C" {
-#include <X11/Xatom.h>
-}
-
-#include <algorithm>
-#include <cassert>
-
-namespace otk {
-
-Atoms Property::atoms;
-
-static Atom create(char *name) { return XInternAtom(**display, name, false); }
-
-void Property::initialize()
-{
- assert(display);
-
- // make sure asserts fire if there is a problem
- memset(&atoms, 0, sizeof(Atoms));
-
- atoms.cardinal = XA_CARDINAL;
- atoms.window = XA_WINDOW;
- atoms.pixmap = XA_PIXMAP;
- atoms.atom = XA_ATOM;
- atoms.string = XA_STRING;
- atoms.utf8 = create("UTF8_STRING");
-
- atoms.openbox_pid = create("_OPENBOX_PID");
-
- atoms.wm_colormap_windows = create("WM_COLORMAP_WINDOWS");
- atoms.wm_protocols = create("WM_PROTOCOLS");
- atoms.wm_state = create("WM_STATE");
- atoms.wm_change_state = create("WM_CHANGE_STATE");
- atoms.wm_delete_window = create("WM_DELETE_WINDOW");
- atoms.wm_take_focus = create("WM_TAKE_FOCUS");
- atoms.wm_name = create("WM_NAME");
- atoms.wm_icon_name = create("WM_ICON_NAME");
- atoms.wm_class = create("WM_CLASS");
- atoms.wm_window_role = create("WM_WINDOW_ROLE");
- atoms.motif_wm_hints = create("_MOTIF_WM_HINTS");
-
- atoms.openbox_show_root_menu = create("_OPENBOX_SHOW_ROOT_MENU");
- atoms.openbox_show_workspace_menu = create("_OPENBOX_SHOW_WORKSPACE_MENU");
-
- atoms.net_supported = create("_NET_SUPPORTED");
- atoms.net_client_list = create("_NET_CLIENT_LIST");
- atoms.net_client_list_stacking = create("_NET_CLIENT_LIST_STACKING");
- atoms.net_number_of_desktops = create("_NET_NUMBER_OF_DESKTOPS");
- atoms.net_desktop_geometry = create("_NET_DESKTOP_GEOMETRY");
- atoms.net_desktop_viewport = create("_NET_DESKTOP_VIEWPORT");
- atoms.net_current_desktop = create("_NET_CURRENT_DESKTOP");
- atoms.net_desktop_names = create("_NET_DESKTOP_NAMES");
- atoms.net_active_window = create("_NET_ACTIVE_WINDOW");
- atoms.net_workarea = create("_NET_WORKAREA");
- atoms.net_supporting_wm_check = create("_NET_SUPPORTING_WM_CHECK");
-// atoms.net_virtual_roots = create("_NET_VIRTUAL_ROOTS");
- atoms.net_desktop_layout = create("_NET_DESKTOP_LAYOUT");
- atoms.net_showing_desktop = create("_NET_SHOWING_DESKTOP");
-
- atoms.net_close_window = create("_NET_CLOSE_WINDOW");
- atoms.net_wm_moveresize = create("_NET_WM_MOVERESIZE");
-
-// atoms.net_properties = create("_NET_PROPERTIES");
- atoms.net_wm_name = create("_NET_WM_NAME");
- atoms.net_wm_visible_name = create("_NET_WM_VISIBLE_NAME");
- atoms.net_wm_icon_name = create("_NET_WM_ICON_NAME");
- atoms.net_wm_visible_icon_name = create("_NET_WM_VISIBLE_ICON_NAME");
- atoms.net_wm_desktop = create("_NET_WM_DESKTOP");
- atoms.net_wm_window_type = create("_NET_WM_WINDOW_TYPE");
- atoms.net_wm_state = create("_NET_WM_STATE");
- atoms.net_wm_strut = create("_NET_WM_STRUT");
-// atoms.net_wm_icon_geometry = create("_NET_WM_ICON_GEOMETRY");
- atoms.net_wm_icon = create("_NET_WM_ICON");
-// atoms.net_wm_pid = create("_NET_WM_PID");
-// atoms.net_wm_handled_icons = create("_NET_WM_HANDLED_ICONS");
- atoms.net_wm_allowed_actions = create("_NET_WM_ALLOWED_ACTIONS");
-
-// atoms.net_wm_ping = create("_NET_WM_PING");
-
- atoms.net_wm_window_type_desktop = create("_NET_WM_WINDOW_TYPE_DESKTOP");
- atoms.net_wm_window_type_dock = create("_NET_WM_WINDOW_TYPE_DOCK");
- atoms.net_wm_window_type_toolbar = create("_NET_WM_WINDOW_TYPE_TOOLBAR");
- atoms.net_wm_window_type_menu = create("_NET_WM_WINDOW_TYPE_MENU");
- atoms.net_wm_window_type_utility = create("_NET_WM_WINDOW_TYPE_UTILITY");
- atoms.net_wm_window_type_splash = create("_NET_WM_WINDOW_TYPE_SPLASH");
- atoms.net_wm_window_type_dialog = create("_NET_WM_WINDOW_TYPE_DIALOG");
- atoms.net_wm_window_type_normal = create("_NET_WM_WINDOW_TYPE_NORMAL");
-
- atoms.net_wm_moveresize_size_topleft =
- create("_NET_WM_MOVERESIZE_SIZE_TOPLEFT");
- atoms.net_wm_moveresize_size_topright =
- create("_NET_WM_MOVERESIZE_SIZE_TOPRIGHT");
- atoms.net_wm_moveresize_size_bottomleft =
- create("_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT");
- atoms.net_wm_moveresize_size_bottomright =
- create("_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT");
- atoms.net_wm_moveresize_move =
- create("_NET_WM_MOVERESIZE_MOVE");
-
- atoms.net_wm_action_move = create("_NET_WM_ACTION_MOVE");
- atoms.net_wm_action_resize = create("_NET_WM_ACTION_RESIZE");
- atoms.net_wm_action_minimize = create("_NET_WM_ACTION_MINIMIZE");
- atoms.net_wm_action_shade = create("_NET_WM_ACTION_SHADE");
- atoms.net_wm_action_stick = create("_NET_WM_ACTION_STICK");
- atoms.net_wm_action_maximize_horz = create("_NET_WM_ACTION_MAXIMIZE_HORZ");
- atoms.net_wm_action_maximize_vert = create("_NET_WM_ACTION_MAXIMIZE_VERT");
- atoms.net_wm_action_fullscreen = create("_NET_WM_ACTION_FULLSCREEN");
- atoms.net_wm_action_change_desktop =
- create("_NET_WM_ACTION_CHANGE_DESKTOP");
- atoms.net_wm_action_close = create("_NET_WM_ACTION_CLOSE");
-
- atoms.net_wm_state_modal = create("_NET_WM_STATE_MODAL");
- atoms.net_wm_state_sticky = create("_NET_WM_STATE_STICKY");
- atoms.net_wm_state_maximized_vert = create("_NET_WM_STATE_MAXIMIZED_VERT");
- atoms.net_wm_state_maximized_horz = create("_NET_WM_STATE_MAXIMIZED_HORZ");
- atoms.net_wm_state_shaded = create("_NET_WM_STATE_SHADED");
- atoms.net_wm_state_skip_taskbar = create("_NET_WM_STATE_SKIP_TASKBAR");
- atoms.net_wm_state_skip_pager = create("_NET_WM_STATE_SKIP_PAGER");
- atoms.net_wm_state_hidden = create("_NET_WM_STATE_HIDDEN");
- atoms.net_wm_state_fullscreen = create("_NET_WM_STATE_FULLSCREEN");
- atoms.net_wm_state_above = create("_NET_WM_STATE_ABOVE");
- atoms.net_wm_state_below = create("_NET_WM_STATE_BELOW");
-
- atoms.net_wm_state_add = 1;
- atoms.net_wm_state_remove = 0;
- atoms.net_wm_state_toggle = 2;
-
- atoms.kde_net_system_tray_windows = create("_KDE_NET_SYSTEM_TRAY_WINDOWS");
- atoms.kde_net_wm_system_tray_window_for =
- create("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
- atoms.kde_net_wm_window_type_override =
- create("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
-
- atoms.kwm_win_icon = create("KWM_WIN_ICON");
-
- atoms.rootpmapid = create("_XROOTPMAP_ID");
- atoms.esetrootid = create("ESETROOT_PMAP_ID");
-
- atoms.openbox_premax = create("_OPENBOX_PREMAX");
- atoms.openbox_active_window = create("_OPENBOX_ACTIVE_WINDOW");
- atoms.openbox_restack_window = create("_OPENBOX_RESTACK_WINDOW");
-}
-
-void Property::set(Window win, Atom atom, Atom type, unsigned char* data,
- int size, int nelements, bool append)
-{
- assert(win != None); assert(atom != None); assert(type != None);
- assert(nelements == 0 || (nelements > 0 && data != (unsigned char *) 0));
- assert(size == 8 || size == 16 || size == 32);
- XChangeProperty(**display, win, atom, type, size,
- (append ? PropModeAppend : PropModeReplace),
- data, nelements);
-}
-
-void Property::set(Window win, Atom atom, Atom type, unsigned long value)
-{
- set(win, atom, type, (unsigned char*) &value, 32, 1, false);
-}
-
-void Property::set(Window win, Atom atom, Atom type, unsigned long value[],
- int elements)
-{
- set(win, atom, type, (unsigned char*) value, 32, elements, false);
-}
-
-void Property::set(Window win, Atom atom, StringType type,
- const ustring &value)
-{
- Atom t;
- switch (type) {
- case ascii: t = atoms.string; assert(!value.utf8()); break;
- case utf8: t = atoms.utf8; assert(value.utf8()); break;
- default: assert(false); return; // unhandled StringType
- }
-
- // add 1 to the size to include the trailing null
- set(win, atom, t, (unsigned char*) value.c_str(), 8, value.bytes() + 1,
- false);
-}
-
-void Property::set(Window win, Atom atom, StringType type,
- const StringVect &strings)
-{
- Atom t;
- bool u; // utf8 encoded?
- switch (type) {
- case ascii: t = atoms.string; u = false; break;
- case utf8: t = atoms.utf8; u = true; break;
- default: assert(false); return; // unhandled StringType
- }
-
- ustring value(u);
-
- StringVect::const_iterator it = strings.begin();
- const StringVect::const_iterator end = strings.end();
- for (; it != end; ++it) {
- assert(it->utf8() == u); // the ustring is encoded correctly?
- value += *it;
- value += '\0';
- }
-
- // add 1 to the size to include the trailing null
- set(win, atom, t, (unsigned char*)value.c_str(), 8,
- value.bytes() + 1, false);
-}
-
-bool Property::get(Window win, Atom atom, Atom type, unsigned long *nelements,
- unsigned char **value, int size)
-{
- assert(win != None); assert(atom != None); assert(type != None);
- assert(size == 8 || size == 16 || size == 32);
- unsigned char *c_val = 0; // value alloc'd in Xlib, must be XFree()d
- Atom ret_type;
- int ret_size;
- unsigned long ret_bytes;
- int result;
- bool ret = false;
-
- // try get the first element
- result = XGetWindowProperty(**display, win, atom, 0l, 1l,
- false, AnyPropertyType, &ret_type, &ret_size,
- nelements, &ret_bytes, &c_val);
- ret = (result == Success && ret_type == type && ret_size == size &&
- *nelements > 0);
- if (ret) {
- if (ret_bytes == 0) {
- // we got the whole property's value
- *value = new unsigned char[*nelements * size/8 + 1];
- memcpy(*value, c_val, *nelements * size/8 + 1);
- } else {
- // get the entire property since it is larger than one long
- XFree(c_val);
- // the number of longs that need to be retreived to get the property's
- // entire value. The last + 1 is the first long that we retrieved above.
- long remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
- result = XGetWindowProperty(**display, win, atom, 0l,
- remain, false, type, &ret_type, &ret_size,
- nelements, &ret_bytes, &c_val);
- ret = (result == Success && ret_type == type && ret_size == size);
- /*
- If the property has changed type/size, or has grown since our first
- read of it, then stop here and try again. If it shrank, then this will
- still work.
- */
- if (! ret) {
- return get(win, atom, type, nelements, value, size);
- }
-
- *value = new unsigned char[*nelements * size/8 + 1];
- memcpy(*value, c_val, *nelements * size/8 + 1);
- }
- }
- if (c_val) XFree(c_val);
- return ret;
-}
-
-bool Property::get(Window win, Atom atom, Atom type, unsigned long *nelements,
- unsigned long **value)
-{
- return get(win, atom, type, nelements, (unsigned char**) value, 32);
-}
-
-bool Property::get(Window win, Atom atom, Atom type, unsigned long *value)
-{
- unsigned long *temp;
- unsigned long num;
- if (! get(win, atom, type, &num, (unsigned char **) &temp, 32))
- return false;
- if (num >= 1) {
- *value = temp[0];
- delete [] temp;
- return true;
- }
- return false;
-}
-
-bool Property::get(Window win, Atom atom, StringType type, ustring *value)
-{
- unsigned long n;
- StringVect s;
-
- if (get(win, atom, type, &n, &s) && n > 0) {
- *value = s[0];
- return true;
- }
- return false;
-}
-
-bool Property::get(Window win, Atom atom, StringType type,
- unsigned long *nelements, StringVect *strings)
-{
- Atom t;
- bool u; // utf8 encoded?
- switch (type) {
- case ascii: t = atoms.string; u = false; break;
- case utf8: t = atoms.utf8; u = true; break;
- default: assert(false); return false; // unhandled StringType
- }
-
- unsigned char *value;
- unsigned long elements;;
- if (!get(win, atom, t, &elements, &value, 8) || elements < 1)
- return false;
-
- std::string s((char*)value, elements);
- delete [] value;
-
- std::string::const_iterator it = s.begin(), end = s.end();
- unsigned long num = 0;
- while(true) {
- std::string::const_iterator tmp = it; // current string.begin()
- it = std::find(tmp, end, '\0'); // look for null between tmp and end
- strings->push_back(std::string(tmp, it)); // s[tmp:it)
- strings->back().setUtf8(u);
- ++num;
- if (it == end) break;
- ++it;
- if (it == end) break;
- }
-
- *nelements = num;
-
- return true;
-}
-
-
-/*
- * Removes a property entirely from a window.
- */
-void Property::erase(Window win, Atom atom)
-{
- XDeleteProperty(**display, win, atom);
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __atom_hh
-#define __atom_hh
-
-/*! @file property.hh
- @brief Provides access to window properties
-*/
-
-#include "ustring.hh"
-#include "screeninfo.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <vector>
-#include <cassert>
-
-namespace otk {
-
-//! The atoms on the X server which this class will cache
-struct Atoms {
- // types
- Atom cardinal; //!< The atom which represents the Cardinal data type
- Atom window; //!< The atom which represents window ids
- Atom pixmap; //!< The atom which represents pixmap ids
- Atom atom; //!< The atom which represents atom values
- Atom string; //!< The atom which represents ascii strings
- Atom utf8; //!< The atom which represents utf8-encoded strings
-
- Atom openbox_pid;
-
- // window hints
- Atom wm_colormap_windows;
- Atom wm_protocols;
- Atom wm_state;
- Atom wm_delete_window;
- Atom wm_take_focus;
- Atom wm_change_state;
- Atom wm_name;
- Atom wm_icon_name;
- Atom wm_class;
- Atom wm_window_role;
- Atom motif_wm_hints;
-
- Atom openbox_show_root_menu;
- Atom openbox_show_workspace_menu;
-
- // NETWM atoms
- // root window properties
- Atom net_supported;
- Atom net_client_list;
- Atom net_client_list_stacking;
- Atom net_number_of_desktops;
- Atom net_desktop_geometry;
- Atom net_desktop_viewport;
- Atom net_current_desktop;
- Atom net_desktop_names;
- Atom net_active_window;
- Atom net_workarea;
- Atom net_supporting_wm_check;
-// Atom net_virtual_roots;
- Atom net_desktop_layout;
- Atom net_showing_desktop;
- // root window messages
- Atom net_close_window;
- Atom net_wm_moveresize;
- // application window properties
-// Atom net_properties;
- Atom net_wm_name;
- Atom net_wm_visible_name;
- Atom net_wm_icon_name;
- Atom net_wm_visible_icon_name;
- Atom net_wm_desktop;
- Atom net_wm_window_type;
- Atom net_wm_state;
- Atom net_wm_strut;
-// Atom net_wm_icon_geometry;
- Atom net_wm_icon;
-// Atom net_wm_pid;
-// Atom net_wm_handled_icons;
- Atom net_wm_allowed_actions;
- // application protocols
-// Atom Atom net_wm_ping;
-
- Atom net_wm_window_type_desktop;
- Atom net_wm_window_type_dock;
- Atom net_wm_window_type_toolbar;
- Atom net_wm_window_type_menu;
- Atom net_wm_window_type_utility;
- Atom net_wm_window_type_splash;
- Atom net_wm_window_type_dialog;
- Atom net_wm_window_type_normal;
-
- Atom net_wm_moveresize_size_topleft;
- Atom net_wm_moveresize_size_topright;
- Atom net_wm_moveresize_size_bottomleft;
- Atom net_wm_moveresize_size_bottomright;
- Atom net_wm_moveresize_move;
-
- Atom net_wm_action_move;
- Atom net_wm_action_resize;
- Atom net_wm_action_minimize;
- Atom net_wm_action_shade;
- Atom net_wm_action_stick;
- Atom net_wm_action_maximize_horz;
- Atom net_wm_action_maximize_vert;
- Atom net_wm_action_fullscreen;
- Atom net_wm_action_change_desktop;
- Atom net_wm_action_close;
-
- Atom net_wm_state_modal;
- Atom net_wm_state_sticky;
- Atom net_wm_state_maximized_vert;
- Atom net_wm_state_maximized_horz;
- Atom net_wm_state_shaded;
- Atom net_wm_state_skip_taskbar;
- Atom net_wm_state_skip_pager;
- Atom net_wm_state_hidden;
- Atom net_wm_state_fullscreen;
- Atom net_wm_state_above;
- Atom net_wm_state_below;
-
- Atom net_wm_state_add;
- Atom net_wm_state_remove;
- Atom net_wm_state_toggle;
-
- Atom kde_net_system_tray_windows;
- Atom kde_net_wm_system_tray_window_for;
- Atom kde_net_wm_window_type_override;
-
- Atom kwm_win_icon;
-
- Atom rootpmapid;
- Atom esetrootid;
-
- Atom openbox_premax;
- Atom openbox_active_window;
- Atom openbox_restack_window;
-};
-
-
-//! Provides easy access to window properties.
-class Property {
-public:
-
- //! The possible types/encodings of strings
- enum StringType {
- ascii, //!< Standard 8-bit ascii string
- utf8, //!< Utf8-encoded string
-#ifndef DOXYGEN_IGNORE
- NUM_STRING_TYPE
-#endif
- };
-
- //! A list of ustrings
- typedef std::vector<ustring> StringVect;
-
- //! The value of all atoms on the X server that exist in the
- //! Atoms struct
- static Atoms atoms;
-
-private:
- //! Sets a property on a window
- static void set(Window win, Atom atom, Atom type, unsigned char *data,
- int size, int nelements, bool append);
- //! Gets a property's value from a window
- static bool get(Window win, Atom atom, Atom type,
- unsigned long *nelements, unsigned char **value,
- int size);
-
-public:
- //! Initializes the Property class.
- /*!
- CAUTION: This function uses otk::Display, so ensure that
- otk::Display::initialize has been called before initializing this class!
- */
- static void initialize();
-
- //! Sets a single-value property on a window to a new value
- /*!
- @param win The window id of the window on which to set the property's value
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type The Atom value of the property type. This can be found in the
- struct returned by Property::atoms.
- @param value The value to set the property to
- */
- static void set(Window win, Atom atom, Atom type, unsigned long value);
- //! Sets an multiple-value property on a window to a new value
- /*!
- @param win The window id of the window on which to set the property's value
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type The Atom value of the property type. This can be found in the
- struct returned by Property::atoms.
- @param value Any array of values to set the property to. The array must
- contain <i>elements</i> number of elements
- @param elements The number of elements in the <i>value</i> array
- */
- static void set(Window win, Atom atom, Atom type,
- unsigned long value[], int elements);
- //! Sets a string property on a window to a new value
- /*!
- @param win The window id of the window on which to set the property's value
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type A member of the Property::StringType enum that specifies the
- type of the string the property is being set to
- @param value The string to set the property to
- */
- static void set(Window win, Atom atom, StringType type,
- const ustring &value);
- //! Sets a string-array property on a window to a new value
- /*!
- @param win The window id of the window on which to set the property's value
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type A member of the Property::StringType enum that specifies the
- type of the string the property is being set to
- @param strings A list of strings to set the property to
- */
- static void set(Window win, Atom atom, StringType type,
- const StringVect &strings);
-
- //! Gets the value of a property on a window
- /*!
- @param win The window id of the window to get the property value from
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type The Atom value of the property type. This can be found in the
- struct returned by Property::atoms.
- @param nelements When the function returns, if it returns true, this will
- contain the actual number of elements retrieved.<br>
- @param value If the function returns true, then this contains an array of
- retrieved values for the property.<br>
- The <i>value</i> is allocated inside the function and
- <b>delete[]</b> value needs to be called when you are done
- with it.<br>
- The <i>value</i> array returned is null terminated, and has
- <i>nelements</i> elements in it plus the terminating null.
- @return true if retrieval of the specified property with the specified
- type was successful; otherwise, false
- */
- static bool get(Window win, Atom atom, Atom type,
- unsigned long *nelements, unsigned long **value);
- //! Gets a single element from the value of a property on a window
- /*!
- @param win The window id of the window to get the property value from
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type The Atom value of the property type. This can be found in the
- struct returned by Property::atoms.
- @param value If the function returns true, then this contains the first
- (and possibly only) element in the value of the specified
- property.
- @return true if retrieval of the specified property with the specified
- type was successful; otherwise, false
- */
- static bool get(Window win, Atom atom, Atom type, unsigned long *value);
- //! Gets a single string from the value of a property on a window
- /*!
- @param win The window id of the window to get the property value from
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type A member of the Property::StringType enum that specifies the
- type of the string property to retrieve
- @param value If the function returns true, then this contains the first
- (and possibly only) string in the value of the specified
- property.
- @return true if retrieval of the specified property with the specified
- type was successful; otherwise, false
- */
- static bool get(Window win, Atom atom, StringType type, ustring *value);
- //! Gets strings from the value of a property on a window
- /*!
- @param win The window id of the window to get the property value from
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- @param type A member of the Property::StringType enum that specifies the
- type of the string property to retrieve
- @param nelements When the function returns, if it returns true, this will
- contain the actual number of strings retrieved.<br>
- @param strings If the function returns true, then this contains all of the
- strings retrieved from the property's value.
- @return true if retrieval of the specified property with the specified
- type was successful; otherwise, false
- */
- static bool get(Window win, Atom atom, StringType type,
- unsigned long *nelements, StringVect *strings);
-
- //! Removes a property from a window
- /*!
- @param win The window id of the window to remove the property from
- @param atom The Atom value of the property to set. This can be found in the
- struct returned by Property::atoms.
- */
- static void erase(Window win, Atom atom);
-};
-
-}
-
-#endif // __atom_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "pseudorendercontrol.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-#include "surface.hh"
-#include "rendertexture.hh"
-
-extern "C" {
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdlib>
-
-namespace otk {
-
-PseudoRenderControl::PseudoRenderControl(int screen)
- : RenderControl(screen)
-{
- printf("Initializing PseudoColor RenderControl\n");
- const ScreenInfo *info = display->screenInfo(_screen);
- int depth = info->depth();
-
- // determine the number of colors and the bits-per-color
- _bpc = 2; // XXX THIS SHOULD BE A USER OPTION
- assert(_bpc >= 1);
- _ncolors = 1 << (_bpc * 3);
-
- if (_ncolors > 1 << depth) {
- fprintf(stderr,
- _("PseudoRenderControl: Invalid colormap size. Resizing.\n"));
- _bpc = 1 << (depth/3) >> 3;
- _ncolors = 1 << (_bpc * 3);
- }
-
- // build a color cube
- _colors = new XColor[_ncolors];
-int tr, tg, tb;
- int cpc = 1 << _bpc; // colors per channel
- for (int n = 0,
- r = 0; r < cpc; r++)
- for (int g = 0; g < cpc; g++)
- for (int b = 0; b < cpc; b++, n++) {
- tr = (int)(((float)(r)/(float)(cpc-1)) * 0xFF);
- tg = (int)(((float)(g)/(float)(cpc-1)) * 0xFF);
- tb = (int)(((float)(b)/(float)(cpc-1)) * 0xFF);
- _colors[n].red = tr | tr << 8;
- _colors[n].green = tg | tg << 8;
- _colors[n].blue = tb | tb << 8;
- _colors[n].flags = DoRed|DoGreen|DoBlue; // used to track allocation
- }
-
- // allocate the colors
- for (int i = 0; i < _ncolors; i++)
- if (!XAllocColor(**display, info->colormap(), &_colors[i]))
- _colors[i].flags = 0; // mark it as unallocated
-
- // try allocate any colors that failed allocation above
-
- // get the allocated values from the X server (only the first 256 XXX why!?)
- XColor icolors[256];
- int incolors = (((1 << depth) > 256) ? 256 : (1 << depth));
- for (int i = 0; i < incolors; i++)
- icolors[i].pixel = i;
- XQueryColors(**display, info->colormap(), icolors, incolors);
-
- // try match unallocated ones
- for (int i = 0; i < _ncolors; i++) {
- if (!_colors[i].flags) { // if it wasn't allocated...
- unsigned long closest = 0xffffffff, close = 0;
- for (int ii = 0; ii < incolors; ii++) {
- // find deviations
- int r = (_colors[i].red - icolors[ii].red) & 0xff;
- int g = (_colors[i].green - icolors[ii].green) & 0xff;
- int b = (_colors[i].blue - icolors[ii].blue) & 0xff;
- // find a weighted absolute deviation
- unsigned long dev = (r * r) + (g * g) + (b * b);
-
- if (dev < closest) {
- closest = dev;
- close = ii;
- }
- }
-
- _colors[i].red = icolors[close].red;
- _colors[i].green = icolors[close].green;
- _colors[i].blue = icolors[close].blue;
- _colors[i].pixel = icolors[close].pixel;
-
- // try alloc this closest color, it had better succeed!
- if (XAllocColor(**display, info->colormap(), &_colors[i]))
- _colors[i].flags = DoRed|DoGreen|DoBlue; // mark as alloced
- else
- assert(false); // wtf has gone wrong, its already alloced for chissake!
- }
- }
-}
-
-PseudoRenderControl::~PseudoRenderControl()
-{
- printf("Destroying PseudoColor RenderControl\n");
-
- unsigned long *pixels = new unsigned long [_ncolors], *p = pixels;
- for (int i = 0; i < _ncolors; ++i, ++p)
- *p = _colors[i].pixel;
- XFreeColors(**display, display->screenInfo(_screen)->colormap(), pixels,
- _ncolors, 0);
- delete [] _colors;
-}
-
-inline const XColor *PseudoRenderControl::pickColor(int r, int g, int b) const
-{
- r = (r & 0xff) >> (8-_bpc);
- g = (g & 0xff) >> (8-_bpc);
- b = (b & 0xff) >> (8-_bpc);
- return &_colors[(r << (2*_bpc)) + (g << (1*_bpc)) + b];
-}
-
-void PseudoRenderControl::reduceDepth(Surface &sf, XImage *im) const
-{
- pixel32 *data = sf.pixelData();
- pixel32 *ret = (pixel32*)malloc(im->width * im->height * 4);
- char *p = (char *)ret;
- int x, y;
- for (y = 0; y < im->height; y++) {
- for (x = 0; x < im->width; x++) {
- p[x] = pickColor(data[x] >> default_red_shift,
- data[x] >> default_green_shift,
- data[x] >> default_blue_shift)->pixel;
- }
- data += im->width;
- p += im->bytes_per_line;
- }
- im->data = (char*)ret;
-}
-
-void PseudoRenderControl::allocateColor(XColor *color) const
-{
- const XColor *c = pickColor(color->red, color->blue, color->green);
-
- color->red = c->red;
- color->green = c->green;
- color->blue = c->blue;
- color->pixel = c->pixel;
-
- if (XAllocColor(**display, display->screenInfo(_screen)->colormap(), color))
- color->flags = DoRed|DoGreen|DoBlue; // mark as alloced
- else
- assert(false); // wtf has gone wrong, its already alloced for chissake!
-
- return;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __pseudorendercontrol_hh
-#define __pseudorendercontrol_hh
-
-#include "rendercontrol.hh"
-
-namespace otk {
-
-class PseudoRenderControl : public RenderControl {
-private:
- int _bpc; // number of bits per color
- int _ncolors; // number of allocated colors, size of the XColor array
- XColor *_colors; // the valid allocated colors
-
- virtual void reduceDepth(Surface &sf, XImage *im) const;
-
- const XColor *pickColor(int r, int g, int b) const;
-
-public:
- PseudoRenderControl(int screen);
- virtual ~PseudoRenderControl();
-
- virtual void allocateColor(XColor *color) const;
-};
-
-}
-
-#endif // __pseudorendercontrol_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __rect_hh
-#define __rect_hh
-
-#include "point.hh"
-#include "size.hh"
-
-namespace otk {
-
-class Rect {
- Point _p;
- Size _s;
-public:
- Rect() : _p(), _s() {}
- Rect(const Point &p, const Size &s) : _p(p), _s(s) {}
- Rect(const Rect &r) : _p(r._p), _s(r._s) {}
- Rect(int x, int y, int w, int h)
- : _p(x, y), _s(w, h) {}
-
- inline int x() const { return _p.x(); }
- inline int y() const { return _p.y(); }
- inline int width() const { return _s.width(); }
- inline int height() const { return _s.height(); }
-
- inline int left() const { return _p.x(); }
- inline int top() const { return _p.y(); }
- inline int right() const { return _p.x() + _s.width() - 1; }
- inline int bottom() const { return _p.y() + _s.height() - 1; }
-
- inline const Point& position() const { return _p; }
- inline const Size& size() const { return _s; }
-
- bool operator==(const Rect &o) const { return _p == o._p && _s == o._s; }
- bool operator!=(const Rect &o) const { return _p != o._p || _s != o._s; }
-};
-
-}
-
-#endif // __rect_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "rendercolor.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-#include "rendercontrol.hh"
-
-#include <cstdio>
-
-namespace otk {
-
-std::map<unsigned long, RenderColor::CacheItem*> *RenderColor::_cache = 0;
-
-void RenderColor::initialize()
-{
- _cache = new std::map<unsigned long, CacheItem*>[ScreenCount(**display)];
-}
-
-void RenderColor::destroy()
-{
- delete [] _cache;
-}
-
-RenderColor::RenderColor(int screen, unsigned char red,
- unsigned char green, unsigned char blue)
- : _screen(screen),
- _red(red),
- _green(green),
- _blue(blue)
-{
- create();
-}
-
-RenderColor::RenderColor(int screen, RGB rgb)
- : _screen(screen),
- _red(rgb.r),
- _green(rgb.g),
- _blue(rgb.b)
-{
- create();
-}
-
-void RenderColor::create()
-{
- unsigned long color = _blue | _green << 8 | _red << 16;
-
- // try get a gc from the cache
- CacheItem *item = _cache[_screen][color];
-
- if (item) {
- _gc = item->gc;
- _pixel = item->pixel;
- ++item->count;
- } else {
- XGCValues gcv;
-
- // allocate a color and GC from the server
- const ScreenInfo *info = display->screenInfo(_screen);
-
- XColor xcol; // convert from 0-0xff to 0-0xffff
- xcol.red = (_red << 8) | _red;
- xcol.green = (_green << 8) | _green;
- xcol.blue = (_blue << 8) | _blue;
-
- display->renderControl(_screen)->allocateColor(&xcol);
-
- _pixel = xcol.pixel;
- gcv.foreground = _pixel;
- gcv.cap_style = CapProjecting;
- _gc = XCreateGC(**display, info->rootWindow(),
- GCForeground | GCCapStyle, &gcv);
- assert(_gc);
-
- // insert into the cache
- item = new CacheItem(_gc, _pixel);
- _cache[_screen][color] = item;
- ++item->count;
- }
-}
-
-RenderColor::~RenderColor()
-{
- unsigned long color = _blue | _green << 8 | _red << 16;
-
- CacheItem *item = _cache[_screen][color];
- assert(item); // better be...
-
- if (--item->count <= 0) {
- // remove from the cache
- XFreeGC(**display, _gc);
- _cache[_screen][color] = 0;
- delete item;
-
- const ScreenInfo *info = display->screenInfo(_screen);
- XFreeColors(**display, info->colormap(), &_pixel, 1, 0);
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __rendercolor_hh
-#define __rendercolor_hh
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <map>
-
-namespace otk {
-
-struct RGB {
- int r;
- int g;
- int b;
- RGB(int red, int green, int blue) : r(red), g(green), b(blue) {}
- // color is in ARGB format
- RGB(unsigned long color)
- : r((color >> 16) & 0xff),
- g((color >> 8) & 0xff),
- b((color) & 0xff) {}
-};
-
-class RenderColor {
-private:
- struct CacheItem {
- GC gc;
- unsigned long pixel;
- int count;
- CacheItem(GC g, unsigned long p) : gc(g), pixel(p), count(0) {}
- };
- static std::map<unsigned long, CacheItem*> *_cache;
-
- int _screen;
- unsigned char _red;
- unsigned char _green;
- unsigned char _blue;
-
- unsigned long _pixel;
- GC _gc;
-
- void create();
-
-public:
- static void initialize();
- static void destroy();
-
- RenderColor(int screen, unsigned char red,
- unsigned char green, unsigned char blue);
- RenderColor(int screen, RGB rgb);
- virtual ~RenderColor();
-
- inline int screen() const { return _screen; }
- inline unsigned char red() const { return _red; }
- inline unsigned char green() const { return _green; }
- inline unsigned char blue() const { return _blue; }
- unsigned long pixel() const { return _pixel; }
- GC gc() const { return _gc; }
-};
-
-}
-
-#endif // __rendercolor_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "rendercontrol.hh"
-#include "truerendercontrol.hh"
-#include "pseudorendercontrol.hh"
-#include "rendertexture.hh"
-#include "rendercolor.hh"
-#include "renderstyle.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-#include "surface.hh"
-#include "font.hh"
-#include "ustring.hh"
-#include "property.hh"
-
-extern "C" {
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif // HAVE_SYS_WAIT_H
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif // HAVE_UNISTD_H
-
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdlib>
-
-namespace otk {
-
-RenderControl *RenderControl::createRenderControl(int screen)
-{
- // get the visual on the screen and return the correct type of RenderControl
- int vclass = display->screenInfo(screen)->visual()->c_class;
- switch (vclass) {
- case TrueColor:
- return new TrueRenderControl(screen);
- case PseudoColor:
- case StaticColor:
- return new PseudoRenderControl(screen);
- case GrayScale:
- case StaticGray:
- return new PseudoRenderControl(screen);
- default:
- printf(_("RenderControl: Unsupported visual %d specified. Aborting.\n"),
- vclass);
- ::exit(1);
- }
-}
-
-RenderControl::RenderControl(int screen)
- : _screen(screen)
-
-{
- printf("Initializing RenderControl\n");
-
-}
-
-RenderControl::~RenderControl()
-{
- printf("Destroying RenderControl\n");
-}
-
-void RenderControl::drawString(Surface& sf, const Font &font, int x, int y,
- const RenderColor &color,
- const ustring &string) const
-{
- assert(sf._screen == _screen);
- XftDraw *d = sf._xftdraw;
- assert(d); // this means that the background hasn't been rendered yet!
-
- if (font._shadow) {
- XftColor c;
- c.color.red = 0;
- c.color.green = 0;
- c.color.blue = 0;
- c.color.alpha = font._tint | font._tint << 8; // transparent shadow
- c.pixel = BlackPixel(**display, _screen);
-
- if (string.utf8())
- XftDrawStringUtf8(d, &c, font._xftfont, x + font._offset,
- font._xftfont->ascent + y + font._offset,
- (FcChar8*)string.c_str(), string.bytes());
- else
- XftDrawString8(d, &c, font._xftfont, x + font._offset,
- font._xftfont->ascent + y + font._offset,
- (FcChar8*)string.c_str(), string.bytes());
- }
-
- XftColor c;
- c.color.red = color.red() | color.red() << 8;
- c.color.green = color.green() | color.green() << 8;
- c.color.blue = color.blue() | color.blue() << 8;
- c.pixel = color.pixel();
- c.color.alpha = 0xff | 0xff << 8; // no transparency in Color yet
-
- if (string.utf8())
- XftDrawStringUtf8(d, &c, font._xftfont, x, font._xftfont->ascent + y,
- (FcChar8*)string.c_str(), string.bytes());
- else
- XftDrawString8(d, &c, font._xftfont, x, font._xftfont->ascent + y,
- (FcChar8*)string.c_str(), string.bytes());
- return;
-}
-
-void RenderControl::drawSolidBackground(Surface& sf,
- const RenderTexture& texture) const
-{
- assert(_screen == sf._screen);
- assert(_screen == texture.color().screen());
-
- if (texture.parentRelative()) return;
-
- sf.setPixmap(texture.color());
-
- int width = sf.size().width(), height = sf.size().height();
- int left = 0, top = 0, right = width - 1, bottom = height - 1;
-
- if (texture.interlaced())
- for (int i = 0; i < height; i += 2)
- XDrawLine(**display, sf.pixmap(), texture.interlaceColor().gc(),
- 0, i, width, i);
-
- switch (texture.relief()) {
- case RenderTexture::Raised:
- switch (texture.bevel()) {
- case RenderTexture::Bevel1:
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left, bottom, right, bottom);
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- right, bottom, right, top);
-
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left, top, right, top);
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left, bottom, left, top);
- break;
- case RenderTexture::Bevel2:
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left + 1, bottom - 2, right - 2, bottom - 2);
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- right - 2, bottom - 2, right - 2, top + 1);
-
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left + 1, top + 1, right - 2, top + 1);
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left + 1, bottom - 2, left + 1, top + 1);
- break;
- default:
- assert(false); // unhandled RenderTexture::BevelType
- }
- break;
- case RenderTexture::Sunken:
- switch (texture.bevel()) {
- case RenderTexture::Bevel1:
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left, bottom, right, bottom);
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- right, bottom, right, top);
-
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left, top, right, top);
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left, bottom, left, top);
- break;
- case RenderTexture::Bevel2:
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- left + 1, bottom - 2, right - 2, bottom - 2);
- XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
- right - 2, bottom - 2, right - 2, top + 1);
-
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left + 1, top + 1, right - 2, top + 1);
- XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
- left + 1, bottom - 2, left + 1, top + 1);
- break;
- default:
- assert(false); // unhandled RenderTexture::BevelType
- }
- break;
- case RenderTexture::Flat:
- if (texture.border())
- XDrawRectangle(**display, sf.pixmap(), texture.borderColor().gc(),
- left, top, right, bottom);
- break;
- default:
- assert(false); // unhandled RenderTexture::ReliefType
- }
-}
-
-void RenderControl::drawMask(Surface &sf, const RenderColor &color,
- const PixmapMask &mask) const
-{
- assert(_screen == sf._screen);
- assert(_screen == color.screen());
-
- if (mask.mask == None) return; // no mask given
-
- int width = sf.size().width(), height = sf.size().height();
-
- // set the clip region
- int x = (width - mask.w) / 2, y = (height - mask.h) / 2;
- XSetClipMask(**display, color.gc(), mask.mask);
- XSetClipOrigin(**display, color.gc(), x, y);
-
- // fill in the clipped region
- XFillRectangle(**display, sf.pixmap(), color.gc(), x, y,
- x + mask.w, y + mask.h);
-
- // unset the clip region
- XSetClipMask(**display, color.gc(), None);
- XSetClipOrigin(**display, color.gc(), 0, 0);
-}
-
-void RenderControl::drawGradientBackground(
- Surface &sf, const RenderTexture &texture) const
-{
- unsigned int r,g,b;
- int w = sf.size().width(), h = sf.size().height();
- int off, x;
-
- const ScreenInfo *info = display->screenInfo(_screen);
- XImage *im = XCreateImage(**display, info->visual(), info->depth(),
- ZPixmap, 0, NULL, w, h, 32, 0);
- im->byte_order = endian;
-
- switch (texture.gradient()) {
- case RenderTexture::Vertical:
- verticalGradient(sf, texture);
- break;
- case RenderTexture::Horizontal:
- horizontalGradient(sf, texture);
- break;
- case RenderTexture::Diagonal:
- diagonalGradient(sf, texture);
- break;
- case RenderTexture::CrossDiagonal:
- crossDiagonalGradient(sf, texture);
- break;
- default:
- printf("unhandled gradient\n");
- }
-
- pixel32 *data = sf.pixelData();
- pixel32 current;
-
- if (texture.relief() == RenderTexture::Flat && texture.border()) {
- r = texture.borderColor().red();
- g = texture.borderColor().green();
- b = texture.borderColor().blue();
- current = (r << default_red_shift)
- + (g << default_green_shift)
- + (b << default_blue_shift);
- for (off = 0, x = 0; x < w; ++x, off++) {
- *(data + off) = current;
- *(data + off + ((h-1) * w)) = current;
- }
- for (off = 0, x = 0; x < h; ++x, off++) {
- *(data + (off * w)) = current;
- *(data + (off * w) + w - 1) = current;
- }
- }
-
- if (texture.relief() != RenderTexture::Flat) {
- if (texture.bevel() == RenderTexture::Bevel1) {
- for (off = 1, x = 1; x < w - 1; ++x, off++)
- highlight(data + off,
- data + off + (h-1) * w,
- texture.relief()==RenderTexture::Raised);
- for (off = 0, x = 0; x < h; ++x, off++)
- highlight(data + off * w,
- data + off * w + w - 1,
- texture.relief()==RenderTexture::Raised);
- }
-
- if (texture.bevel() == RenderTexture::Bevel2) {
- for (off = 2, x = 2; x < w - 2; ++x, off++)
- highlight(data + off + w,
- data + off + (h-2) * w,
- texture.relief()==RenderTexture::Raised);
- for (off = 1, x = 1; x < h-1; ++x, off++)
- highlight(data + off * w + 1,
- data + off * w + w - 2,
- texture.relief()==RenderTexture::Raised);
- }
- }
-
- reduceDepth(sf, im);
- sf.setPixmap(im);
- XDestroyImage(im);
-}
-
-void RenderControl::verticalGradient(Surface &sf,
- const RenderTexture &texture) const
-{
- pixel32 *data = sf.pixelData();
- pixel32 current;
- float dr, dg, db;
- unsigned int r,g,b;
- int w = sf.size().width(), h = sf.size().height();
-
- dr = (float)(texture.secondary_color().red() - texture.color().red());
- dr/= (float)h;
-
- dg = (float)(texture.secondary_color().green() - texture.color().green());
- dg/= (float)h;
-
- db = (float)(texture.secondary_color().blue() - texture.color().blue());
- db/= (float)h;
-
- for (int y = 0; y < h; ++y) {
- r = texture.color().red() + (int)(dr * y);
- g = texture.color().green() + (int)(dg * y);
- b = texture.color().blue() + (int)(db * y);
- current = (r << default_red_shift)
- + (g << default_green_shift)
- + (b << default_blue_shift);
- for (int x = 0; x < w; ++x, ++data)
- *data = current;
- }
-}
-
-void RenderControl::horizontalGradient(Surface &sf,
- const RenderTexture &texture) const
-{
- pixel32 *data = sf.pixelData();
- pixel32 current;
- float dr, dg, db;
- unsigned int r,g,b;
- int w = sf.size().width(), h = sf.size().height();
-
- dr = (float)(texture.secondary_color().red() - texture.color().red());
- dr/= (float)w;
-
- dg = (float)(texture.secondary_color().green() - texture.color().green());
- dg/= (float)w;
-
- db = (float)(texture.secondary_color().blue() - texture.color().blue());
- db/= (float)w;
-
- for (int x = 0; x < w; ++x, ++data) {
- r = texture.color().red() + (int)(dr * x);
- g = texture.color().green() + (int)(dg * x);
- b = texture.color().blue() + (int)(db * x);
- current = (r << default_red_shift)
- + (g << default_green_shift)
- + (b << default_blue_shift);
- for (int y = 0; y < h; ++y)
- *(data + y*w) = current;
- }
-}
-
-void RenderControl::diagonalGradient(Surface &sf,
- const RenderTexture &texture) const
-{
- pixel32 *data = sf.pixelData();
- pixel32 current;
- float drx, dgx, dbx, dry, dgy, dby;
- unsigned int r,g,b;
- int w = sf.size().width(), h = sf.size().height();
-
- for (int y = 0; y < h; ++y) {
- drx = (float)(texture.secondary_color().red() - texture.color().red());
- dry = drx/(float)h;
- drx/= (float)w;
-
- dgx = (float)(texture.secondary_color().green() - texture.color().green());
- dgy = dgx/(float)h;
- dgx/= (float)w;
-
- dbx = (float)(texture.secondary_color().blue() - texture.color().blue());
- dby = dbx/(float)h;
- dbx/= (float)w;
- for (int x = 0; x < w; ++x, ++data) {
- r = texture.color().red() + ((int)(drx * x) + (int)(dry * y))/2;
- g = texture.color().green() + ((int)(dgx * x) + (int)(dgy * y))/2;
- b = texture.color().blue() + ((int)(dbx * x) + (int)(dby * y))/2;
- current = (r << default_red_shift)
- + (g << default_green_shift)
- + (b << default_blue_shift);
- *data = current;
- }
- }
-}
-
-void RenderControl::crossDiagonalGradient(
- Surface &sf, const RenderTexture &texture) const
-{
- pixel32 *data = sf.pixelData();
- pixel32 current;
- float drx, dgx, dbx, dry, dgy, dby;
- unsigned int r,g,b;
- int w = sf.size().width(), h = sf.size().height();
-
- for (int y = 0; y < h; ++y) {
- drx = (float)(texture.secondary_color().red() - texture.color().red());
- dry = drx/(float)h;
- drx/= (float)w;
-
- dgx = (float)(texture.secondary_color().green() - texture.color().green());
- dgy = dgx/(float)h;
- dgx/= (float)w;
-
- dbx = (float)(texture.secondary_color().blue() - texture.color().blue());
- dby = dbx/(float)h;
- dbx/= (float)w;
- for (int x = w; x > 0; --x, ++data) {
- r = texture.color().red() + ((int)(drx * (x-1)) + (int)(dry * y))/2;
- g = texture.color().green() + ((int)(dgx * (x-1)) + (int)(dgy * y))/2;
- b = texture.color().blue() + ((int)(dbx * (x-1)) + (int)(dby * y))/2;
- current = (r << default_red_shift)
- + (g << default_green_shift)
- + (b << default_blue_shift);
- *data = current;
- }
- }
-}
-
-void RenderControl::highlight(pixel32 *x, pixel32 *y, bool raised) const
-{
- int r, g, b;
-
- pixel32 *up, *down;
- if (raised) {
- up = x;
- down = y;
- } else {
- up = y;
- down = x;
- }
- r = (*up >> default_red_shift) & 0xFF;
- r += r >> 1;
- g = (*up >> default_green_shift) & 0xFF;
- g += g >> 1;
- b = (*up >> default_blue_shift) & 0xFF;
- b += b >> 1;
- if (r > 255) r = 255;
- if (g > 255) g = 255;
- if (b > 255) b = 255;
- *up = (r << default_red_shift) + (g << default_green_shift)
- + (b << default_blue_shift);
-
- r = (*down >> default_red_shift) & 0xFF;
- r = (r >> 1) + (r >> 2);
- g = (*down >> default_green_shift) & 0xFF;
- g = (g >> 1) + (g >> 2);
- b = (*down >> default_blue_shift) & 0xFF;
- b = (b >> 1) + (b >> 2);
- *down = (r << default_red_shift) + (g << default_green_shift)
- + (b << default_blue_shift);
-}
-
-void RenderControl::drawBackground(Surface& sf,
- const RenderTexture &texture) const
-{
- assert(_screen == sf._screen);
- assert(_screen == texture.color().screen());
-
- if (texture.gradient() == RenderTexture::Solid)
- drawSolidBackground(sf, texture);
- else
- drawGradientBackground(sf, texture);
-}
-
-
-void RenderControl::drawImage(Surface &sf, int w, int h,
- unsigned long *data) const
-{
- pixel32 *bg = sf.pixelData();
- int c, sfw, sfh;
- unsigned int i, e, bgi;
- sfw = sf.size().width();
- sfh = sf.size().height();
-
- if (w && h) {
- // scale it
- unsigned long *olddata = data;
- unsigned long newdata[sfw*sfh];
- double dx = w / (double)sfw;
- double dy = h / (double)sfh;
- double px = 0.0;
- double py = 0.0;
- int iy = 0;
- for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
- newdata[i] = olddata[(int)px + iy];
- if (++c >= sfw) {
- c = 0;
- px = 0;
- py += dy;
- iy = (int)py * w;
- } else
- px += dx;
- }
- data = newdata;
-
- // apply the alpha channel
- for (i = 0, c = 0, e = sfw*sfh; i < e; ++i, ++bgi) {
- unsigned char alpha = data[i] >> 24;
- unsigned char r = data[i] >> 16;
- unsigned char g = data[i] >> 8;
- unsigned char b = data[i];
-
- // background color
- unsigned char bgr = bg[i] >> default_red_shift;
- unsigned char bgg = bg[i] >> default_green_shift;
- unsigned char bgb = bg[i] >> default_blue_shift;
-
- r = bgr + (((r - bgr) * alpha) >> 8);
- g = bgg + (((g - bgg) * alpha) >> 8);
- b = bgb + (((b - bgb) * alpha) >> 8);
-
- bg[i] = (r << default_red_shift) | (g << default_green_shift) |
- (b << default_blue_shift);
- }
- }
-
- const ScreenInfo *info = display->screenInfo(_screen);
- XImage *im = XCreateImage(**display, info->visual(), info->depth(),
- ZPixmap, 0, NULL, sf.size().width(),
- sf.size().height(), 32, 0);
- im->byte_order = endian;
-
- reduceDepth(sf, im);
- sf.setPixmap(im);
- XDestroyImage(im);
-}
-
-void RenderControl::drawImage(Surface &sf, Pixmap pixmap, Pixmap mask) const
-{
- int junk, sfw, sfh, w, h, depth, mw, mh, mdepth;
- Window wjunk;
- const ScreenInfo *info = display->screenInfo(_screen);
- GC mgc = 0;
-
- assert(pixmap != None);
-
- sfw = sf.size().width();
- sfh = sf.size().height();
-
- XGetGeometry(**display, pixmap, &wjunk, &junk, &junk,
- (unsigned int*)&w, (unsigned int*)&h,
- (unsigned int*)&junk, (unsigned int*)&depth);
- if (mask != None) {
- XGetGeometry(**display, mask, &wjunk, &junk, &junk,
- (unsigned int*)&mw, (unsigned int*)&mh,
- (unsigned int*)&junk, (unsigned int*)&mdepth);
- if (mw != w || mh != h || mdepth != 1)
- return;
- }
-
- Pixmap p = XCreatePixmap(**display, info->rootWindow(), sfw, sfh,
- info->depth());
- Pixmap m;
- if (mask == None)
- m = None;
- else {
- m = XCreatePixmap(**display, info->rootWindow(), sfw, sfh, 1);
- XGCValues gcv;
- gcv.subwindow_mode = IncludeInferiors;
- gcv.graphics_exposures = false;
- mgc = XCreateGC(**display, m, GCGraphicsExposures |
- GCSubwindowMode, &gcv);
- }
-
- // scale it
- for (int y = sfh - 1; y >= 0; --y) {
- int yy = y * h / sfh;
- for (int x = sfw - 1; x >= 0; --x) {
- int xx = x * w / sfw;
- if (depth != info->depth()) {
- XCopyPlane(**display, pixmap, p, DefaultGC(**display, _screen),
- xx, yy, 1, 1, x, y, 1);
- } else {
- XCopyArea(**display, pixmap, p, DefaultGC(**display, _screen),
- xx, yy, 1, 1, x, y);
- }
- if (mask != None)
- XCopyArea(**display, mask, m, mgc, xx, yy, 1, 1, x, y);
- }
- }
-
- XSetClipMask(**display, DefaultGC(**display, _screen), m);
- XSetClipOrigin(**display, DefaultGC(**display, _screen), 0, 0);
- XCopyArea(**display, p, sf.pixmap(), DefaultGC(**display, _screen), 0, 0,
- sfw, sfh, 0, 0);
- XSetClipMask(**display, DefaultGC(**display, _screen), None);
-
- XFreePixmap(**display, p);
- if (m != None) XFreePixmap(**display, m);
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __rendercontrol_hh
-#define __rendercontrol_hh
-
-extern "C" {
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-}
-
-#include "surface.hh"
-
-namespace otk {
-
-class ScreenInfo;
-class RenderTexture;
-class Font;
-class RenderColor;
-class ustring;
-class PixmapMask;
-
-class RenderControl {
-protected:
- int _screen;
-
-// bool _dither;
-
- RenderControl(int screen);
-
- inline void highlight(pixel32 *x, pixel32 *y, bool raised) const;
- void verticalGradient(Surface &sf, const RenderTexture &texture) const;
- void horizontalGradient(Surface &sf, const RenderTexture &texture) const;
- void diagonalGradient(Surface &sf, const RenderTexture &texture) const;
- void crossDiagonalGradient(Surface &sf, const RenderTexture &texture) const;
- virtual void drawGradientBackground(Surface &sf,
- const RenderTexture &texture) const;
- virtual void drawSolidBackground(Surface& sf,
- const RenderTexture& texture) const;
-
- //! Reduces a Surface's Surface::pixelData so that it will display correctly
- //! on the screen's depth
- /*!
- This function allocates and sets the im->data member. The allocated memory
- will be freed when XDetroyImage is called on the XImage.
- */
- virtual void reduceDepth(Surface &sf, XImage *im) const = 0;
-
-public:
- virtual ~RenderControl();
-
- static RenderControl *createRenderControl(int screen);
-
- //! Draws a background onto a Surface, as specified by a RenderTexture
- /*!
- This function will overwrite the entire surface.
- */
- virtual void drawBackground(Surface &sf,
- const RenderTexture &texture) const;
-
- //! Draws an image onto the surface
- /*!
- This function will overwrite the entire surface.<br>
- The image must be specified in 32-bit packed ARGB format. The current
- background will be used for applying the alpha.
- */
- virtual void drawImage(Surface &sf, int w, int h,
- unsigned long *data) const;
-
- //! Draws an image onto the surface
- virtual void drawImage(Surface &sf, Pixmap pixmap, Pixmap mask) const;
-
- //! Draws a string onto a Surface
- virtual void drawString(Surface &sf, const Font &font, int x, int y,
- const RenderColor &color,
- const ustring &string) const;
-
- //! Draws a PixmapMask with a specified color onto a Surface
- virtual void drawMask(Surface &sf, const RenderColor &color,
- const PixmapMask &mask) const;
-
- virtual void allocateColor(XColor *color) const = 0;
-};
-
-}
-
-#endif // __rendercontrol_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "renderstyle.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-
-#include <cassert>
-
-namespace otk {
-
-RenderStyle **RenderStyle::_styles = 0;
-std::list<StyleNotify*> *RenderStyle::_notifies = 0;
-
-void RenderStyle::initialize()
-{
- int screens = ScreenCount(**display);
- _styles = new RenderStyle*[screens];
- for (int i = 0; i < screens; ++i) {
- _styles[i] = new RenderStyle();
- defaultStyle(_styles[i], i);
- }
- _notifies = new std::list<StyleNotify*>[screens];
-}
-
-void RenderStyle::destroy()
-{
- int screens = ScreenCount(**display);
- for (int i = 0; i < screens; ++i)
- delete _styles[i];
- delete [] _styles;
- delete [] _notifies;
-}
-
-void RenderStyle::registerNotify(int screen, StyleNotify *n)
-{
- assert(screen >= 0 && screen < ScreenCount(**display));
- _notifies[screen].push_back(n);
-}
-
-void RenderStyle::unregisterNotify(int screen, StyleNotify *n)
-{
- assert(screen >= 0 && screen < ScreenCount(**display));
- _notifies[screen].remove(n);
-}
-
-RenderStyle *RenderStyle::style(int screen)
-{
- assert(screen >= 0 && screen < ScreenCount(**display));
- return _styles[screen];
-}
-
-bool RenderStyle::setStyle(int screen, const ustring &stylefile)
-{
- RenderStyle *s = new RenderStyle();
- if (!loadStyle(s, screen, stylefile)) {
- delete s;
- return false;
- }
- delete _styles[screen];
- _styles[screen] = s;
-
- std::list<StyleNotify*>::iterator it, end = _notifies[screen].end();
- for (it = _notifies[screen].begin(); it != end; ++it)
- (*it)->styleChanged(*s);
- return true;
-}
-
-bool RenderStyle::loadStyle(RenderStyle *s, int screen,
- const ustring &stylefile)
-{
- s->_screen = screen;
- s->_file = stylefile;
-// pick one..
-#define FIERON
-//#define MERRY
-
-#ifdef FIERON
- s->_root_args = "#272a2f";
-
- s->_text_color_focus = new RenderColor(screen, 0x272a2f);
- s->_text_color_unfocus = new RenderColor(screen, 0x676869);
-
- s->_button_color_focus = new RenderColor(screen, 0x96ba86);
- s->_button_color_unfocus = new RenderColor(screen, 0x676869);
-
- s->_frame_border_color = new RenderColor(screen, 0x181f24);
- s->_frame_border_width = 1;
-
- s->_client_border_color_focus = new RenderColor(screen, 0x858687);
- s->_client_border_color_unfocus = new RenderColor(screen, 0x555657);
- s->_client_border_width = 1;
-
- s->_titlebar_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x858687,
- 0x373a3f,
- 0x0,
- 0x0);
- s->_titlebar_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x555657,
- 0x171a1f,
- 0x0,
- 0x0);
-
- s->_label_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Vertical,
- false,
- 0x96ba86,
- 0x5a724c,
- 0x181f24,
- 0x0);
- s->_label_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Sunken,
- RenderTexture::Bevel1,
- false,
- RenderTexture::CrossDiagonal,
- false,
- 0x555657,
- 0x272a2f,
- 0x0,
- 0x0);
-
- s->_handle_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x858687,
- 0x373a3f,
- 0x0,
- 0x0);
- s->_handle_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x555657,
- 0x171a1f,
- 0x0,
- 0x0);
-
- s->_button_unpress_focus = new RenderTexture(screen,
- false,
- RenderTexture::Raised,
- RenderTexture::Bevel2,
- false,
- RenderTexture::CrossDiagonal,
- false,
- 0x858687,
- 0x272a2f,
- 0x0,
- 0x0);
- s->_button_unpress_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Raised,
- RenderTexture::Bevel2,
- false,
- RenderTexture::CrossDiagonal,
- false,
- 0x555657,
- 0x171a1f,
- 0x0,
- 0x0);
-
- s->_button_press_focus = new RenderTexture(screen,
- false,
- RenderTexture::Sunken,
- RenderTexture::Bevel2,
- false,
- RenderTexture::CrossDiagonal,
- false,
- 0x96ba86,
- 0x5a724c,
- 0x0,
- 0x0);
- s->_button_press_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Sunken,
- RenderTexture::Bevel2,
- false,
- RenderTexture::CrossDiagonal,
- false,
- 0x555657,
- 0x171a1f,
- 0x0,
- 0x0);
-
- s->_grip_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x96ba86,
- 0x5a724c,
- 0x0,
- 0x0);
- s->_grip_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0x555657,
- 0x171a1f,
- 0x0,
- 0x0);
-
- s->_label_font = new Font(screen, "Arial,Sans-9:bold", true, 1, 0x40);
- s->_label_justify = RightBottomJustify;
-
- s->_max_mask = new PixmapMask();
- s->_max_mask->w = s->_max_mask->h = 8;
- {
- //char data[] = { 0x7e, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0x7e };
- char data [] = {0x00, 0x00, 0x18, 0x3c, 0x66, 0x42, 0x00, 0x00 };
- s->_max_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 8, 8);
- }
-
- s->_icon_mask = new PixmapMask();
- s->_icon_mask->w = s->_icon_mask->h = 8;
- {
- //char data[] = { 0x00, 0x00, 0xc3, 0xe7, 0x7e, 0x3c, 0x18, 0x00 };
- char data[] = { 0x00, 0x00, 0x42, 0x66, 0x3c, 0x18, 0x00, 0x00 };
- s->_icon_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 8, 8);
- }
-
- s->_alldesk_mask = new PixmapMask();
- s->_alldesk_mask->w = s->_alldesk_mask->h = 8;
- {
- //char data[] = { 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00 };
- char data[] = { 0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00 };
- s->_alldesk_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 8, 8);
- }
-
- s->_close_mask = new PixmapMask();
- s->_close_mask->w = s->_close_mask->h = 8;
- {
- //char data[] = { 0xc3, 0xe7, 0x7e, 0x3c, 0x3c, 0x7e, 0xe7, 0xc3 };
- char data[] = { 0x00, 0xc3, 0x66, 0x3c, 0x3c, 0x66, 0xc3, 0x00 };
- s->_close_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 8, 8);
- }
-
- s->_bevel_width = 1;
- s->_handle_width = 4;
-#else
-# ifdef MERRY
- s->_root_args = "#7b756a";
-
- s->_text_color_focus = new RenderColor(screen, 0xffffff);
- s->_text_color_unfocus = new RenderColor(screen, 0xffffff);
-
- s->_button_color_focus = new RenderColor(screen, 0x222222);
- s->_button_color_unfocus = new RenderColor(screen, 0x333333);
-
- s->_frame_border_color = new RenderColor(screen, 0x222222);
- s->_frame_border_width = 1;
-
- s->_client_border_color_focus = new RenderColor(screen, 0x858687);
- s->_client_border_color_unfocus = new RenderColor(screen, 0x555657);
- s->_client_border_width = 0;
-
- s->_titlebar_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
- s->_titlebar_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xd9d9d9,
- 0x0,
- 0x0);
-
- s->_label_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Vertical,
- false,
- //0x6a6973,
- //0x6a6973,
- 0x4c59a6,
- 0x5a6dbd,
- 0x222222,
- 0x0);
- //urg this ain't so hot
- s->_label_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Vertical,
- false,
- 0xb4b2ad,
- 0xc3c1bc,
- 0x6a696a,
- 0x0);
-
-
- s->_handle_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0xe6e6e6,
- 0xd9d9d9,
- 0x0,
- 0x0);
- s->_handle_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
-
-
- s->_button_unpress_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
- s->_button_unpress_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
-
- s->_button_press_focus = new RenderTexture(screen,
- false,
- RenderTexture::Sunken,
- RenderTexture::Bevel2,
- false,
- RenderTexture::Vertical,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
- s->_button_press_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Sunken,
- RenderTexture::Bevel2,
- false,
- RenderTexture::Vertical,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
-
- s->_grip_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Vertical,
- false,
- 0xe6e6e6,
- 0xd9d9d9,
- 0x0,
- 0x0);
- s->_grip_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0xe6e6e6,
- 0xe6e6e6,
- 0x0,
- 0x0);
-
- s->_label_font = new Font(screen, "Arial,Sans-8", true, 1, 0x3e);
- s->_label_justify = CenterJustify;
-
- s->_max_mask = new PixmapMask();
- s->_max_mask->w = s->_max_mask->h = 7;
- {
- char data [] = {0x7c, 0x44, 0x47, 0x47, 0x7f, 0x1f, 0x1f };
- s->_max_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 7, 7);
- }
-
- s->_icon_mask = new PixmapMask();
- s->_icon_mask->w = s->_icon_mask->h = 7;
- {
- char data[] = { 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e };
- s->_icon_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 7, 7);
- }
-
- s->_alldesk_mask = new PixmapMask();
- s->_alldesk_mask->w = s->_alldesk_mask->h = 7;
- {
- char data[] = {0x00, 0x36, 0x36, 0x00, 0x36, 0x36, 0x00 };
- s->_alldesk_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 7, 7);
- }
-
- s->_close_mask = new PixmapMask();
- s->_close_mask->w = s->_close_mask->h = 7;
- {
- char data[] = { 0x22, 0x77, 0x3e, 0x1c, 0x3e, 0x77, 0x22 };
- s->_close_mask->mask =
- XCreateBitmapFromData(**display,
- display->screenInfo(screen)->rootWindow(),
- data, 7, 7);
- }
-
- s->_bevel_width = 1;
- s->_handle_width = 3;
-# else
-# error 1
-# endif
-#endif
-
- return true;
-}
-
-void RenderStyle::defaultStyle(RenderStyle *s, int screen)
-{
- s->_screen = screen;
- s->_file = "";
-
- s->_root_args = "#000000";
- s->_text_color_focus = new RenderColor(screen, 0xffffff);
- s->_text_color_unfocus = new RenderColor(screen, 0xffffff);
- s->_button_color_focus = new RenderColor(screen, 0xffffff);
- s->_button_color_unfocus = new RenderColor(screen, 0xffffff);
- s->_frame_border_color = new RenderColor(screen, 0);
- s->_frame_border_width = 1;
- s->_client_border_color_focus = new RenderColor(screen, 0);
- s->_client_border_color_unfocus = new RenderColor(screen, 0);
- s->_client_border_width = 1;
- s->_titlebar_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
- s->_titlebar_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_label_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
- s->_label_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_handle_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
- s->_handle_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_button_unpress_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Solid,
- false,
- 0, 0, 0xffffff, 0);
- s->_button_unpress_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_button_press_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- true,
- RenderTexture::Solid,
- false,
- 0, 0, 0xffffff, 0);
- s->_button_press_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_grip_focus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
- s->_grip_unfocus = new RenderTexture(screen,
- false,
- RenderTexture::Flat,
- RenderTexture::Bevel1,
- false,
- RenderTexture::Solid,
- false,
- 0, 0, 0, 0);
-
- s->_label_font = new Font(screen, "Sans-9", false, 0, 0);
- s->_label_justify = LeftTopJustify;
-
- s->_max_mask = new PixmapMask();
- s->_max_mask->w = s->_max_mask->h = 0;
- s->_max_mask->mask = None;
-
- s->_icon_mask = new PixmapMask();
- s->_icon_mask->w = s->_icon_mask->h = 0;
- s->_icon_mask->mask = None;
-
- s->_alldesk_mask = new PixmapMask();
- s->_alldesk_mask->w = s->_alldesk_mask->h = 0;
- s->_alldesk_mask->mask = 0;
-
- s->_close_mask = new PixmapMask();
- s->_close_mask->w = s->_close_mask->h = 8;
- s->_close_mask->mask = 0;
-
- s->_bevel_width = 1;
- s->_handle_width = 4;
-}
-
-RenderStyle::~RenderStyle()
-{
- assert(_text_color_focus);
- delete _text_color_focus;
- assert(_text_color_unfocus);
- delete _text_color_unfocus;
-
- assert(_button_color_focus);
- delete _button_color_focus;
- assert(_button_color_unfocus);
- delete _button_color_unfocus;
-
- assert(_frame_border_color);
- delete _frame_border_color;
-
- assert(_client_border_color_focus);
- delete _client_border_color_focus;
- assert(_client_border_color_unfocus);
- delete _client_border_color_unfocus;
-
- assert(_titlebar_focus);
- delete _titlebar_focus;
- assert(_titlebar_unfocus);
- delete _titlebar_unfocus;
-
- assert(_label_focus);
- delete _label_focus;
- assert(_label_unfocus);
- delete _label_unfocus;
-
- assert(_handle_focus);
- delete _handle_focus;
- assert(_handle_unfocus);
- delete _handle_unfocus;
-
- assert(_button_unpress_focus);
- delete _button_unpress_focus;
- assert(_button_unpress_unfocus);
- delete _button_unpress_unfocus;
- assert(_button_press_focus);
- delete _button_press_focus;
- assert(_button_press_unfocus);
- delete _button_press_unfocus;
-
- assert(_grip_focus);
- delete _grip_focus;
- assert(_grip_unfocus);
- delete _grip_unfocus;
-
- assert(_label_font);
- delete _label_font;
-
- assert(_max_mask);
- delete _max_mask;
- assert(_icon_mask);
- delete _icon_mask;
- assert(_alldesk_mask);
- delete _alldesk_mask;
- assert(_close_mask);
- delete _close_mask;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __renderstyle_hh
-#define __renderstyle_hh
-
-#include "rendertexture.hh"
-#include "rendercolor.hh"
-#include "font.hh"
-#include "ustring.hh"
-
-#include <list>
-#include <string>
-
-namespace otk {
-
-struct PixmapMask {
- Pixmap mask;
- unsigned int w, h;
- PixmapMask() { mask = None; w = h = 0; }
-};
-
-class RenderStyle;
-
-class StyleNotify {
-public:
- //! Called when the style is changed on the same screen as the handler.
- virtual void styleChanged(const RenderStyle &) {}
-};
-
-class RenderStyle {
- static RenderStyle **_styles;
- static std::list<StyleNotify*> *_notifies;
-public:
- static void initialize();
- static void destroy();
- static void registerNotify(int screen, StyleNotify *n);
- static void unregisterNotify(int screen, StyleNotify *n);
- static RenderStyle *style(int screen);
- static bool setStyle(int screen, const ustring &stylefile);
-
- enum Justify {
- LeftTopJustify,
- RightBottomJustify,
- CenterJustify
- };
-
-private:
- static bool loadStyle(RenderStyle *s, int screen, const ustring &stylefile);
- static void defaultStyle(RenderStyle *s, int screen);
-
- int _screen;
- ustring _file;
-
- std::string _root_args;
-
- RenderColor *_text_color_focus;
- RenderColor *_text_color_unfocus;
-
- RenderColor *_button_color_focus;
- RenderColor *_button_color_unfocus;
-
- RenderColor *_frame_border_color;
- int _frame_border_width;
-
- RenderColor *_client_border_color_focus;
- RenderColor *_client_border_color_unfocus;
- int _client_border_width;
-
- RenderTexture *_titlebar_focus;
- RenderTexture *_titlebar_unfocus;
-
- RenderTexture *_label_focus;
- RenderTexture *_label_unfocus;
-
- RenderTexture *_handle_focus;
- RenderTexture *_handle_unfocus;
-
- RenderTexture *_button_unpress_focus;
- RenderTexture *_button_unpress_unfocus;
- RenderTexture *_button_press_focus;
- RenderTexture *_button_press_unfocus;
-
- RenderTexture *_grip_focus;
- RenderTexture *_grip_unfocus;
-
- Font *_label_font;
- Justify _label_justify;
-
- PixmapMask *_max_mask;
- PixmapMask *_icon_mask;
- PixmapMask *_alldesk_mask;
- PixmapMask *_close_mask;
-
- int _handle_width;
- int _bevel_width;
-
-public:
- virtual ~RenderStyle();
-
- inline int screen() const { return _screen; }
-
- inline const std::string& rootArgs() const { return _root_args; }
-
- inline RenderColor *textFocusColor() const { return _text_color_focus; }
- inline RenderColor *textUnfocusColor() const { return _text_color_unfocus; }
-
- inline RenderColor *buttonFocusColor() const { return _button_color_focus; }
- inline RenderColor *buttonUnfocusColor() const
- { return _button_color_unfocus; }
-
- inline RenderColor *frameBorderColor() const { return _frame_border_color; }
- inline int frameBorderWidth() const { return _frame_border_width; }
-
- inline RenderColor *clientBorderFocusColor() const
- { return _client_border_color_focus; }
- inline RenderColor *clientBorderUnfocusColor() const
- { return _client_border_color_unfocus; }
- inline int clientBorderWidth() const { return _client_border_width; }
-
- inline RenderTexture *titlebarFocusBackground() const
- { return _titlebar_focus; }
- inline RenderTexture *titlebarUnfocusBackground() const
- { return _titlebar_unfocus; }
-
- inline RenderTexture *labelFocusBackground() const { return _label_focus; }
- inline RenderTexture *labelUnfocusBackground() const { return _label_unfocus;}
-
- inline RenderTexture *handleFocusBackground() const { return _handle_focus; }
- inline RenderTexture *handleUnfocusBackground() const
- { return _handle_unfocus; }
-
- inline RenderTexture *buttonUnpressFocusBackground() const
- { return _button_unpress_focus; }
- inline RenderTexture *buttonUnpressUnfocusBackground() const
- { return _button_unpress_unfocus; }
- inline RenderTexture *buttonPressFocusBackground() const
- { return _button_press_focus; }
- inline RenderTexture *buttonPressUnfocusBackground() const
- { return _button_press_unfocus; }
-
- inline RenderTexture *gripFocusBackground() const { return _grip_focus; }
- inline RenderTexture *gripUnfocusBackground() const { return _grip_unfocus; }
-
- inline Font *labelFont() const { return _label_font; }
- inline Justify labelTextJustify() const { return _label_justify; }
-
- inline PixmapMask *maximizeMask() const { return _max_mask; }
- inline PixmapMask *iconifyMask() const { return _icon_mask; }
- inline PixmapMask *alldesktopsMask() const { return _alldesk_mask; }
- inline PixmapMask *closeMask() const { return _close_mask; }
-
- inline int handleWidth() const { return _handle_width; }
- inline int bevelWidth() const { return _bevel_width; }
-};
-
-}
-
-#endif // __renderstyle_hh
+++ /dev/null
-#include "config.h"
-
-#include "otk.hh"
-#include "rendercontrol.hh"
-#include "rendertexture.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <cstdio>
-
-int main(int argc, char **argv)
-{
- printf("\n");
-
- otk::Application app(argc, argv);
- otk::AppWidget foo(&app);
- foo.resize(600, 500);
-
- otk::RenderColor color(0, 0x96, 0xba, 0x86);
- otk::RenderColor color2(0, 0x5a, 0x72, 0x4c);
- otk::RenderColor colord(0, 0, 0, 0);
- otk::RenderColor colorl(0, 0xff, 0xff, 0xff);
- otk::RenderTexture tex(false,
- otk::RenderTexture::Raised,
- otk::RenderTexture::Bevel1,
- false,
- otk::RenderTexture::Vertical,
- false,
- &color,
- &color2,
- &colord,
- &colorl,
- 0,
- 0);
- foo.setTexture(&tex);
-
- foo.show();
-
- app.run();
-
- printf("\n");
- return 0;
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __rendertexture_hh
-#define __rendertexture_hh
-
-#include "rendercolor.hh"
-
-namespace otk {
-
-//! Superclass for all the Textures
-class RenderTexture {
-public:
- enum ReliefType {
- Flat,
- Raised,
- Sunken
- };
- enum BevelType {
- Bevel1,
- Bevel2
- };
- enum GradientType {
- Solid,
- Horizontal,
- Vertical,
- Diagonal,
- CrossDiagonal,
- PipeCross,
- Rectangle,
- Pyramid,
- Elliptic
- };
-
-private:
- int _screen;
-
- //! If true, the texture is not rendered at all, so all options are ignored
- bool _parent_relative;
- //! The relief type of the texture
- ReliefType _relief;
- //! The way the bevel should be drawn
- BevelType _bevel;
- //! If a flat border is drawn on the outside, ignored for all ReliefType
- //! values except ReliefType::Flat
- bool _border;
- //! The type of gradient to fill the texture with (if any)
- GradientType _gradient;
- //! If interlace lines should be drawn over the texture
- bool _interlaced;
-
- //! The base color for the texture, the only color when the texture is solid.
- //! This must always be defined
- const RenderColor *_color;
- //! The secondary color for a gradient texture.
- //! This is only defined for gradients
- const RenderColor *_secondary_color;
- //! The shadow color for the bevel. This must be defined if
- //! RenderTexture::_relief is not RenderTexture::ReliefType::Flat
- const RenderColor *_bevel_dark_color;
- //! The light color for the bevel. This must be defined if
- //! RenderTexture::_relief is not RenderTexture::ReliefType::Flat
- const RenderColor *_bevel_light_color;
- //! The color for the flat border if RenderTexture::_border is true. This
- //! must be defined if it is true
- const RenderColor *_border_color;
- //! The color for the interlace lines if RenderTexture. This must be defined
- //! if it is true
- const RenderColor *_interlace_color;
-
-public:
- RenderTexture(int screen,
- bool parent_relative, ReliefType relief, BevelType bevel,
- bool border, GradientType gradient, bool interlaced,
- const RGB &color,
- const RGB &secondary_color,
- const RGB &border_color,
- const RGB &interlace_color)
- : _screen(screen),
- _parent_relative(parent_relative),
- _relief(relief),
- _bevel(bevel),
- _border(border),
- _gradient(gradient),
- _interlaced(interlaced),
- _color(new RenderColor(screen, color)),
- _secondary_color(new RenderColor(screen, secondary_color)),
- _bevel_dark_color(0),
- _bevel_light_color(0),
- _border_color(new RenderColor(screen, border_color)),
- _interlace_color(new RenderColor(screen, interlace_color))
- {
- if (_relief != Flat) {
- unsigned char r, g, b;
-
- // calculate the light bevel color
- r = _color->red() + _color->red() / 2;
- g = _color->green() + _color->green() / 2;
- b = _color->blue() + _color->blue() / 2;
- // watch for wraparound
- if (r < _color->red()) r = 0xff;
- if (g < _color->green()) g = 0xff;
- if (b < _color->blue()) b = 0xff;
- _bevel_dark_color = new RenderColor(screen, r, g, b);
-
- // calculate the dark bevel color
- r = _color->red() / 4 + _color->red() / 2;
- g = _color->green() / 4 + _color->green() / 2;
- b = _color->blue() / 4 + _color->blue() / 2;
- _bevel_light_color = new RenderColor(screen, r, g, b);
- }
-
- assert(_relief == Flat || (_bevel_dark_color && _bevel_light_color));
- //assert(!_border || _border_color);
- //assert(!_interlaced || _interlace_color);
- assert(_color);
- assert(_secondary_color);
- assert(_border_color);
- assert(_interlace_color);
- }
-
- virtual ~RenderTexture() {
- delete _color;
- delete _secondary_color;
- if (_bevel_dark_color) delete _bevel_dark_color;
- if (_bevel_dark_color) delete _bevel_light_color;
- delete _border_color;
- delete _interlace_color;
- }
-
- //! If true, the texture is not rendered at all, so all options are ignored
- inline bool parentRelative() const { return _parent_relative; }
- //! The relief type of the texture
- inline ReliefType relief() const { return _relief; }
- //! The way the bevel should be drawn
- inline BevelType bevel() const { return _bevel; }
- //! If a flat border is drawn on the outside, ignored for all ReliefType
- //! values except ReliefType::Flat
- inline bool border() const { return _border; }
- //! The type of gradient to fill the texture with (if any)
- inline GradientType gradient() const { return _gradient; }
- //! If interlace lines should be drawn over the texture
- inline bool interlaced() const { return _interlaced; }
-
- //! The base color for the texture, the only color when the texture is solid.
- //! This must always be defined
- inline const RenderColor& color() const { return *_color; }
- //! The secondary color for gradient textures.
- //! This is only defined for gradients
- inline const RenderColor& secondary_color() const
- { return *_secondary_color; }
- //! The shadow color for the bevel. This must be defined if
- //! RenderTexture::_relief is not RenderTexture::ReliefType::Flat
- inline const RenderColor& bevelDarkColor() const
- { return *_bevel_dark_color; }
- //! The light color for the bevel. This must be defined if
- //! RenderTexture::)relief is not RenderTexture::ReliefType::Flat
- inline const RenderColor& bevelLightColor() const
- { return *_bevel_light_color; }
- //! The color for the flat border if RenderTexture::_border is true. This
- //! must be defined if it is true
- inline const RenderColor& borderColor() const { return *_border_color; }
- //! The color for the interlace lines if RenderTexture. This must be defined
- //! if it is true
- inline const RenderColor& interlaceColor() const
- { return *_interlace_color; }
-};
-
-}
-
-#endif // __rendertexture_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-extern "C" {
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-}
-
-#include "screeninfo.hh"
-#include "display.hh"
-#include "util.hh"
-
-using std::string;
-
-namespace otk {
-
-ScreenInfo::ScreenInfo(int num) {
- assert(num >= 0 && num < ScreenCount(**display));
-
- _screen = num;
-
- _root_window = RootWindow(**display, _screen);
-
- _size = Size(WidthOfScreen(ScreenOfDisplay(**display,
- _screen)),
- HeightOfScreen(ScreenOfDisplay(**display,
- _screen)));
- // get the default display string and strip the screen number
- string default_string = DisplayString(**display);
- const string::size_type pos = default_string.rfind(".");
- if (pos != string::npos)
- default_string.resize(pos);
-
- _display_string = string("DISPLAY=") + default_string + '.' +
- itostring(static_cast<unsigned long>(_screen));
-
-#if 0 //def XINERAMA
- _xinerama_active = False;
-
- if (d->hasXineramaExtensions()) {
- if (d->getXineramaMajorVersion() == 1) {
- // we know the version 1(.1?) protocol
-
- /*
- in this version of Xinerama, we can't query on a per-screen basis, but
- in future versions we should be able, so the 'activeness' is checked
- on a pre-screen basis anyways.
- */
- if (XineramaIsActive(**display)) {
- /*
- If Xinerama is being used, there there is only going to be one screen
- present. We still, of course, want to use the screen class, but that
- is why no screen number is used in this function call. There should
- never be more than one screen present with Xinerama active.
- */
- int num;
- XineramaScreenInfo *info = XineramaQueryScreens(**display, &num);
- if (num > 0 && info) {
- _xinerama_areas.reserve(num);
- for (int i = 0; i < num; ++i) {
- _xinerama_areas.push_back(Rect(info[i].x_org, info[i].y_org,
- info[i].width, info[i].height));
- }
- XFree(info);
-
- // if we can't find any xinerama regions, then we act as if it is not
- // active, even though it said it was
- _xinerama_active = true;
- }
- }
- }
- }
-#else
- _xinerama_active = false;
-#endif // XINERAMA
- if (!_xinerama_active)
- _xinerama_areas.push_back(Rect(Point(0, 0), _size));
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __screeninfo_hh
-#define __screeninfo_hh
-
-#include "size.hh"
-#include "rect.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <string>
-#include <vector>
-
-namespace otk {
-
-class ScreenInfo {
-private:
- int _screen;
- std::string _display_string;
- Size _size;
- std::vector<Rect> _xinerama_areas;
- bool _xinerama_active;
-
-public:
- ScreenInfo(int num);
-
- inline Visual *visual() const { return _visual; }
- inline Window rootWindow() const { return _root_window; }
- inline Colormap colormap() const { return _colormap; }
- inline int depth() const { return _depth; }
- inline int screen() const { return _screen; }
- inline const Size& size() const { return _size; }
- inline const std::string& displayString() const { return _display_string; }
- inline const std::vector<Rect> &xineramaAreas() const
- { return _xinerama_areas; }
- inline bool isXineramaActive() const { return _xinerama_active; }
-};
-
-}
-
-#endif // __screeninfo_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __size_hh
-#define __size_hh
-
-#include <cassert>
-
-namespace otk {
-
-class Size {
- int _w, _h;
-public:
- Size() : _w(1), _h(1) {}
- Size(int w, int h) : _w(w), _h(h) { assert(_w >= 0 && _h >= 0); }
- Size(const Size &s) : _w(s._w), _h(s._h) { assert(_w >= 0 && _h >= 0); }
-
- inline int width() const { return _w; }
- inline int height() const { return _h; }
-
- bool operator==(const Size &o) const { return _w == o._w && _h == o._h; }
- bool operator!=(const Size &o) const { return _w != o._w || _h != o._h; }
-};
-
-}
-
-#endif // __size_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __strut_hh
-#define __strut_hh
-
-/*! @file strut.hh
- @brief The Strut struct defines a margin on 4 sides
-*/
-
-namespace otk {
-
-//! Defines a margin on 4 sides
-struct Strut {
- //! The margin on the top of the Strut
- unsigned int top;
- //! The margin on the bottom of the Strut
- unsigned int bottom;
- //! The margin on the left of the Strut
- unsigned int left;
- //! The margin on the right of the Strut
- unsigned int right;
-
- //! Constructs a new Strut with no margins
- Strut(void): top(0), bottom(0), left(0), right(0) {}
- //! Constructs a new Strut with margins
- Strut(int l, int t, int r, int b): top(t), bottom(b), left(l), right(r) {}
-
- bool operator==(const Strut &o) const {
- return top == o.top && bottom == o.bottom && left == o.left &&
- right == o.right;
- }
-};
-
-}
-
-#endif // __strut_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "surface.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-#include "rendercolor.hh"
-
-extern "C" {
-#include <X11/Xutil.h>
-#include <cstring>
-}
-
-namespace otk {
-
-Surface::Surface(int screen, const Size &size)
- : _screen(screen),
- _size(size),
- _pixel_data(new pixel32[size.width()*size.height()]),
- _pixmap(None),
- _xftdraw(0)
-{
-}
-
-Surface::~Surface()
-{
- destroyObjects();
- freePixelData();
-}
-
-void Surface::freePixelData()
-{
- if (_pixel_data) {
- delete [] _pixel_data;
- _pixel_data = 0;
- }
-}
-
-void Surface::setPixmap(const RenderColor &color)
-{
- assert(_pixel_data);
- if (_pixmap == None)
- createObjects();
-
- XFillRectangle(**display, _pixmap, color.gc(), 0, 0,
- _size.width(), _size.height());
-
- pixel32 val = (color.red() << default_red_shift) |
- (color.green() << default_green_shift) |
- (color.blue() << default_blue_shift);
- for (unsigned int i = 0, s = _size.width() * _size.height(); i < s; ++i)
- _pixel_data[i] = val;
-}
-
-void Surface::setPixmap(XImage *image)
-{
- assert(_pixel_data);
- assert(image->width == _size.width());
- assert(image->height == _size.height());
-
- if (_pixmap == None)
- createObjects();
-
- XPutImage(**display, _pixmap, DefaultGC(**display, _screen),
- image, 0, 0, 0, 0, _size.width(), _size.height());
-}
-
-void Surface::createObjects()
-{
- assert(_pixmap == None); assert(!_xftdraw);
-
- const ScreenInfo *info = display->screenInfo(_screen);
-
- _pixmap = XCreatePixmap(**display, info->rootWindow(),
- _size.width(), _size.height(), info->depth());
- assert(_pixmap != None);
-
- _xftdraw = XftDrawCreate(**display, _pixmap,
- info->visual(), info->colormap());
- assert(_xftdraw);
-}
-
-void Surface::destroyObjects()
-{
- if (_xftdraw) {
- XftDrawDestroy(_xftdraw);
- _xftdraw = 0;
- }
-
- if (_pixmap != None) {
- XFreePixmap(**display, _pixmap);
- _pixmap = None;
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __surface_hh
-#define __surface_hh
-
-#include "size.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-#define _XFT_NO_COMPAT_ // no Xft 1 API
-#include <X11/Xft/Xft.h>
-
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#else
-# ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-# endif
-#endif
-}
-
-namespace otk {
-
-class ScreenInfo;
-class RenderColor;
-class RenderControl;
-class TrueRenderControl;
-class PseudoRenderControl;
-
-#ifdef HAVE_STDINT_H
-typedef uint32_t pixel32;
-typedef uint16_t pixel16;
-#else
-typedef u_int32_t pixel32;
-typedef u_int16_t pixel16;
-#endif /* HAVE_STDINT_H */
-
-#ifdef WORDS_BIGENDIAN
-const int default_red_shift=0;
-const int default_green_shift=8;
-const int default_blue_shift=16;
-const int endian=MSBFirst;
-#else
-const int default_red_shift=16;
-const int default_green_shift=8;
-const int default_blue_shift=0;
-const int endian=LSBFirst;
-#endif /* WORDS_BIGENDIAN */
-
-class Surface {
- int _screen;
- Size _size;
- pixel32 *_pixel_data;
- Pixmap _pixmap;
- XftDraw *_xftdraw;
-
-protected:
- void createObjects();
- void destroyObjects();
-
- void setPixmap(XImage *image);
- void setPixmap(const RenderColor &color);
-
-public:
- Surface(int screen, const Size &size);
- virtual ~Surface();
-
- inline int screen(void) const { return _screen; }
-
- const Size& size() const { return _size; }
-
- Pixmap pixmap() const { return _pixmap; }
-
- pixel32 *pixelData() { return _pixel_data; }
-
- //! Frees the pixel data when it will no longer be needed. Only do this once
- //! you have completed rendering onto the surface.
- void freePixelData();
-
- // The RenderControl classes use the internal objects in this class to render
- // to it. Noone else needs them tho, so they are private.
- friend class RenderControl;
- friend class TrueRenderControl;
- friend class PseudoRenderControl;
-};
-
-}
-
-#endif // __surface_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "timer.hh"
-#include "display.hh"
-
-extern "C" {
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif // HAVE_SYS_SELECT_H
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-}
-
-namespace otk {
-
-timeval Timer::_nearest_timeout, Timer::_now;
-Timer::TimerQ Timer::_q;
-
-void Timer::timevalAdd(timeval &a, long msec)
-{
- a.tv_sec += msec / 1000;
- a.tv_usec += (msec % 1000) * 1000;
- a.tv_sec += a.tv_usec / 1000000;
- a.tv_usec %= 1000000;
-}
-
-bool Timer::nearestTimeout(struct timeval &tm)
-{
- if (_q.empty())
- return false;
- tm.tv_sec = _nearest_timeout.tv_sec - _now.tv_sec;
- tm.tv_usec = _nearest_timeout.tv_usec - _now.tv_usec;
-
- while (tm.tv_usec < 0) {
- tm.tv_usec += 1000000;
- tm.tv_sec--;
- }
- tm.tv_sec += tm.tv_usec / 1000000;
- tm.tv_usec %= 1000000;
- if (tm.tv_sec < 0)
- tm.tv_sec = 0;
-
- return true;
-}
-
-void Timer::dispatchTimers(bool wait)
-{
- fd_set selset;
- int fd;
- timeval next;
- Timer *curr;
-
- gettimeofday(&_now, NULL);
- _nearest_timeout = _now;
- _nearest_timeout.tv_sec += 10000;
-
- while (!_q.empty()) {
- curr = _q.top();
- /* since we overload the destructor to keep from removing from the middle
- of the priority queue, set _del_me, we have to do our real delete in
- here.
- */
- if (curr->_del_me) {
- _q.pop();
- realDelete(curr);
- continue;
- }
-
- // the queue is sorted, so if this timer shouldn't fire, none are ready
- _nearest_timeout = curr->_timeout;
- if (!timercmp(&_now, &_nearest_timeout, >))
- break;
-
- /* we set the last fired time to delay msec after the previous firing, then
- re-insert. timers maintain their order and may trigger more than once
- if they've waited more than one delay's worth of time.
- */
- _q.pop();
- timevalAdd(curr->_last, curr->_delay);
- curr->_action(curr->_data);
- timevalAdd(curr->_timeout, curr->_delay);
- _q.push(curr);
-
- /* if at least one timer fires, then don't wait on X events, as there may
- already be some in the queue from the timer callbacks.
- */
- wait = false;
- }
-
- if (wait) {
- // wait for the nearest trigger, or for X to do something interesting
- fd = ConnectionNumber(**display);
- FD_ZERO(&selset);
- FD_SET(fd, &selset);
- if (nearestTimeout(next)) {
- select(fd + 1, &selset, NULL, NULL, &next);
- } else
- select(fd + 1, &selset, NULL, NULL, NULL);
- }
-}
-
-Timer::Timer(long delay, Timer::TimeoutHandler action, void *data)
- : _delay(delay),
- _action(action),
- _data(data),
- _del_me(false),
- _last(_now),
- _timeout(_now)
-{
- timevalAdd(_timeout, delay);
- _q.push(this);
-}
-
-void Timer::operator delete(void *self)
-{
- Timer *t;
- t = (Timer *)self;
- t->_del_me = true;
-}
-
-void Timer::realDelete(Timer *me)
-{
- ::delete me;
-}
-
-void Timer::initialize(void)
-{
- gettimeofday(&_now, NULL);
- _nearest_timeout.tv_sec = 100000;
- _nearest_timeout.tv_usec = 0;
-}
-
-void Timer::destroy(void)
-{
- while(!_q.empty()) {
- realDelete(_q.top());
- _q.pop();
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __timer_hh
-#define __timer_hh
-
-/*! @file timer.hh
- @brief Contains the Timer class, used for timed callbacks.
-*/
-
-extern "C" {
-#include <ctime>
-}
-
-#include <queue>
-#include <vector>
-
-namespace otk {
-
-//! The Timer class implements timed callbacks.
-/*!
- The Timer class can be used to have a callback fire after a given time
- interval. A created Timer will fire repetitively until it is destroyed.
-*/
-class Timer {
-public:
- //! Data type of Timer callback
- typedef void (*TimeoutHandler)(void *data);
-
-private:
- //! Compares two timeval structs
- struct TimerCompare {
- //! Compares two timeval structs
- inline bool operator()(const Timer *a, const Timer *b) const {
- return ((&a->_timeout)->tv_sec == (&b->_timeout)->tv_sec) ?
- ((&a->_timeout)->tv_usec > (&b->_timeout)->tv_usec) :
- ((&a->_timeout)->tv_sec > (&b->_timeout)->tv_sec);
- }
- };
- friend struct TimerCompare; // give access to _timeout for shitty compilers
-
- typedef
- std::priority_queue<Timer*, std::vector<Timer*>, TimerCompare> TimerQ;
-
- //! Milliseconds between timer firings
- long _delay;
- //! Callback for timer expiry
- TimeoutHandler _action;
- //! Data sent to callback
- void *_data;
- //! We overload the delete operator to just set this to true
- bool _del_me;
- //! The time the last fire should've been at
- struct timeval _last;
- //! When this timer will next trigger
- struct timeval _timeout;
-
- //! Queue of pending timers
- static TimerQ _q;
- //! Time next timer will expire
- static timeval _nearest_timeout;
- //! Time at start of current processing loop
- static timeval _now;
-
- //! Really delete something (not just flag for later)
- /*!
- @param self Timer to be deleted.
- */
- static void realDelete(Timer *self);
-
- //! Adds a millisecond delay to a timeval structure
- /*!
- @param a Amount of time to increment.
- @param msec Number of milliseconds to increment by.
- */
- static void timevalAdd(timeval &a, long msec);
-
-public:
- //! Constructs a new running timer and queues it
- /*!
- @param delay Time in milliseconds between firings
- @param cb The function to be called on fire.
- @param data Data to be passed to the callback on fire.
- */
- Timer(long delay, TimeoutHandler cb, void *data);
-
- //! Overloaded delete so we can leave deleted objects in queue for later reap
- /*!
- @param self Pointer to current instance of Timer.
- */
- void operator delete(void *self);
-
- //! Dispatches all elligible timers, then optionally waits for X events
- /*!
- @param wait Whether to wait for X events after processing timers.
- */
- static void dispatchTimers(bool wait = true);
-
- //! Returns a relative timeval (to pass select) of the next timer
- /*!
- @param tm Changed to hold the time until next timer.
- @return true if there are any timers queued, and the timeout is being
- returned in 'tm'. false if there are no timers queued.
- */
- static bool nearestTimeout(struct timeval &tm);
-
- //! Initializes internal data before use
- static void initialize();
-
- //! Deletes all waiting timers
- static void destroy();
-};
-
-}
-
-#endif // __timer.hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "truerendercontrol.hh"
-#include "display.hh"
-#include "screeninfo.hh"
-#include "surface.hh"
-#include "rendertexture.hh"
-
-extern "C" {
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdlib>
-
-namespace otk {
-
-TrueRenderControl::TrueRenderControl(int screen)
- : RenderControl(screen),
- _red_offset(0),
- _green_offset(0),
- _blue_offset(0)
-{
- printf("Initializing TrueColor RenderControl\n");
-
- const ScreenInfo *info = display->screenInfo(_screen);
- XImage *timage = XCreateImage(**display, info->visual(), info->depth(),
- ZPixmap, 0, NULL, 1, 1, 32, 0);
-
- unsigned long red_mask, green_mask, blue_mask;
-
- // find the offsets for each color in the visual's masks
- red_mask = timage->red_mask;
- green_mask = timage->green_mask;
- blue_mask = timage->blue_mask;
-
- while (! (red_mask & 1)) { _red_offset++; red_mask >>= 1; }
- while (! (green_mask & 1)) { _green_offset++; green_mask >>= 1; }
- while (! (blue_mask & 1)) { _blue_offset++; blue_mask >>= 1; }
-
- _red_shift = _green_shift = _blue_shift = 8;
- while (red_mask) { red_mask >>= 1; _red_shift--; }
- while (green_mask) { green_mask >>= 1; _green_shift--; }
- while (blue_mask) { blue_mask >>= 1; _blue_shift--; }
- XFree(timage);
-}
-
-TrueRenderControl::~TrueRenderControl()
-{
- printf("Destroying TrueColor RenderControl\n");
-}
-
-void TrueRenderControl::reduceDepth(Surface &sf, XImage *im) const
-{
- // since pixel32 is the largest possible pixel size, we can share the array
- int r, g, b;
- int x,y;
- pixel32 *data = sf.pixelData();
- pixel32 *ret = (pixel32*)malloc(im->width * im->height * 4);
- pixel16 *p = (pixel16*) ret;
- switch (im->bits_per_pixel) {
- case 32:
- if ((_red_offset != default_red_shift) ||
- (_blue_offset != default_blue_shift) ||
- (_green_offset != default_green_shift)) {
- printf("cross endian conversion\n");
- for (y = 0; y < im->height; y++) {
- for (x = 0; x < im->width; x++) {
- r = (data[x] >> default_red_shift) & 0xFF;
- g = (data[x] >> default_green_shift) & 0xFF;
- b = (data[x] >> default_blue_shift) & 0xFF;
- ret[x] = (r << _red_offset) + (g << _green_offset) +
- (b << _blue_offset);
- }
- data += im->width;
- }
- } else {
- memcpy(ret, data, im->width * im->height * 4);
- }
- break;
- case 16:
- for (y = 0; y < im->height; y++) {
- for (x = 0; x < im->width; x++) {
- r = (data[x] >> default_red_shift) & 0xFF;
- r = r >> _red_shift;
- g = (data[x] >> default_green_shift) & 0xFF;
- g = g >> _green_shift;
- b = (data[x] >> default_blue_shift) & 0xFF;
- b = b >> _blue_shift;
- p[x] = (r << _red_offset) + (g << _green_offset) + (b << _blue_offset);
- }
- data += im->width;
- p += im->bytes_per_line/2;
- }
- break;
- default:
- printf("your bit depth is currently unhandled\n");
- }
- im->data = (char*)ret;
-}
-
-void TrueRenderControl::allocateColor(XColor *color) const
-{
- const ScreenInfo *info = display->screenInfo(_screen);
- if (!XAllocColor(**display, info->colormap(), color)) {
- fprintf(stderr, "TrueRenderControl: color alloc error: rgb:%x/%x/%x\n",
- color->red & 0xff, color->green & 0xff, color->blue & 0xff);
- color->pixel = 0;
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __truerendercontrol_hh
-#define __truerendercontrol_hh
-
-#include "rendercontrol.hh"
-
-#include <vector>
-
-namespace otk {
-
-class TrueRenderControl : public RenderControl {
-private:
- // the number of bits to shift a color value (from 0-255) to the right, to
- // fit it into the the color mask (do this before the offset)
- int _red_shift;
- int _green_shift;
- int _blue_shift;
-
- // the offset of each color in a color mask
- int _red_offset;
- int _green_offset;
- int _blue_offset;
-
- virtual void reduceDepth(Surface &sf, XImage *im) const;
-
-public:
- TrueRenderControl(int screen);
- virtual ~TrueRenderControl();
-
- virtual void allocateColor(XColor *color) const;
-};
-
-}
-
-#endif // __truerendercontrol_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "ustring.hh"
-
-#include <cassert>
-
-namespace otk {
-
-// helper functions
-
-// The number of bytes to skip to find the next character in the string
-static const char utf8_skip[256] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
-};
-
-// takes a pointer into a utf8 string and returns a unicode character for the
-// first character at the pointer
-unichar utf8_get_char (const char *p)
-{
- unichar result = static_cast<unsigned char>(*p);
-
- // if its not a 7-bit ascii character
- if((result & 0x80) != 0) {
- // len is the number of bytes this character takes up in the string
- unsigned char len = utf8_skip[result];
- result &= 0x7F >> len;
-
- while(--len != 0) {
- result <<= 6;
- result |= static_cast<unsigned char>(*++p) & 0x3F;
- }
- }
-
- return result;
-}
-
-// takes a pointer into a string and finds its offset
-static ustring::size_type utf8_ptr_to_offset(const char *str, const char *pos)
-{
- ustring::size_type offset = 0;
-
- while (str < pos) {
- str += utf8_skip[static_cast<unsigned char>(*str)];
- offset++;
- }
-
- return offset;
-}
-
-// takes an offset into a string and returns a pointer to it
-const char *utf8_offset_to_ptr(const char *str, ustring::size_type offset)
-{
- while (offset--)
- str += utf8_skip[static_cast<unsigned char>(*str)];
- return str;
-}
-
-// First overload: stop on '\0' character.
-ustring::size_type utf8_byte_offset(const char* str, ustring::size_type offset)
-{
- if(offset == ustring::npos)
- return ustring::npos;
-
- const char* p = str;
-
- for(; offset != 0; --offset)
- {
- if(*p == '\0')
- return ustring::npos;
-
- p += utf8_skip[static_cast<unsigned char>(*p)];
- }
-
- return (p - str);
-}
-
-// Second overload: stop when reaching maxlen.
-ustring::size_type utf8_byte_offset(const char* str, ustring::size_type offset,
- ustring::size_type maxlen)
-{
- if(offset == ustring::npos)
- return ustring::npos;
-
- const char *const pend = str + maxlen;
- const char* p = str;
-
- for(; offset != 0; --offset)
- {
- if(p >= pend)
- return ustring::npos;
-
- p += utf8_skip[static_cast<unsigned char>(*p)];
- }
-
- return (p - str);
-}
-
-
-// ustring methods
-
-ustring::ustring(bool utf8)
- : _utf8(utf8)
-{
-}
-
-ustring::~ustring()
-{
-}
-
-ustring::ustring(const ustring& other)
- : _string(other._string), _utf8(other._utf8)
-{
-}
-
-ustring& ustring::operator=(const ustring& other)
-{
- _string = other._string;
- _utf8 = other._utf8;
- return *this;
-}
-
-ustring::ustring(const std::string& src, bool utf8)
- : _string(src), _utf8(utf8)
-{
-}
-
-ustring::ustring(const char* src, bool utf8)
- : _string(src), _utf8(utf8)
-{
-}
-
-ustring& ustring::operator+=(const ustring& src)
-{
- assert(_utf8 == src._utf8);
- _string += src._string;
- return *this;
-}
-
-ustring& ustring::operator+=(const char* src)
-{
- _string += src;
- return *this;
-}
-
-ustring& ustring::operator+=(char c)
-{
- _string += c;
- return *this;
-}
-
-ustring::size_type ustring::size() const
-{
- if (_utf8) {
- const char *const pdata = _string.data();
- return utf8_ptr_to_offset(pdata, pdata + _string.size());
- } else
- return _string.size();
-}
-
-ustring::size_type ustring::bytes() const
-{
- return _string.size();
-}
-
-ustring::size_type ustring::capacity() const
-{
- return _string.capacity();
-}
-
-ustring::size_type ustring::max_size() const
-{
- return _string.max_size();
-}
-
-bool ustring::empty() const
-{
- return _string.empty();
-}
-
-void ustring::clear()
-{
- _string.erase();
-}
-
-ustring& ustring::erase(ustring::size_type i, ustring::size_type n)
-{
- if (_utf8) {
- // find a proper offset
- size_type utf_i = utf8_byte_offset(_string.c_str(), i);
- if (utf_i != npos) {
- // if the offset is not npos, find a proper length for 'n'
- size_type utf_n = utf8_byte_offset(_string.data() + utf_i, n,
- _string.size() - utf_i);
- _string.erase(utf_i, utf_n);
- }
- } else
- _string.erase(i, n);
-
- return *this;
-}
-
-void ustring::resize(ustring::size_type n, char c)
-{
- if (_utf8) {
- const size_type size_now = size();
- if(n < size_now)
- erase(n, npos);
- else if(n > size_now)
- _string.append(n - size_now, c);
- } else
- _string.resize(n, c);
-}
-
-ustring::value_type ustring::operator[](ustring::size_type i) const
-{
- return utf8_get_char(utf8_offset_to_ptr(_string.data(), i));
-}
-
-bool ustring::operator==(const ustring &other) const
-{
- return _string == other._string && _utf8 == other._utf8;
-}
-
-bool ustring::operator==(const std::string &other) const
-{
- return _string == other;
-}
-
-bool ustring::operator==(const char *other) const
-{
- return _string == other;
-}
-
-const char* ustring::data() const
-{
- return _string.data();
-}
-
-const char* ustring::c_str() const
-{
- return _string.c_str();
-}
-
-bool ustring::utf8() const
-{
- return _utf8;
-}
-
-void ustring::setUtf8(bool utf8)
-{
- _utf8 = utf8;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __ustring_hh
-#define __ustring_hh
-
-/*! @file ustring.hh
- @brief Provides a simple UTF-8 encoded string
-*/
-
-extern "C" {
-
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#else
-# ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-# endif
-#endif
-
-}
-
-#include <string>
-
-namespace otk {
-
-
-#ifdef HAVE_STDINT_H
-typedef uint32_t unichar;
-#else
-typedef u_int32_t unichar;
-#endif
-
-
-#ifndef DOXYGEN_IGNORE
-
-unichar utf8_get_char(const char *p);
-
-#endif // DOXYGEN_IGNORE
-
-//! The iterator type for ustring
-/*!
- Note this is not a random access iterator but a bidirectional one, since all
- index operations need to iterate over the UTF-8 data. Use std::advance() to
- move to a certain position.
- <p>
- A writeable iterator isn't provided because: The number of bytes of the old
- UTF-8 character and the new one to write could be different. Therefore, any
- write operation would invalidate all other iterators pointing into the same
- string.
-*/
-
-template <class T>
-class ustring_Iterator
-{
-public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef unichar value_type;
- typedef std::string::difference_type difference_type;
- //typedef value_type reference;
- typedef void pointer;
-
- inline ustring_Iterator() {}
- inline ustring_Iterator(const ustring_Iterator<std::string::iterator>&
- other) : _pos(other.base()) {}
-
-
- inline value_type operator*() const {
- // get an iterator to the internal string
- std::string::const_iterator pos = _pos;
- return utf8_get_char(&(*pos));
- }
-
-
- inline ustring_Iterator<T> & operator++() {
- pos_ += g_utf8_skip[static_cast<unsigned char>(*pos_)];
- return *this;
- }
- inline ustring_Iterator<T> & operator--() {
- do { --_pos; } while((*_pos & '\xC0') == '\x80');
- return *this;
- }
-
- explicit inline ustring_Iterator(T pos) : _pos(pos) {}
- inline T base() const { return _pos; }
-
-private:
- T _pos;
-};
-
-
-//! This class provides a simple wrapper to a std::string that can be encoded
-//! as UTF-8. The ustring::utf() member specifies if the given string is UTF-8
-//! encoded. ustrings default to specifying UTF-8 encoding.
-/*!
- This class does <b>not</b> handle extended 8-bit ASCII charsets like
- ISO-8859-1.
- <p>
- More info on Unicode and UTF-8 can be found here:
- http://www.cl.cam.ac.uk/~mgk25/unicode.html
- <p>
- This does not subclass std::string, because std::string was intended to be a
- final class. For instance, it does not have a virtual destructor.
-*/
-class ustring {
- std::string _string;
- bool _utf8;
-
-public:
- typedef std::string::size_type size_type;
- typedef std::string::difference_type difference_type;
-
- typedef unichar value_type;
- //typedef unichar & reference;
- //typedef const unichar & const_reference;
-
- //typedef ustring_Iterator<std::string::iterator> iterator;
- //typedef ustring_Iterator<std::string::const_iterator> const_iterator;
-
- static const size_type npos = std::string::npos;
-
- ustring(bool utf8 = true);
- ~ustring();
-
- // make new strings
-
- ustring(const ustring& other);
- ustring& operator=(const ustring& other);
- ustring(const std::string& src, bool utf8 = true);
- ustring(const char* src, bool utf8 = true);
-
- // append to the string
-
- ustring& operator+=(const ustring& src);
- ustring& operator+=(const char* src);
- ustring& operator+=(char c);
-
- // sizes
-
- ustring::size_type size() const;
- ustring::size_type bytes() const;
- ustring::size_type capacity() const;
- ustring::size_type max_size() const;
- bool empty() const;
-
- // erase substrings
-
- void clear();
- ustring& erase(size_type i, size_type n=npos);
-
- // change the string's size
-
- void resize(size_type n, char c='\0');
-
- // extract characters
-
- // No reference return; use replace() to write characters.
- value_type operator[](size_type i) const;
-
- // compare strings
-
- bool operator==(const ustring &other) const;
- bool operator==(const std::string &other) const;
- bool operator==(const char *other) const;
-
- // internal data
-
- const char* data() const;
- const char* c_str() const;
-
- // encoding
-
- bool utf8() const;
- void setUtf8(bool utf8);
-};
-
-}
-
-#endif // __ustring_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-extern "C" {
-#include <X11/Xatom.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif // HAVE_UNISTD_H
-
-// this is not checked in configure anymore!!
-//#if defined(HAVE_PROCESS_H) && defined(__EMX__)
-//# include <process.h>
-//#endif // HAVE_PROCESS_H __EMX__
-
-#include "../src/gettext.h"
-#define _(str) gettext(str)
-
-}
-
-#include <algorithm>
-#include <cassert>
-#include <cstdio>
-#include <cstring>
-#include <cstdlib>
-
-#include "util.hh"
-
-using std::string;
-
-namespace otk {
-
-string expandTilde(const string& s) {
- if (s[0] != '~') return s;
-
- const char* const home = getenv("HOME");
- if (home == NULL) return s;
-
- return string(home + s.substr(s.find('/')));
-}
-
-
-void bexec(const string& command, const string& displaystring) {
-//#ifndef __EMX__
- if (! fork()) {
- setsid();
- putenv(displaystring);
- int ret = execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
- exit(ret);
- }
-//#else // __EMX__
-// spawnlp(P_NOWAIT, "cmd.exe", "cmd.exe", "/c", command.c_str(), NULL);
-//#endif // !__EMX__
-}
-
-
-string itostring(unsigned long i) {
- if (i == 0)
- return string("0");
-
- string tmp;
- for (; i > 0; i /= 10)
- tmp.insert(tmp.begin(), "0123456789"[i%10]);
- return tmp;
-}
-
-
-string itostring(long i) {
- std::string tmp = itostring( (unsigned long) std::abs(i));
- if (i < 0)
- tmp.insert(tmp.begin(), '-');
- return tmp;
-}
-
-void putenv(const std::string &data)
-{
- char *c = new char[data.size() + 1];
- std::string::size_type i, max;
- for (i = 0, max = data.size(); i < max; ++i)
- c[i] = data[i];
- c[i] = 0;
- if (::putenv(c)) {
- printf(_("warning: couldn't set environment variable\n"));
- perror("putenv()");
- }
-}
-
-string basename (const string& path) {
- string::size_type slash = path.rfind('/');
- if (slash == string::npos)
- return path;
- return path.substr(slash+1);
-}
-
-}
-
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __util_hh
-#define __util_hh
-
-extern "C" {
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-}
-
-#include <string>
-#include <vector>
-
-namespace otk {
-
-std::string expandTilde(const std::string& s);
-
-void bexec(const std::string& command, const std::string& displaystring);
-
-std::string itostring(unsigned long i);
-std::string itostring(long i);
-inline std::string itostring(unsigned int i)
- { return itostring((unsigned long) i); }
-inline std::string itostring(int i)
- { return itostring((long) i); }
-
-void putenv(const std::string &data);
-
-std::string basename(const std::string& path);
-
-}
-
-#endif // __util_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-#include "widget.hh"
-#include "display.hh"
-#include "surface.hh"
-#include "rendertexture.hh"
-#include "rendercolor.hh"
-#include "eventdispatcher.hh"
-#include "screeninfo.hh"
-
-#include <climits>
-#include <cassert>
-#include <algorithm>
-
-namespace otk {
-
-Widget::Widget(int screen, EventDispatcher *ed, Direction direction, int bevel,
- bool overrideredir)
- : _texture(0),
- _screen(screen),
- _parent(0),
- _window(0),
- _surface(0),
- _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
- ExposureMask | StructureNotifyMask),
- _alignment(RenderStyle::CenterJustify),
- _direction(direction),
- _max_size(INT_MAX, INT_MAX),
- _visible(false),
- _bordercolor(0),
- _borderwidth(0),
- _bevel(bevel),
- _dirty(true),
- _dispatcher(ed),
- _ignore_config(0)
-{
- createWindow(overrideredir);
- _dispatcher->registerHandler(_window, this);
-}
-
-Widget::Widget(Widget *parent, Direction direction, int bevel)
- : _texture(0),
- _screen(parent->_screen),
- _parent(parent),
- _window(0),
- _surface(0),
- _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
- ExposureMask | StructureNotifyMask),
- _alignment(RenderStyle::CenterJustify),
- _direction(direction),
- _max_size(INT_MAX, INT_MAX),
- _visible(false),
- _bordercolor(0),
- _borderwidth(0),
- _bevel(bevel),
- _dirty(true),
- _dispatcher(parent->_dispatcher),
- _ignore_config(0)
-{
- assert(parent);
- createWindow(false);
- parent->addChild(this);
- if (parent->visible()) parent->layout();
- _dispatcher->registerHandler(_window, this);
- styleChanged(*RenderStyle::style(_screen));
-}
-
-Widget::~Widget()
-{
- assert(_children.empty()); // this would be bad. theyd have a hanging _parent
-
- if (_surface) delete _surface;
- if (_parent) _parent->removeChild(this);
-
- _dispatcher->clearHandler(_window);
- XDestroyWindow(**display, _window);
-}
-
-void Widget::show(bool children)
-{
- if (children) {
- std::list<Widget*>::iterator it , end = _children.end();
- for (it = _children.begin(); it != end; ++it) {
- (*it)->show(true);
- }
- }
- if (!_visible) {
- if (_parent) _parent->calcDefaultSizes();
- else resize(_area.size()); // constrain sizes
- _visible = true;
- XMapWindow(**display, _window);
- update();
- }
-}
-
-void Widget::hide()
-{
- if (_visible) {
- _visible = false;
- XUnmapWindow(**display, _window);
- if (_parent) {
- _parent->calcDefaultSizes();
- _parent->layout();
- }
- }
-}
-
-void Widget::setEventMask(long e)
-{
- XSelectInput(**display, _window, e);
- _event_mask = e;
-}
-
-void Widget::update()
-{
- if (!_visible) return;
- _dirty = true;
- if (_parent) {
- _parent->calcDefaultSizes();
- _parent->layout(); // relay-out us and our siblings
- } else {
- render();
- layout();
- }
-}
-
-void Widget::moveresize(const Rect &r)
-{
- int w, h;
- w = std::max(std::min(r.width(), maxSize().width()), minSize().width());
- h = std::max(std::min(r.height(), maxSize().height()), minSize().height());
-
- bool sizechange = !(w == area().width() && h == area().height());
-
- if (r.x() == area().x() && r.y() == area().y() && !sizechange)
- return; // no change, don't cause a big layout chain to occur!
-
- internal_moveresize(r.x(), r.y(), w, h);
-
- if (sizechange)
- update();
-}
-
-void Widget::internal_moveresize(int x, int y, int w, int h)
-{
- assert(w > 0);
- assert(h > 0);
- assert(_borderwidth >= 0);
- _dirty = true;
- if (!(x == _area.x() && y == _area.y())) {
- if (!(w == _area.width() && h == _area.height()))
- XMoveResizeWindow(**display, _window, x, y,
- w - _borderwidth * 2,
- h - _borderwidth * 2);
- else
- XMoveWindow(**display, _window, x, y);
- } else
- XResizeWindow(**display, _window, w - _borderwidth*2, h - _borderwidth*2);
- _ignore_config++;
-
- _area = Rect(x, y, w, h);
-}
-
-void Widget::setAlignment(RenderStyle::Justify a)
-{
- _alignment = a;
- layout();
-}
-
-void Widget::createWindow(bool overrideredir)
-{
- const ScreenInfo *info = display->screenInfo(_screen);
- XSetWindowAttributes attrib;
- unsigned long mask = CWEventMask | CWBorderPixel;
-
- attrib.event_mask = _event_mask;
- attrib.border_pixel = (_bordercolor ?
- _bordercolor->pixel():
- BlackPixel(**display, _screen));
-
- if (overrideredir) {
- mask |= CWOverrideRedirect;
- attrib.override_redirect = true;
- }
-
- _window = XCreateWindow(**display, (_parent ?
- _parent->_window :
- RootWindow(**display, _screen)),
- _area.x(), _area.y(),
- _area.width(), _area.height(),
- _borderwidth,
- info->depth(),
- InputOutput,
- info->visual(),
- mask,
- &attrib);
- assert(_window != None);
- ++_ignore_config;
-}
-
-void Widget::calcDefaultSizes()
-{
- std::list<Widget*>::const_iterator it, end = _children.end();
- int min_biggest = 0, max_biggest = 0;
- int min_sum = _bevel + _borderwidth * 2;
- int max_sum = _bevel + _borderwidth * 2;
- bool fullmax = false;
-
- for (it = _children.begin(); it != end; ++it) {
- const otk::Size &min = (*it)->minSize();
- const otk::Size &max = (*it)->maxSize();
- if (_direction == Horizontal) {
- if (min.height() > min_biggest) min_biggest = min.height();
- if (max.height() > max_biggest) max_biggest = max.height();
- min_sum += _bevel + min.width();
- if (max.width() == INT_MAX)
- fullmax = true;
- else if (!fullmax)
- max_sum += _bevel + max.width();
- } else {
- if (min.width() > min_biggest) min_biggest = min.width();
- if (max.width() > max_biggest) max_biggest = max.width();
- min_sum += _bevel + min.height();
- if (max.height() == INT_MAX)
- fullmax = true;
- else if (!fullmax)
- max_sum += _bevel + max.height();
- }
- }
- if (_direction == Horizontal) {
- _min_size = otk::Size(min_sum + (_bevel + _borderwidth) * 2,
- min_biggest + (_bevel + _borderwidth) * 2);
- _max_size = otk::Size((fullmax ? INT_MAX :
- max_sum + (_bevel + _borderwidth) * 2),
- max_biggest);
- } else {
- _min_size = otk::Size(min_biggest + (_bevel + _borderwidth) * 2,
- min_sum + (_bevel + _borderwidth) * 2);
- _max_size = otk::Size(max_biggest, (fullmax ? INT_MAX : max_sum +
- (_bevel + _borderwidth) * 2));
- }
- update();
-}
-
-void Widget::setBorderWidth(int w)
-{
- assert(w >= 0);
- if (!parent()) return; // top-level windows cannot have borders
- if (w == borderWidth()) return; // no change
-
- _borderwidth = w;
- XSetWindowBorderWidth(**display, _window, _borderwidth);
-
- calcDefaultSizes();
- update();
-}
-
-void Widget::setMinSize(const Size &s)
-{
- _min_size = s;
- update();
-}
-
-void Widget::setMaxSize(const Size &s)
-{
- _max_size = s;
- update();
-}
-
-void Widget::setBorderColor(const RenderColor *c)
-{
- _bordercolor = c;
- XSetWindowBorder(**otk::display, _window,
- c ? c->pixel() : BlackPixel(**otk::display, _screen));
-}
-
-void Widget::setBevel(int b)
-{
- _bevel = b;
- calcDefaultSizes();
- layout();
-}
-
-void Widget::layout()
-{
- if (_children.empty() || !_visible) return;
- if (_direction == Horizontal)
- layoutHorz();
- else
- layoutVert();
-}
-
-void Widget::layoutHorz()
-{
- std::list<Widget*>::iterator it, end;
-
- // work with just the visible children
- std::list<Widget*> visible;
- for (it = _children.begin(), end = _children.end(); it != end; ++it)
- if ((*it)->visible())
- visible.push_back(*it);
-
- if (visible.empty()) return;
-
- int x, y, w, h; // working area
- x = y = _bevel;
- w = _area.width() - _borderwidth * 2 - _bevel * 2;
- h = _area.height() - _borderwidth * 2 - _bevel * 2;
- if (w < 0 || h < 0) return; // not worth laying anything out!
-
- int free = w - (visible.size() - 1) * _bevel;
- if (free < 0) free = 0;
- int each;
-
- std::list<Widget*> adjustable;
-
- // find the 'free' space, and how many children will be using it
- for (it = visible.begin(), end = visible.end(); it != end; ++it) {
- free -= (*it)->minSize().width();
- if (free < 0) free = 0;
- if ((*it)->maxSize().width() - (*it)->minSize().width() > 0)
- adjustable.push_back(*it);
- }
- // some widgets may have max widths that restrict them, find the 'true'
- // amount of free space after these widgets are not included
- if (!adjustable.empty()) {
- do {
- each = free / adjustable.size();
- for (it = adjustable.begin(), end = adjustable.end(); it != end;) {
- std::list<Widget*>::iterator next = it; ++next;
- int m = (*it)->maxSize().width() - (*it)->minSize().width();
- if (m > 0 && m < each) {
- free -= m;
- if (free < 0) free = 0;
- adjustable.erase(it);
- break; // if one is found to be fixed, then the free space needs to
- // change, and the rest need to be reexamined
- }
- it = next;
- }
- } while (it != end && !adjustable.empty());
- }
-
- // place/size the widgets
- if (!adjustable.empty())
- each = free / adjustable.size();
- else
- each = 0;
- for (it = visible.begin(), end = visible.end(); it != end; ++it) {
- int w;
- // is the widget adjustable?
- std::list<Widget*>::const_iterator
- found = std::find(adjustable.begin(), adjustable.end(), *it);
- if (found != adjustable.end()) {
- // adjustable
- w = (*it)->minSize().width() + each;
- } else {
- // fixed
- w = (*it)->minSize().width();
- }
- // align it vertically
- int yy = y;
- int hh = std::max(std::min(h, (*it)->_max_size.height()),
- (*it)->_min_size.height());
- if (hh < h) {
- switch(_alignment) {
- case RenderStyle::RightBottomJustify:
- yy += h - hh;
- break;
- case RenderStyle::CenterJustify:
- yy += (h - hh) / 2;
- break;
- case RenderStyle::LeftTopJustify:
- break;
- }
- }
- (*it)->internal_moveresize(x, yy, w, hh);
- (*it)->render();
- (*it)->layout();
- x += w + _bevel;
- }
-}
-
-void Widget::layoutVert()
-{
- std::list<Widget*>::iterator it, end;
-
- // work with just the visible children
- std::list<Widget*> visible;
- for (it = _children.begin(), end = _children.end(); it != end; ++it)
- if ((*it)->visible())
- visible.push_back(*it);
-
- if (visible.empty()) return;
-
- int x, y, w, h; // working area
- x = y = _bevel;
- w = _area.width() - _borderwidth * 2 - _bevel * 2;
- h = _area.height() - _borderwidth * 2 - _bevel * 2;
- if (w < 0 || h < 0) return; // not worth laying anything out!
-
- int free = h - (visible.size() - 1) * _bevel;
- if (free < 0) free = 0;
- int each;
-
- std::list<Widget*> adjustable;
-
- // find the 'free' space, and how many children will be using it
- for (it = visible.begin(), end = visible.end(); it != end; ++it) {
- free -= (*it)->minSize().height();
- if (free < 0) free = 0;
- if ((*it)->maxSize().height() - (*it)->minSize().height() > 0)
- adjustable.push_back(*it);
- }
- // some widgets may have max heights that restrict them, find the 'true'
- // amount of free space after these widgets are not included
- if (!adjustable.empty()) {
- do {
- each = free / adjustable.size();
- for (it = adjustable.begin(), end = adjustable.end(); it != end;) {
- std::list<Widget*>::iterator next = it; ++next;
- int m = (*it)->maxSize().height() - (*it)->minSize().height();
- if (m > 0 && m < each) {
- free -= m;
- if (free < 0) free = 0;
- adjustable.erase(it);
- break; // if one is found to be fixed, then the free space needs to
- // change, and the rest need to be reexamined
- }
- it = next;
- }
- } while (it != end && !adjustable.empty());
- }
-
- // place/size the widgets
- if (!adjustable.empty())
- each = free / adjustable.size();
- else
- each = 0;
- for (it = visible.begin(), end = visible.end(); it != end; ++it) {
- int h;
- // is the widget adjustable?
- std::list<Widget*>::const_iterator
- found = std::find(adjustable.begin(), adjustable.end(), *it);
- if (found != adjustable.end()) {
- // adjustable
- h = (*it)->minSize().height() + each;
- } else {
- // fixed
- h = (*it)->minSize().height();
- }
- // align it horizontally
- int xx = x;
- int ww = std::max(std::min(w, (*it)->_max_size.width()),
- (*it)->_min_size.width());
- if (ww < w) {
- switch(_alignment) {
- case RenderStyle::RightBottomJustify:
- xx += w - ww;
- break;
- case RenderStyle::CenterJustify:
- xx += (w - ww) / 2;
- break;
- case RenderStyle::LeftTopJustify:
- break;
- }
- }
- (*it)->internal_moveresize(xx, y, ww, h);
- (*it)->render();
- (*it)->layout();
- y += h + _bevel;
- }
-}
-
-void Widget::render()
-{
- if (!_dirty) return;
- if (!_texture) {
- // set a solid color as the default background
- XSetWindowBackground(**display, _window,
- RenderStyle::style(_screen)->
- titlebarUnfocusBackground()->color().pixel());
- return;
- }
- if (_borderwidth * 2 > _area.width() ||
- _borderwidth * 2 > _area.height())
- return; // no surface to draw on
-
- Surface *s = new Surface(_screen, Size(_area.width() - _borderwidth * 2,
- _area.height() - _borderwidth * 2));
- display->renderControl(_screen)->drawBackground(*s, *_texture);
-
- renderForeground(*s); // for inherited types to render onto the _surface
-
- XSetWindowBackgroundPixmap(**display, _window, s->pixmap());
- XClearWindow(**display, _window);
-
- // delete the old surface *after* its pixmap isn't in use anymore
- if (_surface) delete _surface;
-
- s->freePixelData(); // done rendering with this surface
- _surface = s;
-
- _dirty = false;
-}
-
-void Widget::renderChildren()
-{
- std::list<Widget*>::iterator it, end = _children.end();
- for (it = _children.begin(); it != end; ++it)
- (*it)->render();
-}
-
-void Widget::styleChanged(const RenderStyle &)
-{
- refresh();
-}
-
-void Widget::exposeHandler(const XExposeEvent &e)
-{
- EventHandler::exposeHandler(e);
- XClearArea(**display, _window, e.x, e.y, e.width, e.height, false);
-}
-
-void Widget::configureHandler(const XConfigureEvent &e)
-{
- if (_ignore_config) {
- _ignore_config--;
- } else {
- // only interested in these for top level windows
- if (_parent) return;
-
- XEvent ev;
- ev.xconfigure.width = e.width;
- ev.xconfigure.height = e.height;
- while (XCheckTypedWindowEvent(**display, window(), ConfigureNotify, &ev));
-
- if (!(ev.xconfigure.width == area().width() &&
- ev.xconfigure.height == area().height())) {
- _area = Rect(_area.position(), Size(e.width, e.height));
- update();
- }
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __widget_hh
-#define __widget_hh
-
-#include "eventhandler.hh"
-#include "rect.hh"
-#include "renderstyle.hh"
-
-#include <list>
-#include <algorithm>
-#include <cassert>
-
-namespace otk {
-
-class Surface;
-class RenderTexture;
-class RenderColor;
-class EventDispatcher;
-
-class Widget : public EventHandler, public StyleNotify {
-public:
- enum Direction { Horizontal, Vertical };
-
- Widget(int screen, EventDispatcher *ed, Direction direction = Horizontal,
- int bevel = 3, bool overrideredir = false);
- Widget(Widget *parent, Direction direction = Horizontal, int bevel = 3);
- virtual ~Widget();
-
- inline int screen() const { return _screen; }
- inline Window window() const { return _window; }
- inline Widget *parent() const { return _parent; }
- inline Direction direction() const { return _direction; }
-
- inline RenderStyle::Justify alignment() const { return _alignment; }
- void setAlignment(RenderStyle::Justify a);
-
- inline long eventMask() const { return _event_mask; }
- virtual void setEventMask(long e);
-
- inline const Rect& area() const { return _area; }
- inline Rect usableArea() const { return Rect(_area.position(),
- Size(_area.width() -
- _borderwidth * 2,
- _area.height() -
- _borderwidth * 2));}
- inline const Size& minSize() const { return _min_size; }
- inline const Size& maxSize() const { return _max_size; }
- virtual void setMaxSize(const Size &s);
-
- virtual void show(bool children = false);
- virtual void hide();
- inline bool visible() const { return _visible; }
-
- virtual void update();
- virtual void refresh() { if (_visible) { _dirty = true; render(); } }
-
- virtual void setBevel(int b);
- inline int bevel() const { return _bevel; }
-
- void move(const Point &p)
- { moveresize(Rect(p, _area.size())); }
- void resize(const Size &s)
- { moveresize(Rect(_area.position(), s)); }
- /*!
- When a widget has a parent, this won't change the widget directly, but will
- just cause the parent to re-layout all its children.
- */
- virtual void moveresize(const Rect &r);
-
- inline const RenderColor *borderColor() const { return _bordercolor; }
- virtual void setBorderColor(const RenderColor *c);
-
- inline int borderWidth() const { return _borderwidth; }
- virtual void setBorderWidth(int w);
-
- const std::list<Widget*>& children() const { return _children; }
-
- virtual void exposeHandler(const XExposeEvent &e);
- virtual void configureHandler(const XConfigureEvent &e);
- virtual void styleChanged(const RenderStyle &style);
-
-protected:
- virtual void addChild(Widget *w) { assert(w); _children.push_back(w); }
- virtual void removeChild(Widget *w) { assert(w); _children.remove(w); }
-
- //! Find the default min/max sizes for the widget. Useful after the in-use
- //! style has changed.
- virtual void calcDefaultSizes();
-
- virtual void setMinSize(const Size &s);
-
- //! Arrange the widget's children
- virtual void layout();
- virtual void layoutHorz();
- virtual void layoutVert();
- virtual void render();
- virtual void renderForeground(Surface&) {};
- virtual void renderChildren();
-
- void createWindow(bool overrideredir);
-
- RenderTexture *_texture;
-
- EventDispatcher *dispatcher() const { return _dispatcher; }
-
-private:
- void internal_moveresize(int x, int y, int w, int h);
-
- int _screen;
- Widget *_parent;
- Window _window;
- Surface *_surface;
- long _event_mask;
-
- RenderStyle::Justify _alignment;
- Direction _direction;
- Rect _area;
- //! This size is the size *inside* the border, so they won't match the
- //! actual size of the widget
- Size _min_size;
- //! This size is the size *inside* the border, so they won't match the
- //! actual size of the widget
- Size _max_size;
-
- bool _visible;
-
- const RenderColor *_bordercolor;
- int _borderwidth;
- int _bevel;
- bool _dirty;
-
- std::list<Widget*> _children;
-
- EventDispatcher *_dispatcher;
-
- int _ignore_config;
-};
-
-}
-
-#endif // __widget_hh
+++ /dev/null
-Makefile
-Makefile.in
+++ /dev/null
-scriptdir=$(libdir)/openbox/python
-
-SUBDIRS =
-
-script_PYTHON = rc.py keymap.py buttonmap.py config.py motion.py \
- historyplacement.py windowplacement.py stackedcycle.py focus.py
-
-MAINTAINERCLEANFILES= Makefile.in
-
-distclean-local:
- $(RM) *\~ *.orig *.rej .\#*
+++ /dev/null
-from input import Pointer
-
-def set(map):
- """Set your buttonmap. Functions in the button map should all take a single
- argument, a Client object, except for functions for Action_Motion events,
- who should take 2 arguments, a PointerData object and a Client object."""
- global _press_map, _release_map, _click_map, _doubleclick_map, _motion_map
- Pointer.clearBinds()
- _press_map = []
- _release_map = []
- _click_map = []
- _doubleclick_map = []
- _motion_map = []
- for button, context, action, func in map:
- if (action == Pointer.Action_Press):
- _press_map.append((button, context, func))
- mapfunc = press_run
- if (action == Pointer.Action_Release):
- _release_map.append((button, context, func))
- mapfunc = release_run
- if (action == Pointer.Action_Click):
- _click_map.append((button, context, func))
- mapfunc = click_run
- if (action == Pointer.Action_DoubleClick):
- _doubleclick_map.append((button, context, func))
- mapfunc = doubleclick_run
- if (action == Pointer.Action_Motion):
- _motion_map.append((button, context, func))
- mapfunc = motion_run
- Pointer.bind(button, context, action, mapfunc)
-
-def press_run(ptrdata, client):
- """Run a button press event through the buttonmap"""
- button = ptrdata.button
- context = ptrdata.context
- for but, cont, func in _press_map:
- if (but == button and cont == context):
- func(client)
-
-def release_run(ptrdata, client):
- """Run a button release event through the buttonmap"""
- button = ptrdata.button
- context = ptrdata.context
- for but, cont, func in _release_map:
- if (but == button and cont == context):
- func(client)
-
-def click_run(ptrdata, client):
- """Run a button click event through the buttonmap"""
- button = ptrdata.button
- context = ptrdata.context
- for but, cont, func in _click_map:
- if (but == button and cont == context):
- func(client)
-
-def doubleclick_run(ptrdata, client):
- """Run a button doubleclick event through the buttonmap"""
- button = ptrdata.button
- context = ptrdata.context
- for but, cont, func in _doubleclick_map:
- if (but == button and cont == context):
- func(client)
-
-def motion_run(ptrdata, client):
- """Run a pointer motion event through the buttonmap"""
- button = ptrdata.button
- context = ptrdata.context
- for but, cont, func in _motion_map:
- if (but == button and cont == context):
- func(ptrdata, client)
-
-_press_map = ()
-_release_map = ()
-_click_map = ()
-_doubleclick_map = ()
-_motion_map = ()
+++ /dev/null
-# Openbox's config system. Please use the defined functions instead of
-# accessing the internal data structures directly, for the sake of us all.
-
-def add(modulename, name, friendlyname, description, type, default,
- **keywords):
- """Add a variable to the configuration system.
-
- Add a variable to the configuration system for a module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- friendlyname - The user-friendly name of the variable, e.g. 'My Variable'
- description - The detailed destription of the variable, e.g. 'Does Things'
- type - The type of the variable, one of:
- - 'boolean'
- - 'enum'
- - 'integer'
- - 'string'
- - 'file'
- - 'function'
- - 'object'
- default - The default value for the variable, e.g. 300
- keywords - Extra keyword=value pairs to further define the variable. These
- can be:
- - For 'enum' types:
- - options : A list of possible options for the variable.
- This *must* be set for all enum variables.
- - For 'integer' types:
- - min : The minimum value for the variable.
- - max : The maximum value for the variable.
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- friendlyname = str(friendlyname)
- description = str(description)
- type = str(type).lower()
-
- # make sure the sub-dicts exist
- try:
- _settings[modulename]
- try:
- _settings[modulename][name]
- except KeyError:
- _settings[modulename][name] = {}
- except KeyError:
- _settings[modulename] = {}
- _settings[modulename][name] = {}
-
- # add the keywords first as they are used for the tests in set()
- for key,value in zip(keywords.keys(), keywords.values()):
- _settings[modulename][name][key] = value
-
- _settings[modulename][name]['name'] = friendlyname
- _settings[modulename][name]['description'] = description
- _settings[modulename][name]['type'] = type
- _settings[modulename][name]['default'] = default
-
- # put it through the tests
- try:
- set(modulename, name, default)
- except:
- del _settings[modulename][name]
- import sys
- raise sys.exc_info()[0], sys.exc_info()[1] # re-raise it
-
-def set(modulename, name, value):
- """Set a variable's value.
-
- Sets the value for a variable of the specified module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- value - The new value for the variable.
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
-
- # proper value checking for 'boolean's
- if _settings[modulename][name]['type'] == 'boolean':
- if not (value == 0 or value == 1):
- raise ValueError, 'Attempted to set ' + name + ' to a value of '+\
- str(value) + ' but boolean variables can only contain 0 or'+\
- ' 1.'
-
- # proper value checking for 'enum's
- elif _settings[modulename][name]['type'] == 'enum':
- options = _settings[modulename][name]['options']
- if not value in options:
- raise ValueError, 'Attempted to set ' + name + ' to a value of '+\
- str(value) + ' but this is not one of the possible values '+\
- 'for this enum variable. Possible values are: ' +\
- str(options) + "."
-
- # min/max checking for 'integer's
- elif _settings[modulename][name]['type'] == 'integer':
- try:
- min = _settings[modulename][name]['min']
- if value < min:
- raise ValueError, 'Attempted to set ' + name + ' to a value '+\
- ' of ' + str(value) + ' but it has a minimum value ' +\
- ' of ' + str(min) + '.'
- except KeyError: pass
- try:
- max = _settings[modulename][name]['max']
- if value > max:
- raise ValueError, 'Attempted to set ' + name + ' to a value '+\
- ' of ' + str(value) + ' but it has a maximum value ' +\
- ' of ' + str(min) + '.'
- except KeyError: pass
-
- _settings[modulename][name]['value'] = value
-
-def reset(modulename, name):
- """Reset a variable to its default value.
-
- Resets the value for a variable in the specified module back to its
- original (default) value.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- _settings[modulename][name]['value'] = \
- _settings[modulename][name]['default']
-
-def get(modulename, name):
- """Returns the value of a variable.
-
- Returns the current value for a variable in the specified module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my variable'
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- return _settings[modulename][name]['value']
-
-#---------------------------- Internals ---------------------------
-
-"""The main configuration dictionary, which holds sub-dictionaries for each
- module.
-
- The format for entries in here like this (for a string):
- _settings['modulename']['varname']['name'] = 'Text Label'
- _settings['modulename']['varname']['description'] = 'Does this'
- _settings['modulename']['varname']['type'] = 'string'
- _settings['modulename']['varname']['default'] = 'Foo'
- _settings['modulename']['varname']['value'] = 'Foo'
- # 'value' should always be initialized to the same
- # value as the 'default' field!
-
- Here's an example of an enum:
- _settings['modulename']['varname']['name'] = 'My Enum Variable'
- _settings['modulename']['varname']['description'] = 'Does Enum-like things.'
- _settings['modulename']['varname']['type'] = 'enum'
- _settings['modulename']['varname']['default'] = \
- _settings['modulename']['varname']['value'] = [ 'Blue', 'Green', 'Pink' ]
-
- And Here's an example of an integer with bounds:
- _settings['modulename']['varname']['name'] = 'A Bounded Integer'
- _settings['modulename']['varname']['description'] = 'A fierce party animal!'
- _settings['modulename']['varname']['type'] = 'integer'
- _settings['modulename']['varname']['default'] = \
- _settings['modulename']['varname']['value'] = 0
- _settings['modulename']['varname']['min'] = 0
- _settings['modulename']['varname']['max'] = 49
-
- Hopefully you get the idea.
- """
-_settings = {}
-
-"""Valid values for a variable's type."""
-_types = [ 'boolean', # Boolean types can only hold a value of 0 or 1.
-
- 'enum', # Enum types hold a value from a list of possible values.
- # An 'options' field *must* be provided for enums,
- # containing a list of possible values for the variable.
-
- 'integer', # Integer types hold a single number, as well as a 'min'
- # and 'max' property.
- # If the 'min' or 'max' is ignore then bounds checking
- # will not be performed in that direction.
-
- 'string', # String types hold a text string.
-
- 'file', # File types hold a file object.
-
- 'function',# Function types hold any callable object.
-
- 'object' # Object types can hold any python object.
- ];
-
-print "Loaded config.py"
+++ /dev/null
-###########################################################################
-### Functions for helping out with your window focus. ###
-###########################################################################
-
-import config, ob, hooks
-
-export_functions = ()
-
-config.add('focus',
- 'avoid_skip_taskbar',
- 'Avoid SkipTaskbar Windows',
- "Don't focus windows which have requested to not be displayed " + \
- "in taskbars. You will still be able to focus the windows, but " + \
- "not through cycling, and they won't be focused as a fallback " + \
- "if 'Focus Fallback' is enabled.",
- 'boolean',
- 1)
-
-config.add('focus',
- 'fallback',
- 'Focus Fallback',
- "Send focus somewhere when nothing is left with the focus, if " + \
- "possible.",
- 'boolean',
- 1)
-
-# maintain a list of clients, stacked in focus order
-_clients = []
-_skip = 0
-
-def focusable(client, desktop):
- if not client.normal(): return False
- if not (client.canFocus() or client.focusNotify()): return False
- if client.iconic(): return False
- if config.get('focus', 'avoid_skip_taskbar') and \
- client.skipTaskbar(): return False
-
- desk = client.desktop()
- if not (desk == 0xffffffff or desk == desktop): return False
-
- return True
-
-def _focused(client):
- global _clients, _skip
-
- if _skip:
- _skip -= 1
- return
-
- if client:
- # move it to the top
- _clients.remove(client)
- _clients.insert(0, client)
- elif config.get('focus', 'fallback'):
- # pass around focus
- desktop = ob.Openbox.desktop()
- for c in _clients:
- if focusable(c, desktop):
- c.focus()
- break
-
-hooks.managed.append(lambda c: _clients.append(c))
-hooks.closed.append(lambda c: _clients.remove(c))
-hooks.focused.append(_focused)
-
-print "Loaded focus.py"
+++ /dev/null
-##############################################################################
-### The history window placement algorithm. ebind historyplacement.place ###
-### to the ob.EventAction.PlaceWindow event to use it. ###
-##############################################################################
-
-import windowplacement, config, hooks
-
-def place(data):
- """Place a window usingthe history placement algorithm."""
- _place(data)
-
-export_functions = place
-
-##############################################################################
-
-config.add('historyplacement',
- 'ignore_requested_positions',
- 'Ignore Requested Positions',
- "When true, the placement algorithm will attempt to place " + \
- "windows even when they request a position (like XMMS can)." + \
- "Note this only applies to 'normal' windows, not to special " + \
- "cases like desktops and docks.",
- 'boolean',
- 0)
-config.add('historyplacement',
- 'dont_duplicate',
- "Don't Diplicate",
- "When true, if 2 copies of the same match in history are to be " + \
- "placed before one of them is closed (so it would be placed " + \
- "over-top of the last one), this will cause the second window to "+\
- "not be placed via history, and the 'Fallback Algorithm' will be "+\
- "used instead.",
- 'boolean',
- 1)
-config.add('historyplacement',
- 'filename',
- 'History Database Filename',
- "The name of the file where history data will be stored. The " + \
- "number of the screen is appended onto this name. The file will " +\
- "be placed in ~/.openbox/.",
- 'string',
- 'historydb')
-config.add('historyplacement',
- 'fallback',
- 'Fallback Algorithm',
- "The window placement algorithm that will be used when history " + \
- "placement does not have a place for the window.",
- 'enum',
- windowplacement.random,
- options = windowplacement.export_functions)
-
-###########################################################################
-
-###########################################################################
-### Internal stuff, should not be accessed outside the module. ###
-###########################################################################
-
-import ob, os, string
-
-_data = []
-
-class _State:
- def __init__(self, resname, resclass, role, x, y):
- self.resname = resname
- self.resclass = resclass
- self.role = role
- self.x = x
- self.y = y
- self.placed = 0
- def __eq__(self, other):
- if self.resname == other.resname and \
- self.resclass == other.resclass and \
- self.role == other.role:
- return 1
- return 0
-
-def _load():
- global _data
- try:
- file = open(os.environ['HOME'] + '/.openbox/' + \
- config.get('historyplacement', 'filename') + \
- "." + str(ob.Openbox.screenNumber()), 'r')
- # read data
- for line in file.readlines():
- line = line[:-1] # drop the '\n'
- try:
- s = string.split(line, '\0')
- state = _State(s[0], s[1], s[2],
- int(s[3]), int(s[4]))
-
- _data.append(state)
-
- except ValueError: pass
- except IndexError: pass
- file.close()
- except IOError: pass
-
-def _save():
- file = open(os.environ['HOME'] + '/.openbox/'+ \
- config.get('historyplacement', 'filename') + \
- "." + str(ob.Openbox.screenNumber()), 'w')
- if file:
- for i in _data:
- file.write(i.resname + '\0' +
- i.resclass + '\0' +
- i.role + '\0' +
- str(i.x) + '\0' +
- str(i.y) + '\n')
- file.close()
-
-def _create_state(client):
- area = client.area()
- return _State(client.resName(), client.resClass(),
- client.role(), area[0], area[1])
-
-def _place(client):
- state = _create_state(client)
- try:
- print "looking for : " + state.resname + " : " + \
- state.resclass + " : " + state.role
- try:
- i = _data.index(state)
- except ValueError:
- print "No match in history"
- else:
- coords = _data[i] # get the equal element
- print "Found in history ("+str(coords.x)+","+\
- str(coords.y)+")"
- if not (config.get('historyplacement', 'dont_duplicate') \
- and coords.placed):
- coords.placed = 1
- if ob.Openbox.state() != ob.State.Starting:
-# if not (config.get('historyplacement', 'ignore_requested_positions') \
-# and data.client.normal()):
-# if data.client.positionRequested(): return
- ca = client.area()
- client.setArea((coords.x, coords.y, ca[2], ca[3]))
- return
- else:
- print "Already placed another window there"
- except TypeError:
- pass
- fallback = config.get('historyplacement', 'fallback')
- if fallback: fallback(client)
-
-def _save_window(client):
- global _data
- state = _create_state(client)
- print "looking for : " + state.resname + " : " + state.resclass + \
- " : " + state.role
-
- try:
- print "replacing"
- i = _data.index(state)
- _data[i] = state # replace it
- except ValueError:
- print "appending"
- _data.append(state)
-
-hooks.startup.append(_load)
-hooks.shutdown.append(_save)
-hooks.closed.append(_save_window)
-
-print "Loaded historyplacement.py"
+++ /dev/null
-from input import Keyboard
-
-def set(map):
- """Set your keymap"""
- global _map
- Keyboard.clearBinds()
- for key, func in map:
- Keyboard.bind(key, run)
- _map = map
-
-def run(keydata, client):
- """Run a key press event through the keymap"""
- for key, func in _map:
- if (keydata.keychain == key):
- func(keydata, client)
-
-_map = ()
+++ /dev/null
-import config, hooks, ob
-from input import Pointer
-
-config.add('motion',
- 'edge_resistance',
- 'Edge Resistance',
- "The amount of resistance to provide to moving a window past a " + \
- "screen boundary. Specify a value of 0 to disable edge resistance.",
- 'integer',
- 10,
- min = 0)
-
-def move(ptrdata, client):
- def mymove(ptrdata, client):
- global _moving, _last_pos
- if ptrdata.action == Pointer.Action_Release:
- _moveclient.setArea(_moveclient.area(), True) # finalize the move
- _moving = False
- Pointer.ungrab()
- elif ptrdata.action == Pointer.Action_Motion:
- pos = ptrdata.pos
-
- x = _pcarea[0] + pos[0] - _presspos[0]
- y = _pcarea[1] + pos[1] - _presspos[1]
-
- resist = config.get('motion', 'edge_resistance')
- if resist:
- ca = _moveclient.area()
- w, h = ca[2], ca[3]
- # use the area based on the struts
- sa = ob.Openbox.screenArea(_moveclient.desktop())
- l, t = sa[0], sa[1]
- r = l+ sa[2] - w
- b = t+ sa[3] - h
- # left screen edge
- if _last_pos[0] >= pos[0] and x < l and x >= l - resist:
- x = l
- # right screen edge
- if _last_pos[0] <= pos[0] and x > r and x <= r + resist:
- x = r
- # top screen edge
- if _last_pos[1] >= pos[1] and y < t and y >= t - resist:
- y = t
- # right screen edge
- if _last_pos[1] <= pos[1] and y > b and y <= b + resist:
- y = b
-
- _moveclient.setArea((x, y, _pcarea[2], _pcarea[3]), False)
- _last_pos = pos
-
- global _last_pos, _moving, _pcarea, _presspos, _moveclient
- if not _moving:
- _moving = True
- _pcarea = ptrdata.pressclientarea
- _presspos = ptrdata.presspos
- _last_pos = _presspos
- _moveclient = client
- Pointer.grab(mymove)
- mymove(ptrdata, client)
-
-def resize(ptrdata, client):
- x, y = ptrdata.pos
- px, py = ptrdata.presspos
- cx, cy, cw, ch = ptrdata.pressclientarea
- dx = x - px
- dy = y - py
- if px < cx + cw / 2: # left side
- dx *= -1
- cx -= dx
- if py < cy + ch / 2: # top side
- dy *= -1
- cy -= dy
- cw += dx
- ch += dy
- client.setArea((cx, cy, cw, ch))
-
-_moving = False
-_moveclient = 0
-_last_pos = ()
-_pcarea = ()
-_presspos = ()
+++ /dev/null
-import hooks, ob, keymap, buttonmap, os, sys, input, motion, historyplacement
-import stackedcycle
-from input import Pointer
-
-hooks.managed.append(historyplacement.place)
-#import windowplacement
-#hooks.managed.append(windowplacement.random)
-
-_grab = 0
-def printshit(keydata, client):
- global _grab
- print "shit"
- _grab = not _grab
- print _grab
- def gfunc(data, client=None): pass
- if _grab:
- input.Keyboard.grab(gfunc)
- input.Pointer.grab(gfunc)
- else:
- input.Keyboard.ungrab()
- input.Pointer.ungrab()
-
-def myexec(prog):
- print "execing: ", prog
- if (os.fork() == 0):
- try:
- os.setsid()
- os.execl("/bin/sh", "/bin/sh", "-c", prog)
- except:
- print str(sys.exc_info()[0]) + ": " + str(sys.exc_info()[1])
- try:
- print "failed to execute '" + prog + "'"
- except:
- print str(sys.exc_info()[0]) + ": " + str(sys.exc_info()[1])
- os._exit(0)
-
-def myactivate(c):
- if ob.Openbox.showingDesktop():
- ob.Openbox.setShowingDesktop(False)
- if c.iconic():
- c.setIconic(False)
- elif not c.visible():
- # if its not visible for other reasons, then don't mess with it
- return
- if c.shaded():
- c.setShaded(False)
- c.focus()
- c.raiseWindow()
-
-hooks.requestactivate.append(myactivate)
-
-def myfocus(c):
- if c and c.normal(): c.focus()
-
-#hooks.showwindow.append(myfocus)
-hooks.pointerenter.append(myfocus)
-
-hooks.visible.append(myfocus)
-
-mykmap=((("C-a", "d"), printshit),
- (("C-Tab",), stackedcycle.next),
- (("C-S-Tab",), stackedcycle.previous),
- (("Mod1-1",), lambda k,c: ob.Openbox.setDesktop(1)),
- (("Mod1-2",), lambda k,c: ob.Openbox.setDesktop(2)),
- (("Mod1-3",), lambda k,c: ob.Openbox.setDesktop(3)),
- (("Mod1-4",), lambda k,c: ob.Openbox.setDesktop(4)),
- (("Mod1-C-Left",), lambda k,c: ob.Openbox.setPreviousDesktop() or c.setDesktop(ob.Openbox.desktop())),
- (("Mod1-C-Right",), lambda k,c: ob.Openbox.setNextDesktop() or c.setDesktop(ob.Openbox.desktop())),
- (("Mod1-Left",), lambda k,c: ob.Openbox.setPreviousDesktop()),
- (("Mod1-Right",), lambda k,c: ob.Openbox.setNextDesktop()),
- (("C-space",), lambda k,c: myexec("xterm")))
-keymap.set(mykmap)
-
-def mytogglesticky(client):
- if client.desktop() == 0xffffffff: d = ob.Openbox.desktop()
- else: d = 0xffffffff
- client.setDesktop(d)
-
-mybmap=(("1", "maximize", Pointer.Action_Click,
- lambda c: c.setMaximized(not c.maximized())),
- ("2", "maximize", Pointer.Action_Click,
- lambda c: c.setMaximizedVert(not c.maximizedVert())),
- ("3", "maximize", Pointer.Action_Click,
- lambda c: c.setMaximizedHorz(not c.maximizedHorz())),
- ("1", "alldesktops", Pointer.Action_Click, mytogglesticky),
- ("1", "iconify", Pointer.Action_Click,
- lambda c: c.setIconic(True)),
- ("1", "icon", Pointer.Action_DoubleClick, ob.Client.close),
- ("1", "close", Pointer.Action_Click, ob.Client.close),
- ("1", "titlebar", Pointer.Action_Motion, motion.move),
- ("1", "handle", Pointer.Action_Motion, motion.move),
- ("Mod1-1", "frame", Pointer.Action_Click, ob.Client.raiseWindow),
- ("Mod1-1", "frame", Pointer.Action_Motion, motion.move),
- ("1", "titlebar", Pointer.Action_Press, ob.Client.raiseWindow),
- ("1", "handle", Pointer.Action_Press, ob.Client.raiseWindow),
- ("1", "client", Pointer.Action_Press, ob.Client.raiseWindow),
- ("2", "titlebar", Pointer.Action_Press, ob.Client.lowerWindow),
- ("2", "handle", Pointer.Action_Press, ob.Client.lowerWindow),
- ("Mod1-3", "frame", Pointer.Action_Click, ob.Client.lowerWindow),
- ("Mod1-3", "frame", Pointer.Action_Motion, motion.resize),
- ("1", "blcorner", Pointer.Action_Motion, motion.resize),
- ("1", "brcorner", Pointer.Action_Motion, motion.resize),
- ("1", "titlebar", Pointer.Action_Press, ob.Client.focus),
- ("1", "handle", Pointer.Action_Press, ob.Client.focus),
- ("1", "client", Pointer.Action_Press, ob.Client.focus),
- ("1", "titlebar", Pointer.Action_DoubleClick,
- lambda c: c.setShaded(not c.shaded())),
- ("4", "titlebar", Pointer.Action_Click,
- lambda c: c.setShaded(True)),
- ("5", "titlebar", Pointer.Action_Click,
- lambda c: c.setShaded(False)),
- ("4", "root", Pointer.Action_Click,
- lambda c: ob.Openbox.setNextDesktop()),
- ("5", "root", Pointer.Action_Click,
- lambda c: ob.Openbox.setPreviousDesktop()),
- ("Mod1-4", "frame", Pointer.Action_Click,
- lambda c: ob.Openbox.setNextDesktop()),
- ("Mod1-5", "frame", Pointer.Action_Click,
- lambda c: ob.Openbox.setPreviousDesktop()),
- ("Mod1-4", "root", Pointer.Action_Click,
- lambda c: ob.Openbox.setNextDesktop()),
- ("Mod1-5", "root", Pointer.Action_Click,
- lambda c: ob.Openbox.setPreviousDesktop()))
-buttonmap.set(mybmap)
+++ /dev/null
-import ob, config, hooks, focus
-from input import Pointer, Keyboard
-
-config.add('stackedcycle',
- 'activate_while_cycling',
- 'Activate While Cycling',
- "If this is True then windows will be activated as they are" + \
- "highlighted in the cycling list (except iconified windows).",
- 'boolean',
- True)
-
-config.add('stackedcycle',
- 'raise_window',
- 'Raise After Cycling',
- "If this is True, the selected window will be raised as well as " +\
- "focused.",
- 'boolean',
- True)
-
-config.add('stackedcycle',
- 'include_all_desktops',
- 'Include Windows From All Desktops',
- "If this is True then windows from all desktops will be included" +\
- " in the stacking list.",
- 'boolean',
- False)
-
-config.add('stackedcycle',
- 'include_icons',
- 'Include Icons',
- "If this is True then windows which are iconified on the current" +\
- " desktop will be included in the stacking list.",
- 'boolean',
- False)
-
-config.add('stackedcycle',
- 'include_icons_all_desktops',
- 'Include Icons From All Desktops',
- "If this is True then windows which are iconified from all " +\
- "desktops will be included in the stacking list (if Include Icons"+\
- " is also True).",
- 'boolean',
- True)
-
-config.add('stackedcycle',
- 'include_omnipresent',
- 'Include Omnipresent Windows',
- "If this is True then windows which are on all-desktops at once " +\
- "will be included in the stacking list.",
- 'boolean',
- True)
-
-def next(keydata, client): _cycle(keydata, client, True)
-def previous(keydata, client): _cycle(keydata, client, False)
-
-def _shouldAdd(client):
- """Determines if a client should be added to the cycling list."""
- curdesk = ob.Openbox.desktop()
- desk = client.desktop()
-
- if not (client.normal() and client.canFocus()): return False
- if config.get('focus', 'avoid_skip_taskbar') and client.skipTaskbar():
- return False
-
- if client.iconic():
- if config.get('stackedcycle', 'include_icons'):
- if config.get('stackedcycle', 'include_icons_all_desktops'):
- return True
- if desk == curdesk: return True
- return False
- if config.get('stackedcycle', 'include_omnipresent') and \
- desk == 0xffffffff: return True
- if config.get('stackedcycle', 'include_all_desktops'): return True
- if desk == curdesk: return True
-
- return False
-
-def _populateItems():
- global _items
- # get the list of clients, keeping iconic windows at the bottom
- _items = []
- iconic_clients = []
- for c in focus._clients:
- if _shouldAdd(c):
- if c.iconic(): iconic_clients.append(c)
- else: _items.append(c)
- _items.extend(iconic_clients)
-
-def _populate():
- global _pos, _items
- try:
- current = _items[_pos]
- except IndexError:
- current = None
- oldpos = _pos
- _pos = -1
-
- _populateItems()
-
- i = 0
- for item in _items:
- # current item might have shifted after a populateItems()
- # call, so we need to do this test.
- if current == item:
- _pos = i
- i += 1
-
- # The item we were on might be gone entirely
- if _pos < 0:
- # try stay at the same spot in the menu
- if oldpos >= len(_items):
- _pos = len(_items) - 1
- else:
- _pos = oldpos
-
-
-def _activate(final):
- """
- Activates (focuses and, if the user requested it, raises a window).
- If final is True, then this is the very last window we're activating
- and the user has finished cycling.
- """
- print "_activate"
- try:
- client = _items[_pos]
- except IndexError: return # empty list
- print client
-
- # move the to client's desktop if required
- if not (client.iconic() or client.desktop() == 0xffffffff or \
- client.desktop() == ob.Openbox.desktop()):
- ob.Openbox.setDesktop(client.desktop())
-
- if final or not client.iconic():
- if final: r = config.get('stackedcycle', 'raise_window')
- else: r = False
- client.focus(True)
- if final and client.shaded(): client.setShaded(False)
- print "final", final, "raising", r
- if r: client.raiseWindow()
- if not final:
- focus._skip += 1
-
-def _cycle(keydata, client, forward):
- global _cycling, _state, _pos, _inititem, _items
-
- if not _cycling:
- _items = [] # so it doesnt try start partway through the list
- _populate()
-
- if not _items: return # don't bother doing anything
-
- Keyboard.grab(_grabfunc)
- # the pointer grab causes pointer events during the keyboard grab
- # to go away, which means we don't get enter notifies when the
- # popup disappears, screwing up the focus
- Pointer.grabPointer(True)
-
- _cycling = True
- _state = keydata.state
- _pos = 0
- _inititem = _items[_pos]
-
- if forward:
- _pos += 1
- else:
- _pos -= 1
- # wrap around
- if _pos < 0: _pos = len(_items) - 1
- elif _pos >= len(_items): _pos = 0
- if config.get('stackedcycle', 'activate_while_cycling'):
- _activate(False) # activate, but dont deiconify/unshade/raise
-
-def _grabfunc(keydata, client):
- global _cycling
-
- done = False
- notreverting = True
- # have all the modifiers this started with been released?
- if not _state & keydata.state:
- done = True
- elif keydata.press:
- # has Escape been pressed?
- if keydata.keychain == "Escape":
- done = True
- notreverting = False
- # revert
- try:
- _pos = _items.index(_inititem)
- except:
- _pos = -1
- # has Enter been pressed?
- elif keydata.keychain == "Return":
- done = True
-
- if done:
- # activate, and deiconify/unshade/raise
- _activate(notreverting)
- _cycling = False
- Keyboard.ungrab()
- Pointer.grabPointer(False)
-
-
-_cycling = False
-_pos = 0
-_inititem = None
-_items = []
-_state = 0
-
-def _newwin(data):
- if _cycling: _populate()
-def _closewin(data):
- if _cycling: _populate()
-
-hooks.managed.append(_newwin)
-hooks.closed.append(_closewin)
+++ /dev/null
-############################################################################
-### Window placement algorithms, choose one of these and ebind it to the ###
-### ob.EventAction.PlaceWindow event. ###
-### ###
-### Also see historyplacement.py for the history placement module which ###
-### provides an algorithm that can be used in place of, or alongside, ###
-### these. ###
-############################################################################
-
-import ob
-from random import Random
-
-def random(client):
- """Place windows randomly around the screen."""
- if ob.Openbox.state() == ob.State.Starting: return
- #if data.client.positionRequested(): return
- cx, cy, cw, ch = client.area()
- sx, sy, sw, sh = ob.Openbox.screenArea(client.desktop())
- xr = sw - cw - 1 # x range
- yr = sh - ch - 1 # y range
- if xr <= 0: x = 0
- else: x = Random().randrange(sx, xr)
- if yr <= 0: y = 0
- else: y = Random().randrange(sy, yr)
- client.setArea((x, y, cw, ch))
-
-def cascade(client):
- """Place windows in a cascading order from top-left to bottom-right."""
- if ob.Openbox.state() == ob.State.Starting: return
- #if data.client.positionRequested(): return
- cx, cy, cw, ch = client.area()
- sx, sy, sw, sh = ob.Openbox.screenArea(client.desktop())
- width = sw - cw
- height = sh - ch
- global _cascade_x, _cascade_y
- if _cascade_x < sx or _cascade_y < sy or \
- _cascade_x >= width or _cascade_y >= height:
- _cascade_x = sx
- _cascade_y = sy
- client.setArea((_cascade_x, _cascade_y, cw, ch))
- frame_size = client.frameSize()
- _cascade_x += frame_size[1]
- _cascade_y += frame_size[1]
-
-_cascade_x = 0
-_cascade_y = 0
-
-export_functions = random, cascade
-
-print "Loaded windowplacement.py"
+++ /dev/null
-Makefile
-Makefile.in
+++ /dev/null
-scriptdir = $(libdir)/openbox/python
-MAINTAINERCLEANFILES = Makefile.in
-script_PYTHON = config.py defaults.py focus.py callbacks.py \
- focusmodel.py windowplacement.py behavior.py motion.py \
- historyplacement.py cycle.py
-
-distclean-local:
- $(RM) *\~ .\#*
-uninstall-am:
- rmdir -p $(scriptdir)
+++ /dev/null
-###############################################################################
-### Functions for setting up some default behaviors. This includes the ###
-### default bindings for clicking on various parts of a window, the ###
-### titlebar buttons, and bindings for the scroll wheel on your mouse. ###
-###############################################################################
-
-import ob
-import callbacks
-import motion
-
-def setup_window_clicks():
- """Sets up the default bindings for various mouse buttons for various
- contexts.
- This includes:
- * Alt-left drag anywhere on a window will move it
- * Alt-right drag anywhere on a window will resize it
- * Left drag on a window's titlebar/handle will move it
- * Left drag on a window's handle grips will resize it
- * Alt-left press anywhere on a window's will raise it to the front of
- its stacking layer.
- * Left press on a window's titlebar/handle will raise it to the front
- of its stacking layer.
- * Alt-middle click anywhere on a window's will lower it to the bottom
- of its stacking layer.
- * Middle click on a window's titlebar/handle will lower it to the
- bottom of its stacking layer.
- * Double-left click on a window's titlebar will toggle shading it
- """
- ob.mbind("A-Left", ob.MouseContext.Frame,
- ob.MouseAction.Motion, motion.move)
- ob.mbind("A-Left", ob.MouseContext.Frame,
- ob.MouseAction.Release, motion.end_move)
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Motion, motion.move)
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Release, motion.end_move)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Motion, motion.move)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Release, motion.end_move)
-
- ob.mbind("A-Right", ob.MouseContext.Frame,
- ob.MouseAction.Motion, motion.resize)
- ob.mbind("A-Right", ob.MouseContext.Frame,
- ob.MouseAction.Release, motion.end_resize)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Motion, motion.resize)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Release, motion.end_resize)
-
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("A-Left", ob.MouseContext.Frame,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("A-Middle", ob.MouseContext.Frame,
- ob.MouseAction.Click, callbacks.lower_win)
- ob.mbind("Middle", ob.MouseContext.Titlebar,
- ob.MouseAction.Click, callbacks.lower_win)
- ob.mbind("Middle", ob.MouseContext.Handle,
- ob.MouseAction.Click, callbacks.lower_win)
-
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.DoubleClick, callbacks.toggle_shade)
-
-def setup_window_buttons():
- """Sets up the default behaviors for the buttons in the window titlebar."""
- ob.mbind("Left", ob.MouseContext.AllDesktopsButton,
- ob.MouseAction.Click, callbacks.toggle_all_desktops)
- ob.mbind("Left", ob.MouseContext.CloseButton,
- ob.MouseAction.Click, callbacks.close)
- ob.mbind("Left", ob.MouseContext.IconifyButton,
- ob.MouseAction.Click, callbacks.iconify)
- ob.mbind("Left", ob.MouseContext.MaximizeButton,
- ob.MouseAction.Click, callbacks.toggle_maximize)
- ob.mbind("Middle", ob.MouseContext.MaximizeButton,
- ob.MouseAction.Click, callbacks.toggle_maximize_vert)
- ob.mbind("Right", ob.MouseContext.MaximizeButton,
- ob.MouseAction.Click, callbacks.toggle_maximize_horz)
-
-def setup_scroll():
- """Sets up the default behaviors for the mouse scroll wheel.
- This includes:
- * scrolling on a window titlebar will shade/unshade it
- * alt-scrolling anywhere will switch to the next/previous desktop
- * control-alt-scrolling on a window will send it to the next/previous
- desktop, and switch to the desktop with the window
- """
- ob.mbind("Up", ob.MouseContext.Titlebar,
- ob.MouseAction.Click, callbacks.shade)
- ob.mbind("Down", ob.MouseContext.Titlebar,
- ob.MouseAction.Click, callbacks.unshade)
-
- ob.mbind("A-Up", ob.MouseContext.Frame,
- ob.MouseAction.Click, callbacks.next_desktop)
- ob.mbind("A-Up", ob.MouseContext.Root,
- ob.MouseAction.Click, callbacks.next_desktop)
- ob.mbind("Up", ob.MouseContext.Root,
- ob.MouseAction.Click, callbacks.next_desktop)
- ob.mbind("A-Down", ob.MouseContext.Frame,
- ob.MouseAction.Click, callbacks.prev_desktop)
- ob.mbind("A-Down", ob.MouseContext.Root,
- ob.MouseAction.Click, callbacks.prev_desktop)
- ob.mbind("Down", ob.MouseContext.Root,
- ob.MouseAction.Click, callbacks.prev_desktop)
-
- ob.mbind("C-A-Up", ob.MouseContext.Frame,
- ob.MouseAction.Click, callbacks.send_to_next_desktop)
- ob.mbind("C-A-Down", ob.MouseContext.Frame,
- ob.MouseAction.Click, callbacks.send_to_prev_desktop)
-
-export_functions = setup_window_clicks, setup_window_buttons, setup_scroll
-
-print "Loaded behavior.py"
+++ /dev/null
-############################################################################
-### Functions that can be used as callbacks for mouse/keyboard bindings ###
-############################################################################
-
-import ob
-import otk
-
-def iconify(data):
- """Iconifies the window on which the event occured"""
- if not data.client: return
- data.client.iconify(1)
-
-def restore(data):
- """Un-iconifies the window on which the event occured, but does not focus
- if. If you want to focus the window too, it is recommended that you
- use the activate() function."""
- if not data.client: return
- data.client.iconify(0)
-
-def close(data):
- """Closes the window on which the event occured"""
- if not data.client: return
- data.client.close()
-
-def focus(data):
- """Focuses the window on which the event occured"""
- if not data.client: return
- # !normal windows dont get focus from window enter events
- if data.action == ob.EventAction.EnterWindow and not data.client.normal():
- return
- data.client.focus()
-
-def raise_win(data):
- """Raises the window on which the event occured"""
- if not data.client: return
- data.client.raiseWindow()
-
-def lower_win(data):
- """Lowers the window on which the event occured"""
- if not data.client: return
- data.client.lowerWindow()
-
-def toggle_maximize(data):
- """Toggles the maximized status of the window on which the event occured"""
- if not data.client: return
- data.client.maximize(not (data.client.maxHorz() or data.client.maxVert()))
-
-def toggle_maximize_horz(data):
- """Toggles the horizontal maximized status of the window on which the event
- occured"""
- if not data.client: return
- data.client.maximizeHorizontal(not data.client.maxHorz())
-
-def toggle_maximize_vert(data):
- """Toggles the vertical maximized status of the window on which the event
- occured"""
- if not data.client: return
- data.client.maximizeVertical(not data.client.maxVert())
-
-def maximize(data):
- """Maximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximize(1)
-
-def maximize_horz(data):
- """Horizontally maximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximizeHorizontal(1)
-
-def maximize_vert(data):
- """Vertically maximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximizeVertical(1)
-
-def unmaximize(data):
- """Unmaximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximize(0)
-
-def unmaximize_horz(data):
- """Horizontally unmaximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximizeHorizontal(0)
-
-def unmaximize_vert(data):
- """Vertically unmaximizes the window on which the event occured"""
- if not data.client: return
- data.client.maximizeVertical(0)
-
-def toggle_shade(data):
- """Toggles the shade status of the window on which the event occured"""
- if not data.client: return
- data.client.shade(not data.client.shaded())
-
-def shade(data):
- """Shades the window on which the event occured"""
- if not data.client: return
- data.client.shade(1)
-
-def unshade(data):
- """Unshades the window on which the event occured"""
- if not data.client: return
- data.client.shade(0)
-
-def change_desktop(data, num):
- """Switches to a specified desktop"""
- ob.openbox.screen(data.screen).changeDesktop(num)
-
-def show_desktop(data, show=1):
- """Shows and focuses the desktop, hiding any client windows. Optionally,
- if show is zero, this will hide the desktop, leaving show-desktop
- mode."""
- ob.openbox.screen(data.screen).showDesktop(show)
-
-def hide_desktop(data):
- """Hides the desktop, re-showing the client windows. Leaves show-desktop
- mode."""
- show_desktop(data, 0)
-
-def toggle_show_desktop(data):
- """Requests the Openbox to show the desktop, hiding the client windows, or
- redisplay the clients."""
- screen = ob.openbox.screen(data.screen)
- screen.showDesktop(not screen.showingDesktop())
-
-def next_desktop(data, no_wrap=0):
- """Switches to the next desktop, optionally (by default) cycling around to
- the first when going past the last."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- if (d < (n-1)):
- d = d + 1
- elif not no_wrap:
- d = 0
- change_desktop(data, d)
-
-def prev_desktop(data, no_wrap=0):
- """Switches to the previous desktop, optionally (by default) cycling around
- to the last when going past the first."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- if (d > 0):
- d = d - 1
- elif not no_wrap:
- d = n - 1
- change_desktop(data, d)
-
-def up_desktop(data, num=1):
- """Switches to the desktop vertically above the current one. This is based
- on the desktop layout chosen by an EWMH compliant pager. Optionally, num
- can be specified to move more than one row at a time."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- l = screen.desktopLayout()
-
- target = d - num * l.columns
- if target < 0:
- target += l.rows * l.columns
- while target >= n:
- target -= l.columns
- change_desktop(data, target)
-
-def down_desktop(data, num=1):
- """Switches to the desktop vertically below the current one. This is based
- on the desktop layout chosen by an EWMH compliant pager. Optionally, num
- can be specified to move more than one row at a time."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- l = screen.desktopLayout()
-
- target = d + num * l.columns
- if target >= n:
- target -= l.rows * l.columns
- while target < 0:
- target += l.columns
- change_desktop(data, target)
-
-def left_desktop(data, num=1):
- """Switches to the desktop horizotally left of the current one. This is
- based on the desktop layout chosen by an EWMH compliant pager.
- Optionally, num can be specified to move more than one column at a
- time."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- l = screen.desktopLayout()
-
- rowstart = d - d % l.columns
- target = d - num
- while target < rowstart:
- target += l.columns
- change_desktop(data, target)
-
-def right_desktop(data, num=1):
- """Switches to the desktop horizotally right of the current one. This is
- based on the desktop layout chosen by an EWMH compliant pager.
- Optionally, num can be specified to move more than one column at a
- time."""
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- l = screen.desktopLayout()
-
- rowstart = d - d % l.columns
- target = d + num
- while target >= rowstart + l.columns:
- target -= l.columns
- change_desktop(data, target)
-
-def send_to_desktop(data, num):
- """Sends a client to a specified desktop"""
- if not data.client: return
- data.client.setDesktop(num)
-
-def toggle_all_desktops(data):
- """Toggles between sending a client to all desktops and to the current
- desktop."""
- if not data.client: return
- if not data.client.desktop() == 0xffffffff:
- send_to_desktop(data, 0xffffffff)
- else:
- send_to_desktop(data, ob.openbox.screen(data.screen).desktop())
-
-def send_to_all_desktops(data):
- """Sends a client to all desktops"""
- if not data.client: return
- send_to_desktop(data, 0xffffffff)
-
-def send_to_next_desktop(data, no_wrap=0, follow=1):
- """Sends a window to the next desktop, optionally (by default) cycling
- around to the first when going past the last. Also optionally moving to
- the new desktop after sending the window."""
- if not data.client: return
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- if (d < (n-1)):
- d = d + 1
- elif not no_wrap:
- d = 0
- send_to_desktop(data, d)
- if follow:
- change_desktop(data, d)
-
-def send_to_prev_desktop(data, no_wrap=0, follow=1):
- """Sends a window to the previous desktop, optionally (by default) cycling
- around to the last when going past the first. Also optionally moving to
- the new desktop after sending the window."""
- if not data.client: return
- screen = ob.openbox.screen(data.screen)
- d = screen.desktop()
- n = screen.numDesktops()
- if (d > 0):
- d = d - 1
- elif not no_wrap:
- d = n - 1
- send_to_desktop(data, d)
- if follow:
- change_desktop(data, d)
-
-def restart(data=0, other = ""):
- """Restarts Openbox, optionally starting another window manager."""
- ob.openbox.restart(other)
-
-def exit(data=0):
- """Exits Openbox."""
- ob.openbox.shutdown()
-
-export_functions = iconify, restore, close, focus, raise_win, lower_win, \
- toggle_maximize, toggle_maximize_horz, \
- toggle_maximize_vert, maximize, maximize_horz, \
- maximize_vert, unmaximize, unmaximize_horz, \
- unmaximize_vert, toggle_shade, shade, unshade, \
- change_desktop, show_desktop, hide_desktop, \
- toggle_show_desktop, next_desktop, prev_desktop, \
- up_desktop, down_desktop, left_desktop, right_desktop, \
- send_to_desktop, toggle_all_desktops, send_to_all_desktops,\
- send_to_next_desktop, send_to_prev_desktop, restart, exit
-
-print "Loaded callbacks.py"
+++ /dev/null
-# Openbox's config system. Please use the defined functions instead of
-# accessing the internal data structures directly, for the sake of us all.
-
-import ob
-
-def add(modulename, name, friendlyname, description, type, default,
- **keywords):
- """Add a variable to the configuration system.
-
- Add a variable to the configuration system for a module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- friendlyname - The user-friendly name of the variable, e.g. 'My Variable'
- description - The detailed destription of the variable, e.g. 'Does Things'
- type - The type of the variable, one of:
- - 'boolean'
- - 'enum'
- - 'integer'
- - 'string'
- - 'file'
- - 'function'
- - 'object'
- default - The default value for the variable, e.g. 300
- keywords - Extra keyword=value pairs to further define the variable. These
- can be:
- - For 'enum' types:
- - options : A list of possible options for the variable.
- This *must* be set for all enum variables.
- - For 'integer' types:
- - min : The minimum value for the variable.
- - max : The maximum value for the variable.
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- friendlyname = str(friendlyname)
- description = str(description)
- type = str(type).lower()
-
- # make sure the sub-dicts exist
- try:
- _settings[modulename]
- try:
- _settings[modulename][name]
- except KeyError:
- _settings[modulename][name] = {}
- except KeyError:
- _settings[modulename] = {}
- _settings[modulename][name] = {}
-
- # add the keywords first as they are used for the tests in set()
- for key,value in zip(keywords.keys(), keywords.values()):
- _settings[modulename][name][key] = value
-
- _settings[modulename][name]['name'] = friendlyname
- _settings[modulename][name]['description'] = description
- _settings[modulename][name]['type'] = type
- _settings[modulename][name]['default'] = default
-
- # put it through the tests
- try:
- set(modulename, name, default)
- except:
- del _settings[modulename][name]
- import sys
- raise sys.exc_info()[0], sys.exc_info()[1] # re-raise it
-
-def set(modulename, name, value):
- """Set a variable's value.
-
- Sets the value for a variable of the specified module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- value - The new value for the variable.
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
-
- # proper value checking for 'boolean's
- if _settings[modulename][name]['type'] == 'boolean':
- if not (value == 0 or value == 1):
- raise ValueError, 'Attempted to set ' + name + ' to a value of '+\
- str(value) + ' but boolean variables can only contain 0 or'+\
- ' 1.'
-
- # proper value checking for 'enum's
- elif _settings[modulename][name]['type'] == 'enum':
- options = _settings[modulename][name]['options']
- if not value in options:
- raise ValueError, 'Attempted to set ' + name + ' to a value of '+\
- str(value) + ' but this is not one of the possible values '+\
- 'for this enum variable. Possible values are: ' +\
- str(options) + "."
-
- # min/max checking for 'integer's
- elif _settings[modulename][name]['type'] == 'integer':
- try:
- min = _settings[modulename][name]['min']
- if value < min:
- raise ValueError, 'Attempted to set ' + name + ' to a value '+\
- ' of ' + str(value) + ' but it has a minimum value ' +\
- ' of ' + str(min) + '.'
- except KeyError: pass
- try:
- max = _settings[modulename][name]['max']
- if value > max:
- raise ValueError, 'Attempted to set ' + name + ' to a value '+\
- ' of ' + str(value) + ' but it has a maximum value ' +\
- ' of ' + str(min) + '.'
- except KeyError: pass
-
- _settings[modulename][name]['value'] = value
-
-def reset(modulename, name):
- """Reset a variable to its default value.
-
- Resets the value for a variable in the specified module back to its
- original (default) value.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my_variable'
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- _settings[modulename][name]['value'] = \
- _settings[modulename][name]['default']
-
-def get(modulename, name):
- """Returns the value of a variable.
-
- Returns the current value for a variable in the specified module.
- modulename - The name of the module, e.g. 'focus'
- name - The name of the variable, e.g. 'my variable'
- """
- modulename = str(modulename).lower()
- name = str(name).lower()
- return _settings[modulename][name]['value']
-
-#---------------------------- Internals ---------------------------
-
-"""The main configuration dictionary, which holds sub-dictionaries for each
- module.
-
- The format for entries in here like this (for a string):
- _settings['modulename']['varname']['name'] = 'Text Label'
- _settings['modulename']['varname']['description'] = 'Does this'
- _settings['modulename']['varname']['type'] = 'string'
- _settings['modulename']['varname']['default'] = 'Foo'
- _settings['modulename']['varname']['value'] = 'Foo'
- # 'value' should always be initialized to the same
- # value as the 'default' field!
-
- Here's an example of an enum:
- _settings['modulename']['varname']['name'] = 'My Enum Variable'
- _settings['modulename']['varname']['description'] = 'Does Enum-like things.'
- _settings['modulename']['varname']['type'] = 'enum'
- _settings['modulename']['varname']['default'] = \
- _settings['modulename']['varname']['value'] = [ 'Blue', 'Green', 'Pink' ]
-
- And Here's an example of an integer with bounds:
- _settings['modulename']['varname']['name'] = 'A Bounded Integer'
- _settings['modulename']['varname']['description'] = 'A fierce party animal!'
- _settings['modulename']['varname']['type'] = 'integer'
- _settings['modulename']['varname']['default'] = \
- _settings['modulename']['varname']['value'] = 0
- _settings['modulename']['varname']['min'] = 0
- _settings['modulename']['varname']['max'] = 49
-
- Hopefully you get the idea.
- """
-_settings = {}
-
-"""Valid values for a variable's type."""
-_types = [ 'boolean', # Boolean types can only hold a value of 0 or 1.
-
- 'enum', # Enum types hold a value from a list of possible values.
- # An 'options' field *must* be provided for enums,
- # containing a list of possible values for the variable.
-
- 'integer', # Integer types hold a single number, as well as a 'min'
- # and 'max' property.
- # If the 'min' or 'max' is ignore then bounds checking
- # will not be performed in that direction.
-
- 'string', # String types hold a text string.
-
- 'file', # File types hold a file object.
-
- 'function',# Function types hold any callable object.
-
- 'object' # Object types can hold any python object.
- ];
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#############################################################################
-### Options that can be changed to adjust the behavior of Openbox. ###
-#############################################################################
-
-THEME = "/usr/local/share/openbox/styles/fieron2"
-"""The theme used to decorate everything."""
-
-#TITLEBAR_LAYOUT = [ "icon", "title", "alldesktops", "iconify", "maximize", "close" ]
-TITLEBAR_LAYOUT = "DITMC"
-"""The layout of the buttons/label on client titlebars, can be made up of the
-following:
- I - iconify button
- L - text label
- M - maximize button,
- D - all-desktops button
- C - close button
-If no 'L' is included in the string, one will be added to the end by
-Openbox."""
-
-DOUBLE_CLICK_DELAY = 300
-"""The number of milliseconds in which 2 clicks are perceived as a
-double-click."""
-
-DRAG_THRESHOLD = 3
-"""The amount of pixels that you have to drag the mouse before motion events
-will start occuring."""
-
-DESKTOP_NAMES = ["one", "two", "three", "four", "five", "six", "seven", \
- "eight", "nine", "ten", "eleven", "twelve"]
-"""The name of each desktop."""
-
-NUMBER_OF_DESKTOPS = 4
-"""The number of desktops/workspaces which can be scrolled between."""
-
-#############################################################################
-
-print "Loaded config.py"
+++ /dev/null
-import ob, otk, config
-class _Cycle:
- """
- This is a basic cycling class for anything, from xOr's stackedcycle.py,
- that pops up a cycling menu when there's more than one thing to be cycled
- to.
- An example of inheriting from and modifying this class is _CycleWindows,
- which allows users to cycle around windows.
-
- This class could conceivably be used to cycle through anything -- desktops,
- windows of a specific class, XMMS playlists, etc.
- """
-
- """This specifies a rough limit of characters for the cycling list titles.
- Titles which are larger will be chopped with an elipsis in their
- center."""
- TITLE_SIZE_LIMIT = 80
-
- """If this is non-zero then windows will be activated as they are
- highlighted in the cycling list (except iconified windows)."""
- ACTIVATE_WHILE_CYCLING = 0
-
- """If this is true, we start cycling with the next (or previous) thing
- selected."""
- START_WITH_NEXT = 1
-
- """If this is true, a popup window will be displayed with the options
- while cycling."""
- SHOW_POPUP = 1
-
- def __init__(self):
- """Initialize an instance of this class. Subclasses should
- do any necessary event binding in their constructor as well.
- """
- self.cycling = 0 # internal var used for going through the menu
- self.items = [] # items to cycle through
-
- self.widget = None # the otk menu widget
- self.menuwidgets = [] # labels in the otk menu widget TODO: RENAME
-
- def createPopup(self):
- """Creates the cycling popup menu.
- """
- self.widget = otk.Widget(self.screen.number(), ob.openbox,
- otk.Widget.Vertical, 0, 1)
-
- def destroyPopup(self):
- """Destroys (or rather, cleans up after) the cycling popup menu.
- """
- self.menuwidgets = []
- self.widget = 0
-
- def populateItems(self):
- """Populate self.items with the appropriate items that can currently
- be cycled through. self.items may be cleared out before this
- method is called.
- """
- pass
-
- def menuLabel(self, item):
- """Return a string indicating the menu label for the given item.
- Don't worry about title truncation.
- """
- pass
-
- def itemEqual(self, item1, item2):
- """Compare two items, return 1 if they're "equal" for purposes of
- cycling, and 0 otherwise.
- """
- # suggestion: define __eq__ on item classes so that this works
- # in the general case. :)
- return item1 == item2
-
- def populateLists(self):
- """Populates self.items and self.menuwidgets, and then shows and
- positions the cycling popup. You probably shouldn't mess with
- this function; instead, see populateItems and menuLabel.
- """
- self.widget.hide()
-
- try:
- current = self.items[self.menupos]
- except IndexError:
- current = None
- oldpos = self.menupos
- self.menupos = -1
-
- self.items = []
- self.populateItems()
-
- # make the widgets
- i = 0
- self.menuwidgets = []
- for i in range(len(self.items)):
- c = self.items[i]
-
- w = otk.Label(self.widget)
- # current item might have shifted after a populateItems()
- # call, so we need to do this test.
- if current and self.itemEqual(c, current):
- self.menupos = i
- w.setHilighted(1)
- self.menuwidgets.append(w)
-
- t = self.menuLabel(c)
- # TODO: maybe subclasses will want to truncate in different ways?
- if len(t) > self.TITLE_SIZE_LIMIT: # limit the length of titles
- t = t[:self.TITLE_SIZE_LIMIT / 2 - 2] + "..." + \
- t[0 - self.TITLE_SIZE_LIMIT / 2 - 2:]
- w.setText(t)
-
- # The item we were on might be gone entirely
- if self.menupos < 0:
- # try stay at the same spot in the menu
- if oldpos >= len(self.items):
- self.menupos = len(self.items) - 1
- else:
- self.menupos = oldpos
-
- # find the size for the popup
- width = 0
- height = 0
- for w in self.menuwidgets:
- size = w.minSize()
- if size.width() > width: width = size.width()
- height += size.height()
-
- # show or hide the list and its child widgets
- if len(self.items) > 1:
- size = self.screen.size()
- self.widget.moveresize(otk.Rect((size.width() - width) / 2,
- (size.height() - height) / 2,
- width, height))
- if self.SHOW_POPUP: self.widget.show(1)
-
- def activateTarget(self, final):
- """Activates (focuses and, if the user requested it, raises a window).
- If final is true, then this is the very last window we're activating
- and the user has finished cycling.
- """
- pass
-
- def setDataInfo(self, data):
- """Retrieve and/or calculate information when we start cycling,
- preferably caching it. Data is what's given to callback functions.
- """
- self.screen = ob.openbox.screen(data.screen)
-
- def chooseStartPos(self):
- """Set self.menupos to a number between 0 and len(self.items) - 1.
- By default the initial menupos is 0, but this can be used to change
- it to some other position."""
- pass
-
- def cycle(self, data, forward):
- """Does the actual job of cycling through windows. data is a callback
- parameter, while forward is a boolean indicating whether the
- cycling goes forwards (true) or backwards (false).
- """
-
- initial = 0
-
- if not self.cycling:
- ob.kgrab(data.screen, self.grabfunc)
- # the pointer grab causes pointer events during the keyboard grab
- # to go away, which means we don't get enter notifies when the
- # popup disappears, screwing up the focus
- ob.mgrab(data.screen)
-
- self.cycling = 1
- self.state = data.state
- self.menupos = 0
-
- self.setDataInfo(data)
-
- self.createPopup()
- self.items = [] # so it doesnt try start partway through the list
- self.populateLists()
-
- self.chooseStartPos()
- self.initpos = self.menupos
-
- initial = 1
-
- if not self.items: return # don't bother doing anything
-
- self.menuwidgets[self.menupos].setHighlighted(0)
-
- if initial and not self.START_WITH_NEXT:
- pass
- else:
- if forward:
- self.menupos += 1
- else:
- self.menupos -= 1
- # wrap around
- if self.menupos < 0: self.menupos = len(self.items) - 1
- elif self.menupos >= len(self.items): self.menupos = 0
- self.menuwidgets[self.menupos].setHighlighted(1)
- if self.ACTIVATE_WHILE_CYCLING:
- self.activateTarget(0) # activate, but dont deiconify/unshade/raise
-
- def grabfunc(self, data):
- """A callback method that grabs away all keystrokes so that navigating
- the cycling menu is possible."""
- done = 0
- notreverting = 1
- # have all the modifiers this started with been released?
- if not self.state & data.state:
- done = 1
- elif data.action == ob.KeyAction.Press:
- # has Escape been pressed?
- if data.key == "Escape":
- done = 1
- notreverting = 0
- # revert
- self.menupos = self.initpos
- # has Enter been pressed?
- elif data.key == "Return":
- done = 1
-
- if done:
- # activate, and deiconify/unshade/raise
- self.activateTarget(notreverting)
- self.destroyPopup()
- self.cycling = 0
- ob.kungrab()
- ob.mungrab()
-
- def next(self, data):
- """Focus the next window."""
- self.cycle(data, 1)
-
- def previous(self, data):
- """Focus the previous window."""
- self.cycle(data, 0)
-
-#---------------------- Window Cycling --------------------
-import focus
-class _CycleWindows(_Cycle):
- """
- This is a basic cycling class for Windows.
-
- An example of inheriting from and modifying this class is
- _ClassCycleWindows, which allows users to cycle around windows of a certain
- application name/class only.
-
- This class has an underscored name because I use the singleton pattern
- (so CycleWindows is an actual instance of this class). This doesn't have
- to be followed, but if it isn't followed then the user will have to create
- their own instances of your class and use that (not always a bad thing).
-
- An example of using the CycleWindows singleton:
-
- from cycle import CycleWindows
- CycleWindows.INCLUDE_ICONS = 0 # I don't like cycling to icons
- ob.kbind(["A-Tab"], ob.KeyContext.All, CycleWindows.next)
- ob.kbind(["A-S-Tab"], ob.KeyContext.All, CycleWindows.previous)
- """
-
- """If this is non-zero then windows from all desktops will be included in
- the stacking list."""
- INCLUDE_ALL_DESKTOPS = 0
-
- """If this is non-zero then windows which are iconified on the current
- desktop will be included in the stacking list."""
- INCLUDE_ICONS = 1
-
- """If this is non-zero then windows which are iconified from all desktops
- will be included in the stacking list."""
- INCLUDE_ICONS_ALL_DESKTOPS = 1
-
- """If this is non-zero then windows which are on all-desktops at once will
- be included."""
- INCLUDE_OMNIPRESENT = 1
-
- """A better default for window cycling than generic cycling."""
- ACTIVATE_WHILE_CYCLING = 1
-
- """When cycling focus, raise the window chosen as well as focusing it."""
- RAISE_WINDOW = 1
-
- def __init__(self):
- _Cycle.__init__(self)
-
- def newwindow(data):
- if self.cycling: self.populateLists()
- def closewindow(data):
- if self.cycling: self.populateLists()
-
- ob.ebind(ob.EventAction.NewWindow, newwindow)
- ob.ebind(ob.EventAction.CloseWindow, closewindow)
-
- def shouldAdd(self, client):
- """Determines if a client should be added to the cycling list."""
- curdesk = self.screen.desktop()
- desk = client.desktop()
-
- if not client.normal(): return 0
- if not (client.canFocus() or client.focusNotify()): return 0
- if config.get('focus', 'avoid_skip_taskbar') and client.skipTaskbar():
- return 0
-
- if client.iconic():
- if self.INCLUDE_ICONS:
- if self.INCLUDE_ICONS_ALL_DESKTOPS: return 1
- if desk == curdesk: return 1
- return 0
- if self.INCLUDE_OMNIPRESENT and desk == 0xffffffff: return 1
- if self.INCLUDE_ALL_DESKTOPS: return 1
- if desk == curdesk: return 1
-
- return 0
-
- def populateItems(self):
- # get the list of clients, keeping iconic windows at the bottom
- iconic_clients = []
- for c in focus._clients:
- if self.shouldAdd(c):
- if c.iconic(): iconic_clients.append(c)
- else: self.items.append(c)
- self.items.extend(iconic_clients)
-
- def menuLabel(self, client):
- if client.iconic(): t = '[' + client.iconTitle() + ']'
- else: t = client.title()
-
- if self.INCLUDE_ALL_DESKTOPS:
- d = client.desktop()
- if d == 0xffffffff: d = self.screen.desktop()
- t = self.screen.desktopNames()[d] + " - " + t
-
- return t
-
- def itemEqual(self, client1, client2):
- return client1.window() == client2.window()
-
- def activateTarget(self, final):
- """Activates (focuses and, if the user requested it, raises a window).
- If final is true, then this is the very last window we're activating
- and the user has finished cycling."""
- try:
- client = self.items[self.menupos]
- except IndexError: return # empty list
-
- # move the to client's desktop if required
- if not (client.iconic() or client.desktop() == 0xffffffff or \
- client.desktop() == self.screen.desktop()):
- self.screen.changeDesktop(client.desktop())
-
- # send a net_active_window message for the target
- if final or not client.iconic():
- if final: r = self.RAISE_WINDOW
- else: r = 0
- client.focus(final, r)
- if not final:
- focus._skip += 1
-
-# The singleton.
-CycleWindows = _CycleWindows()
-
-#---------------------- Window Cycling --------------------
-import focus
-class _CycleWindowsLinear(_CycleWindows):
- """
- This class is an example of how to inherit from and make use of the
- _CycleWindows class. This class also uses the singleton pattern.
-
- An example of using the CycleWindowsLinear singleton:
-
- from cycle import CycleWindowsLinear
- CycleWindows.ALL_DESKTOPS = 1 # I want all my windows in the list
- ob.kbind(["A-Tab"], ob.KeyContext.All, CycleWindowsLinear.next)
- ob.kbind(["A-S-Tab"], ob.KeyContext.All, CycleWindowsLinear.previous)
- """
-
- """When cycling focus, raise the window chosen as well as focusing it."""
- RAISE_WINDOW = 0
-
- """If this is true, a popup window will be displayed with the options
- while cycling."""
- SHOW_POPUP = 0
-
- def __init__(self):
- _CycleWindows.__init__(self)
-
- def shouldAdd(self, client):
- """Determines if a client should be added to the cycling list."""
- curdesk = self.screen.desktop()
- desk = client.desktop()
-
- if not client.normal(): return 0
- if not (client.canFocus() or client.focusNotify()): return 0
- if config.get('focus', 'avoid_skip_taskbar') and client.skipTaskbar():
- return 0
-
- if client.iconic(): return 0
- if self.INCLUDE_OMNIPRESENT and desk == 0xffffffff: return 1
- if self.INCLUDE_ALL_DESKTOPS: return 1
- if desk == curdesk: return 1
-
- return 0
-
- def populateItems(self):
- # get the list of clients, keeping iconic windows at the bottom
- iconic_clients = []
- for c in self.screen.clients:
- if self.shouldAdd(c):
- self.items.append(c)
-
- def chooseStartPos(self):
- if focus._clients:
- t = focus._clients[0]
- for i,c in zip(range(len(self.items)), self.items):
- if self.itemEqual(c, t):
- self.menupos = i
- break
-
- def menuLabel(self, client):
- t = client.title()
-
- if self.INCLUDE_ALL_DESKTOPS:
- d = client.desktop()
- if d == 0xffffffff: d = self.screen.desktop()
- t = self.screen.desktopNames()[d] + " - " + t
-
- return t
-
-# The singleton.
-CycleWindowsLinear = _CycleWindowsLinear()
-
-#----------------------- Desktop Cycling ------------------
-class _CycleDesktops(_Cycle):
- """
- Example of usage:
-
- from cycle import CycleDesktops
- ob.kbind(["W-d"], ob.KeyContext.All, CycleDesktops.next)
- ob.kbind(["W-S-d"], ob.KeyContext.All, CycleDesktops.previous)
- """
- class Desktop:
- def __init__(self, name, index):
- self.name = name
- self.index = index
- def __eq__(self, other):
- return other.index == self.index
-
- def __init__(self):
- _Cycle.__init__(self)
-
- def populateItems(self):
- names = self.screen.desktopNames()
- num = self.screen.numDesktops()
- for n, i in zip(names[:num], range(num)):
- self.items.append(_CycleDesktops.Desktop(n, i))
-
- def menuLabel(self, desktop):
- return desktop.name
-
- def chooseStartPos(self):
- self.menupos = self.screen.desktop()
-
- def activateTarget(self, final):
- # TODO: refactor this bit
- try:
- desktop = self.items[self.menupos]
- except IndexError: return
-
- self.screen.changeDesktop(desktop.index)
-
-CycleDesktops = _CycleDesktops()
-
-print "Loaded cycle.py"
+++ /dev/null
-import ob # base module
-import focus # add some default focus handling and cycling functions
-import focusmodel # default focus models
-import behavior # defines default behaviors for interaction with windows
-import callbacks # a lib of functions that can be used as binding callbacks
-import windowplacement # use a routine in here to place windows
-import historyplacement # history window placement
-
-# try focus something when nothing is focused
-focus.FALLBACK = 1
-
-# choose a default focus model
-focusmodel.setup_click_focus() # use focusmodel.setup_sloppy_focus() instead to
- # make focus follow the cursor, or bind things
- # in some way like these functions do to make
- # your own custom focus model.
-# set up the mouse buttons
-behavior.setup_window_clicks()
-behavior.setup_window_buttons()
-behavior.setup_scroll()
-
-# my window placement algorithm
-#ob.ebind(ob.EventAction.PlaceWindow, windowplacement.random)
-ob.ebind(ob.EventAction.PlaceWindow, historyplacement.place)
-# don't place terminals by history placement (xterm,aterm,rxvt)
-def histplace(data):
- if data.client.appClass() == "XTerm": return 0
- return 1
-historyplacement.CONFIRM_CALLBACK = histplace
-
-
-# run xterm from root clicks
-ob.mbind("Left", ob.MouseContext.Root, ob.MouseAction.Click,
- lambda(d): ob.execute("xterm", d.screen))
-
-ob.kbind(["A-F4"], ob.KeyContext.All, callbacks.close)
-
-ob.kbind(["W-d"], ob.KeyContext.All, callbacks.toggle_show_desktop)
-
-# focus bindings
-
-from cycle import CycleWindows
-ob.kbind(["A-Tab"], ob.KeyContext.All, CycleWindows.next)
-ob.kbind(["A-S-Tab"], ob.KeyContext.All, CycleWindows.previous)
-
-# if you want linear cycling instead of stacked cycling, comment out the two
-# bindings above, and use these instead.
-#from cycle import CycleWindowsLinear
-#ob.kbind(["A-Tab"], ob.KeyContext.All, CycleWindows.next)
-#ob.kbind(["A-S-Tab"], ob.KeyContext.All, CycleWindows.previous)
-
-from cycle import CycleDesktops
-ob.kbind(["C-Tab"], ob.KeyContext.All, CycleDesktops.next)
-ob.kbind(["C-S-Tab"], ob.KeyContext.All, CycleDesktops.previous)
-
-# desktop changing bindings
-ob.kbind(["C-1"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 0))
-ob.kbind(["C-2"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 1))
-ob.kbind(["C-3"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 2))
-ob.kbind(["C-4"], ob.KeyContext.All, lambda(d): callbacks.change_desktop(d, 3))
-ob.kbind(["C-A-Right"], ob.KeyContext.All,
- lambda(d): callbacks.right_desktop(d))
-ob.kbind(["C-A-Left"], ob.KeyContext.All,
- lambda(d): callbacks.left_desktop(d))
-ob.kbind(["C-A-Up"], ob.KeyContext.All,
- lambda(d): callbacks.up_desktop(d))
-ob.kbind(["C-A-Down"], ob.KeyContext.All,
- lambda(d): callbacks.down_desktop(d))
-
-ob.kbind(["C-S-A-Right"], ob.KeyContext.All,
- lambda(d): callbacks.send_to_next_desktop(d))
-ob.kbind(["C-S-A-Left"], ob.KeyContext.All,
- lambda(d): callbacks.send_to_prev_desktop(d))
-
-# focus new windows
-ob.ebind(ob.EventAction.NewWindow, callbacks.focus)
-
-print "Loaded defaults.py"
+++ /dev/null
-###########################################################################
-### Functions for helping out with your window focus. ###
-###########################################################################
-
-import config, ob
-
-export_functions = ()
-
-config.add('focus',
- 'avoid_skip_taskbar',
- 'Avoid SkipTaskbar Windows',
- "Don't focus windows which have requested to not be displayed " + \
- "in taskbars. You will still be able to focus the windows, but " + \
- "not through cycling, and they won't be focused as a fallback " + \
- "if 'Focus Fallback' is enabled.",
- 'boolean',
- 1)
-
-config.add('focus',
- 'fallback',
- 'Focus Fallback',
- "Send focus somewhere when nothing is left with the focus, if " + \
- "possible.",
- 'boolean',
- 1)
-
-# maintain a list of clients, stacked in focus order
-_clients = []
-_skip = 0
-
-def _focusable(client, desktop):
- if not client.normal(): return 0
- if not (client.canFocus() or client.focusNotify()): return 0
- if client.iconic(): return 0
- if config.get('focus', 'avoid_skip_taskbar') and \
- client.skipTaskbar(): return 0
-
- desk = client.desktop()
- if not (desk == 0xffffffff or desk == desktop): return 0
-
- return 1
-
-def _remove(client):
- """This function exists because Swig pointers don't define a __eq__
- function, so list.remove(ptr) does not work."""
- win = client.window()
- for i in range(len(_clients)):
- if _clients[i].window() == win:
- _clients.pop(i)
- return
- raise ValueError("_remove(x): x not in _clients list.")
-
-def _focused(data):
- global _clients, _skip
-
- if _skip:
- _skip -= 1
- return
-
- if data.client:
- # move it to the top
- try:
- _remove(data.client)
- except ValueError: pass # happens if _focused comes before _newwindow
- _clients.insert(0, data.client)
- elif config.get('focus', 'fallback'):
- # pass around focus
- desktop = ob.openbox.screen(data.screen).desktop()
- for c in _clients:
- if _focusable(c, desktop):
- c.focus()
- break
-
-def _newwindow(data):
- # make sure its not already in the list
- win = data.client.window()
- for i in range(len(_clients)):
- if _clients[i].window() == win:
- return
- _clients.append(data.client)
-
-def _closewindow(data):
- _remove(data.client)
-
-ob.ebind(ob.EventAction.NewWindow, _newwindow)
-ob.ebind(ob.EventAction.CloseWindow, _closewindow)
-ob.ebind(ob.EventAction.Focus, _focused)
-
-print "Loaded focus.py"
+++ /dev/null
-###############################################################################
-### Functions for setting up some default focus models. ###
-###############################################################################
-
-import ob
-import callbacks
-
-def setup_click_focus(click_raise = 1):
- """Sets up for focusing windows by clicking on or in the window.
- Optionally, clicking on or in a window can raise the window to the
- front of its stacking layer."""
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Window,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Middle", ob.MouseContext.Window,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("A-Left", ob.MouseContext.Frame,
- ob.MouseAction.Press, callbacks.focus)
- if click_raise:
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Window,
- ob.MouseAction.Press, callbacks.raise_win)
-
-def setup_sloppy_focus(click_focus = 1, click_raise = 0):
- """Sets up for focusing windows when the mouse pointer enters them.
- Optionally, clicking on or in a window can focus it if your pointer
- ends up inside a window without focus. Also, optionally, clicking on or
- in a window can raise the window to the front of its stacking layer."""
- ob.ebind(ob.EventAction.EnterWindow, callbacks.focus)
- if click_focus:
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Press, callbacks.focus)
- ob.mbind("Left", ob.MouseContext.Window,
- ob.MouseAction.Press, callbacks.focus)
- if click_raise:
- ob.mbind("Left", ob.MouseContext.Titlebar,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Handle,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Grip,
- ob.MouseAction.Press, callbacks.raise_win)
- ob.mbind("Left", ob.MouseContext.Window,
- ob.MouseAction.Press, callbacks.raise_win)
-
-export_functions = setup_click_focus, setup_sloppy_focus
-
-print "Loaded focusmodel.py"
+++ /dev/null
-##############################################################################
-### The history window placement algorithm. ebind historyplacement.place ###
-### to the ob.EventAction.PlaceWindow event to use it. ###
-##############################################################################
-
-import windowplacement, config
-
-def place(data):
- """Place a window usingthe history placement algorithm."""
- _place(data)
-
-export_functions = place
-
-##############################################################################
-
-config.add('historyplacement',
- 'ignore_requested_positions',
- 'Ignore Requested Positions',
- "When true, the placement algorithm will attempt to place " + \
- "windows even when they request a position (like XMMS can)." + \
- "Note this only applies to 'normal' windows, not to special " + \
- "cases like desktops and docks.",
- 'boolean',
- 0)
-config.add('historyplacement',
- 'dont_duplicate',
- "Don't Diplicate",
- "When true, if 2 copies of the same match in history are to be " + \
- "placed before one of them is closed (so it would be placed " + \
- "over-top of the last one), this will cause the second window to "+\
- "not be placed via history, and the 'Fallback Algorithm' will be "+\
- "used instead.",
- 'boolean',
- 1)
-config.add('historyplacement',
- 'filename',
- 'History Database Filename',
- "The name of the file where history data will be stored. The " + \
- "number of the screen is appended onto this name. The file will " +\
- "be placed in ~/.openbox/.",
- 'string',
- 'historydb')
-config.add('historyplacement',
- 'fallback',
- 'Fallback Algorithm',
- "The window placement algorithm that will be used when history " + \
- "placement does not have a place for the window.",
- 'enum',
- windowplacement.random,
- options = windowplacement.export_functions)
-
-###########################################################################
-
-###########################################################################
-### Internal stuff, should not be accessed outside the module. ###
-###########################################################################
-
-import otk
-import ob
-import os
-import string
-
-_data = []
-
-class _state:
- def __init__(self, appname, appclass, role, x, y):
- self.appname = appname
- self.appclass = appclass
- self.role = role
- self.x = x
- self.y = y
- self.placed = 0
- def __eq__(self, other):
- if self.appname == other.appname and \
- self.appclass == other.appclass and \
- self.role == other.role:
- return 1
- return 0
-
-def _load(data):
- global _data
- try:
- file = open(os.environ['HOME'] + '/.openbox/' + \
- config.get('historyplacement', 'filename') + \
- "." + str(data.screen), 'r')
- # read data
- for line in file.readlines():
- line = line[:-1] # drop the '\n'
- try:
- s = string.split(line, '\0')
- state = _state(s[0], s[1], s[2],
- string.atoi(s[3]), string.atoi(s[4]))
-
- while len(_data)-1 < data.screen:
- _data.append([])
- _data[data.screen].append(state)
-
- except ValueError: pass
- except IndexError: pass
- file.close()
- except IOError: pass
-
-def _save(data):
- global _data
- file = open(os.environ['HOME']+'/.openbox/'+ \
- config.get('historyplacement', 'filename') + \
- "." + str(data.screen), 'w')
- if file:
- while len(_data)-1 < data.screen:
- _data.append([])
- for i in _data[data.screen]:
- file.write(i.appname + '\0' +
- i.appclass + '\0' +
- i.role + '\0' +
- str(i.x) + '\0' +
- str(i.y) + '\n')
- file.close()
-
-def _create_state(data):
- global _data
- area = data.client.area()
- return _state(data.client.appName(), data.client.appClass(),
- data.client.role(), area.x(), area.y())
-
-def _find(screen, state):
- global _data
- try:
- return _data[screen].index(state)
- except ValueError:
- return -1
- except IndexError:
- while len(_data)-1 < screen:
- _data.append([])
- return _find(screen, state) # try again
-
-def _place(data):
- global _data
- if data.client:
- if not (config.get('historyplacement', 'ignore_requested_positions') \
- and data.client.normal()):
- if data.client.positionRequested(): return
- state = _create_state(data)
- try:
- print "looking for : " + state.appname + " : " + \
- state.appclass + " : " + state.role
-
- i = _find(data.screen, state)
- if i >= 0:
- coords = _data[data.screen][i]
- print "Found in history ("+str(coords.x)+","+\
- str(coords.y)+")"
- if not (config.get('historyplacement', 'dont_duplicate') \
- and coords.placed):
- data.client.move(coords.x, coords.y)
- coords.placed = 1
- return
- else:
- print "Already placed another window there"
- else:
- print "No match in history"
- except TypeError:
- pass
- fallback = config.get('historyplacement', 'fallback')
- if fallback: fallback(data)
-
-def _save_window(data):
- global _data
- if data.client:
- state = _create_state(data)
- print "looking for : " + state.appname + " : " + state.appclass + \
- " : " + state.role
-
- i = _find(data.screen, state)
- if i >= 0:
- print "replacing"
- _data[data.screen][i] = state # replace it
- else:
- print "appending"
- _data[data.screen].append(state)
-
-ob.ebind(ob.EventAction.CloseWindow, _save_window)
-ob.ebind(ob.EventAction.Startup, _load)
-ob.ebind(ob.EventAction.Shutdown, _save)
-
-print "Loaded historyplacement.py"
+++ /dev/null
-############################################################################
-### Functions that provide callbacks for motion events to move and ###
-### resize windows. ###
-############################################################################
-
-def move(data):
- """Moves the window interactively. This should only be used with
- MouseAction.Motion events. If 'Coords Popup for Moving' or 'Rubberband
- Mode for Moving' is enabled, then the end_move function needs to be
- bound as well."""
- _move(data)
-
-def end_move(data):
- """Complete the interactive move of a window."""
- _end_move(data)
-
-def resize(data):
- """Resizes the window interactively. This should only be used with
- MouseMotion events. If 'Coords Popup for Resizing' or 'Rubberband Mode
- for Resizing' is enabled, then the end_resize function needs to be
- bound as well."""
- _resize(data)
-
-def end_resize(data):
- """Complete the interactive resize of a window."""
- _end_resize(data)
-
-export_functions = move, end_move, resize, end_resize
-
-#############################################################################
-
-import config
-
-config.add('motion',
- 'edge_resistance',
- 'Edge Resistance',
- "The amount of resistance to provide to moving a window past a " + \
- "screen boundary. Specify a value of 0 to disable edge resistance.",
- 'integer',
- 10,
- min = 0)
-config.add('motion',
- 'popup_in_window',
- 'Coords Popup In Window',
- "When this is true, the coordinates popups will be placed " + \
- "relative to the window being moved/resized. When false, they " + \
- "will appear relative to the entire screen.",
- 'boolean',
- 0)
-config.add('motion',
- 'popup_centered',
- 'Coords Popup Centered',
- "When this is true, the coordinates popups will be centered " + \
- "relative to the window or screen (see 'Coords Popup In " + \
- "Window'). When false, they will be placed based upon the " + \
- "'Coords Popup Position' options.",
- 'boolean',
- 1)
-config.add('motion',
- 'popup_coords_x',
- 'Coords Popup Position - X',
- "When 'Coords Popup Centered' is false, this position will be " + \
- "used to place the coordinates popups. The popups will be " + \
- "placed relative to the window or the screen (see 'Coords " + \
- "Popup In Window'). A value of 0 would place it at the left " + \
- "edge, while a value of -1 would place it at the right edge. " + \
- "This value behaves similarly to those passed to the -geometry " + \
- "flag of many applications.",
- 'integer',
- 0)
-config.add('motion',
- 'popup_coords_y',
- 'Coords Popup Position - Y',
- "When 'Coords Popup Centered' is false, this position will be " + \
- "used to place the coordinates popups. The popups will be " + \
- "placed relative to the window or the screen (see 'Coords Popup " +\
- "In Window'). A value of 0 would place it at the top edge, " + \
- "while a value of -1 would place it at the bottom edge. This " + \
- "value behaves similarly to those passed to the -geometry flag " + \
- "of many applications.",
- 'integer',
- 0)
-config.add('motion',
- 'move_popup',
- 'Coords Popup for Moving',
- "Option to display a coordinates popup when moving windows.",
- 'boolean',
- 1)
-config.add('motion',
- 'move_rubberband',
- 'Rubberband Mode for Moving',
- "NOT IMPLEMENTED (yet?)\n"+\
- "Display an outline while moving instead of moving the actual " + \
- "window, until the move is completed. Good for slower systems.",
- 'boolean',
- 0)
-config.add('motion',
- 'resize_popup',
- 'Coords Popup for Resizing',
- "Option to display a coordinates popup when resizing windows.",
- 'boolean',
- 1)
-config.add('motion',
- 'resize_rubberband',
- 'Rubberband Mode for Resizing',
- "NOT IMPLEMENTED (yet?)\n"+\
- "Display an outline while resizing instead of resizing the " + \
- "actual window, until the resize is completed. Good for slower " + \
- "systems.",
- 'boolean',
- 0)
-config.add('motion',
- 'resize_nearest',
- 'Resize Nearest Corner',
- "When true, resizing will occur from the corner nearest where " + \
- "the mouse is. When false resizing will always occur from the " + \
- "bottom right corner.",
- 'boolean',
- 1)
-
-###########################################################################
-### Internal stuff, should not be accessed outside the module. ###
-###########################################################################
-
-import ob
-import otk
-
-_popwidget = 0
-
-# motion state
-_inmove = 0
-_inresize = 0
-
-# last motion data
-_cx = 0
-_cy = 0
-_cw = 0
-_ch = 0
-_px = 0
-_py = 0
-_dx = 0
-_dy = 0
-_client = 0
-_screen = 0
-
-_motion_mask = 0
-
-def _place_popup():
- if config.get('motion', 'popup_in_window'):
- # use the actual client's area, not the frame's
- area = _client.frame.area()
- size = _client.frame.size()
- area = otk.Rect(area.x() + size.left, area.y() + size.top,
- area.width() - size.left - size.right,
- area.height() - size.top - size.bottom)
- else:
- area = otk.Rect(otk.Point(0, 0), ob.openbox.screen(_screen).size())
- size = _popwidget.minSize()
- if config.get('motion', 'popup_centered'):
- x = area.position().x() + (area.size().width() - size.width()) / 2
- y = area.position().y() + (area.size().height() - size.height()) / 2
- else:
- x = config.get('motion', 'popup_coords_x')
- y = config.get('motion', 'popup_coords_y')
- if x < 0: x += area.width() - size.width() + 1
- if y < 0: y += area.width() - size.height() + 1
- x += area.position().x()
- y += area.position().y()
- _popwidget.moveresize(otk.Rect(x, y, size.width(), size.height()))
-
-def _motion_grab(data):
- global _motion_mask, _inmove, _inresize;
-
- # are all the modifiers this started with still pressed?
- if not _motion_mask & data.state:
- if _inmove:
- _end_move(data)
- elif _inresize:
- _end_resize(data)
- else:
- raise RuntimeError
-
-_last_x = 0
-_last_y = 0
-
-def _do_move(final):
- global _screen, _client, _cx, _cy, _dx, _dy
-
- # get destination x/y for the *frame*
- x = _cx + _dx + _client.frame.area().x() - _client.area().x()
- y = _cy + _dy + _client.frame.area().y() - _client.area().y()
-
- global _last_x, _last_y
- resist = config.get('motion', 'edge_resistance')
- if resist:
- fs = _client.frame.size()
- w = _client.area().width() + fs.left + fs.right
- h = _client.area().height() + fs.top + fs.bottom
- # use the area based on the struts
- area = ob.openbox.screen(_screen).area(_client.desktop())
- l = area.left()
- r = area.right() - w + 1
- t = area.top()
- b = area.bottom() - h + 1
- # left screen edge
- if _last_x > x and x < l and x >= l - resist:
- x = l
- # right screen edge
- if _last_x < x and x > r and x <= r + resist:
- x = r
- # top screen edge
- if _last_y > y and y < t and y >= t - resist:
- y = t
- # right screen edge
- if _last_y < y and y > b and y <= b + resist:
- y = b
-
- global _inmove
- if not _inmove:
- _last_x = 0
- _last_y = 0
- else:
- _last_x = x
- _last_y = y
-
- if not final and config.get('motion', 'move_rubberband'):
- # XXX draw the outline ...
- pass
- else:
- _client.move(x, y, final)
-
- if config.get('motion', 'move_popup'):
- global _popwidget
- text = "X: " + str(x) + " Y: " + str(y)
- if not _popwidget:
- _popwidget = otk.Label(_screen, ob.openbox)
- _popwidget.setHighlighted(1)
- _popwidget.setText(text)
- _place_popup()
- _popwidget.show()
-
-def _move(data):
- if not data.client: return
-
- # not-normal windows dont get moved
- if not data.client.normal(): return
-
- global _screen, _client, _cx, _cy, _dx, _dy, _motion_mask
- _screen = data.screen
- _client = data.client
- _cx = data.press_clientx
- _cy = data.press_clienty
- _dx = data.xroot - data.pressx
- _dy = data.yroot - data.pressy
- _motion_mask = data.state
- _do_move(0)
- global _inmove
- if not _inmove:
- ob.kgrab(_screen, _motion_grab)
- _inmove = 1
-
-def _end_move(data):
- global _inmove, _popwidget
- if _inmove:
- _do_move(1)
- _inmove = 0
- _popwidget = 0
- ob.kungrab()
-
-def _do_resize(final):
- global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
-
- dx = _dx
- dy = _dy
-
- # pick a corner to anchor
- if not (config.get('motion', 'resize_nearest') or
- _context == ob.MouseContext.Grip):
- corner = ob.Client.TopLeft
- else:
- x = _px - _cx
- y = _py - _cy
- if y < _ch / 2:
- if x < _cw / 2:
- corner = ob.Client.BottomRight
- dx *= -1
- else:
- corner = ob.Client.BottomLeft
- dy *= -1
- else:
- if x < _cw / 2:
- corner = ob.Client.TopRight
- dx *= -1
- else:
- corner = ob.Client.TopLeft
-
- w = _cw + dx
- h = _ch + dy
-
- if not final and config.get('motion', 'resize_rubberband'):
- # XXX draw the outline ...
- pass
- else:
- _client.resize(corner, w, h)
-
- if config.get('motion', 'resize_popup'):
- global _popwidget
- ls = _client.logicalSize()
- text = "W: " + str(ls.width()) + " H: " + str(ls.height())
- if not _popwidget:
- _popwidget = otk.Label(_screen, ob.openbox)
- _popwidget.setHighlighted(1)
- _popwidget.setText(text)
- _place_popup()
- _popwidget.show()
-
-def _resize(data):
- if not data.client: return
-
- # not-normal windows dont get resized
- if not data.client.normal(): return
-
- global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
- global _motion_mask
- _screen = data.screen
- _client = data.client
- _cx = data.press_clientx
- _cy = data.press_clienty
- _cw = data.press_clientwidth
- _ch = data.press_clientheight
- _px = data.pressx
- _py = data.pressy
- _dx = data.xroot - _px
- _dy = data.yroot - _py
- _motion_mask = data.state
- _do_resize(0)
- global _inresize
- if not _inresize:
- ob.kgrab(_screen, _motion_grab)
- _inresize = 1
-
-def _end_resize(data):
- global _inresize, _popwidget
- if _inresize:
- _do_resize(1)
- _inresize = 0
- _popwidget = 0
- ob.kungrab()
+++ /dev/null
-############################################################################
-### Window placement algorithms, choose one of these and ebind it to the ###
-### ob.EventAction.PlaceWindow event. ###
-### ###
-### Also see historyplacement.py for the history placement module which ###
-### provides an algorithm that can be used in place of, or alongside, ###
-### these. ###
-############################################################################
-
-import otk, ob, random
-
-_rand = random.Random()
-
-def random(data):
- """Place windows randomly around the screen."""
- if not data.client: return
- if data.client.positionRequested(): return
- client_area = data.client.frame.area()
- screen_area = ob.openbox.screen(data.screen).area(data.client.desktop())
- width = screen_area.width() - client_area.width()
- height = screen_area.height() - client_area.height()
- global _rand
- x = _rand.randrange(screen_area.x(), width-1)
- y = _rand.randrange(screen_area.y(), height-1)
- data.client.move(x, y)
-
-_cascade_x = 0
-_cascade_y = 0
-
-def cascade(data):
- """Place windows in a cascading order from top-left to bottom-right."""
- if not data.client: return
- if data.client.positionRequested(): return
- client_area = data.client.frame.area()
- screen_area = ob.openbox.screen(data.screen).area(data.client.desktop())
- width = screen_area.width() - client_area.width()
- height = screen_area.height() - client_area.height()
- global _cascade_x, _cascade_y
- if _cascade_x < screen_area.x() or _cascade_y < screen_area.y() or \
- _cascade_x >= width or _cascade_y >= height:
- _cascade_x = screen_area.x()
- _cascade_y = screen_area.y()
- data.client.move(_cascade_x, _cascade_y)
- frame_size = data.client.frame.size()
- _cascade_x += frame_size.top
- _cascade_y += frame_size.top
-
-export_functions = random, cascade
-
-print "Loaded windowplacement.py"
+++ /dev/null
-Makefile
-Makefile.in
-openbox3
-.deps
-.libs
+++ /dev/null
-localedir=$(datadir)/locale
-scriptdir = $(libdir)/openbox/python
-DEFAULT_MENU=$(pkgdatadir)/menu
-DEFAULT_STYLE=$(pkgdatadir)/styles/mbdtex
-
-CPPFLAGS=$(XFT_CFLAGS) $(PYTHON_CFLAGS) @CPPFLAGS@ \
--DDEFAULTMENU=\"$(DEFAULT_MENU)\" \
--DDEFAULTSTYLE=\"$(DEFAULT_STYLE)\" \
--DLOCALEDIR=\"$(localedir)\" \
--DSCRIPTDIR=\"$(scriptdir)\"
-
-LIBS=$(XFT_LIBS) $(PYTHON_LIBS) @LIBS@ $(SWIG_PYTHON_LIB)
-
-bin_PROGRAMS= openbox3
-
-openbox3_LDADD=-L../otk -lotk @LIBINTL@
-openbox3_LDFLAGS=-export-dynamic
-openbox3_SOURCES= actions.cc client.cc frame.cc openbox.cc screen.cc \
- main.cc python.cc bindings.cc config.cc
-noinst_HEADERS= actions.hh bindings.hh client.hh frame.hh openbox.hh \
- python.hh screen.hh config.hh
-
-MAINTAINERCLEANFILES= Makefile.in
-
-distclean-local:
- $(RM) *\~ *.orig *.rej .\#*
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "actions.hh"
-#include "openbox.hh"
-#include "client.hh"
-#include "frame.hh"
-#include "screen.hh"
-#include "python.hh"
-#include "bindings.hh"
-#include "otk/display.hh"
-
-#include <cstdio>
-#include <algorithm>
-
-namespace ob {
-
-Actions::Actions()
- : _dragging(false)
-{
-}
-
-
-Actions::~Actions()
-{
-}
-
-
-void Actions::buttonPressHandler(const XButtonEvent &e)
-{
- otk::EventHandler::buttonPressHandler(e);
-
- MouseContext::MC context;
- EventHandler *h = openbox->findHandler(e.window);
- Frame *f = dynamic_cast<Frame*>(h);
- if (f)
- context= f->mouseContext(e.window);
- else if (dynamic_cast<Client*>(h))
- context = MouseContext::Window;
- else if (dynamic_cast<Screen*>(h))
- context = MouseContext::Root;
- else
- return; // not a valid mouse context
-
- if (_press.button) {
- unsigned int mask;
- switch(_press.button) {
- case Button1: mask = Button1Mask; break;
- case Button2: mask = Button2Mask; break;
- case Button3: mask = Button3Mask; break;
- case Button4: mask = Button4Mask; break;
- case Button5: mask = Button5Mask; break;
- default: mask = 0; // on other buttons we have to assume its not pressed...
- }
- // was the button released but we didnt get the event? (pointergrabs cause
- // this)
- if (!(e.state & mask))
- _press.button = 0;
- }
-
- // run the PRESS python hook
- // kill off the Button1Mask etc, only want the modifiers
- unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
- Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
- int screen;
- Client *c = openbox->findClient(e.window);
- if (c)
- screen = c->screen();
- else
- screen = otk::display->findScreen(e.root)->screen();
- MouseData data(screen, c, e.time, state, e.button, context,
- MouseAction::Press);
- openbox->bindings()->fireButton(&data);
-
- if (_press.button) return; // won't count toward CLICK events
-
- _press.win = e.window;
- _press.button = e.button;
- _press.pos = otk::Point(e.x_root, e.y_root);
- if (c)
- _press.clientarea = c->area();
-
- printf("press queue %u pressed %u\n", _press.button, e.button);
-
- if (context == MouseContext::Window) {
- /*
- Because of how events are grabbed on the client window, we can't get
- ButtonRelease events, so instead we simply manufacture them here, so that
- clicks/doubleclicks etc still work.
- */
- //XButtonEvent ev = e;
- //ev.type = ButtonRelease;
- buttonReleaseHandler(e);
- }
-}
-
-
-void Actions::buttonReleaseHandler(const XButtonEvent &e)
-{
- otk::EventHandler::buttonReleaseHandler(e);
-
- MouseContext::MC context;
- EventHandler *h = openbox->findHandler(e.window);
- Frame *f = dynamic_cast<Frame*>(h);
- if (f)
- context= f->mouseContext(e.window);
- else if (dynamic_cast<Client*>(h))
- context = MouseContext::Window;
- else if (dynamic_cast<Screen*>(h))
- context = MouseContext::Root;
- else
- return; // not a valid mouse context
-
- // run the RELEASE python hook
- // kill off the Button1Mask etc, only want the modifiers
- unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
- Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
- int screen;
- Client *c = openbox->findClient(e.window);
- if (c)
- screen = c->screen();
- else
- screen = otk::display->findScreen(e.root)->screen();
- MouseData data(screen, c, e.time, state, e.button, context,
- MouseAction::Release);
- openbox->bindings()->fireButton(&data);
-
- // not for the button we're watching?
- if (_press.button != e.button) return;
-
- _press.button = 0;
- _dragging = false;
-
- // find the area of the window
- XWindowAttributes attr;
- if (!XGetWindowAttributes(**otk::display, e.window, &attr)) return;
-
- // if not on the window any more, it isnt a CLICK
- if (!(e.same_screen && e.x >= 0 && e.y >= 0 &&
- e.x < attr.width && e.y < attr.height))
- return;
-
- // run the CLICK python hook
- data.action = MouseAction::Click;
- openbox->bindings()->fireButton(&data);
-
- long dblclick = 0;
- python_get_long("double_click_delay", &dblclick);
- if (e.time - _release.time < (unsigned)dblclick &&
- _release.win == e.window && _release.button == e.button) {
-
- // run the DOUBLECLICK python hook
- data.action = MouseAction::DoubleClick;
- openbox->bindings()->fireButton(&data);
-
- // reset so you cant triple click for 2 doubleclicks
- _release.win = 0;
- _release.button = 0;
- _release.time = 0;
- } else {
- // save the button release, might be part of a double click
- _release.win = e.window;
- _release.button = e.button;
- _release.time = e.time;
- }
-}
-
-
-void Actions::enterHandler(const XCrossingEvent &e)
-{
- otk::EventHandler::enterHandler(e);
-
- // run the ENTER python hook
- int screen;
- Client *c = openbox->findClient(e.window);
- if (c)
- screen = c->screen();
- else
- screen = otk::display->findScreen(e.root)->screen();
- EventData data(screen, c, EventAction::EnterWindow, e.state);
- openbox->bindings()->fireEvent(&data);
-}
-
-
-void Actions::leaveHandler(const XCrossingEvent &e)
-{
- otk::EventHandler::leaveHandler(e);
-
- // run the LEAVE python hook
- int screen;
- Client *c = openbox->findClient(e.window);
- if (c)
- screen = c->screen();
- else
- screen = otk::display->findScreen(e.root)->screen();
- EventData data(screen, c, EventAction::LeaveWindow, e.state);
- openbox->bindings()->fireEvent(&data);
-}
-
-
-void Actions::keyPressHandler(const XKeyEvent &e)
-{
- otk::EventHandler::keyPressHandler(e);
-
- // kill off the Button1Mask etc, only want the modifiers
- unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
- Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
-
- // add to the state the mask of the modifier being pressed, if it is
- // a modifier key being pressed (this is a little ugly..)
- const XModifierKeymap *map = otk::display->modifierMap();
- const int mask_table[] = {
- ShiftMask, LockMask, ControlMask, Mod1Mask,
- Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
- };
- KeyCode *kp = map->modifiermap;
- for (int i = 0, n = sizeof(mask_table)/sizeof(mask_table[0]); i < n; ++i) {
- for (int k = 0; k < map->max_keypermod; ++k) {
- if (*kp == e.keycode) { // found the keycode
- state |= mask_table[i]; // add the mask for it
- i = n; // cause the first loop to break;
- break; // get outta here!
- }
- ++kp;
- }
- }
-
- openbox->bindings()->
- fireKey(otk::display->findScreen(e.root)->screen(),
- state, e.keycode, e.time, KeyAction::Press);
-}
-
-
-void Actions::keyReleaseHandler(const XKeyEvent &e)
-{
- otk::EventHandler::keyReleaseHandler(e);
-
- // kill off the Button1Mask etc, only want the modifiers
- unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
- Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
-
- // remove from the state the mask of the modifier being released, if it is
- // a modifier key being released (this is a little ugly..)
- const XModifierKeymap *map = otk::display->modifierMap();
- const int mask_table[] = {
- ShiftMask, LockMask, ControlMask, Mod1Mask,
- Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
- };
- KeyCode *kp = map->modifiermap;
- for (int i = 0, n = sizeof(mask_table)/sizeof(mask_table[0]); i < n; ++i) {
- for (int k = 0; k < map->max_keypermod; ++k) {
- if (*kp == e.keycode) { // found the keycode
- state &= ~mask_table[i]; // remove the mask for it
- i = n; // cause the first loop to break;
- break; // get outta here!
- }
- ++kp;
- }
- }
-
- openbox->bindings()->
- fireKey(otk::display->findScreen(e.root)->screen(),
- state, e.keycode, e.time, KeyAction::Release);
-}
-
-
-void Actions::motionHandler(const XMotionEvent &e)
-{
- otk::EventHandler::motionHandler(e);
-
- if (!e.same_screen) return; // this just gets stupid
-
- if (e.window != _press.win) return;
-
- MouseContext::MC context;
- EventHandler *h = openbox->findHandler(e.window);
- Frame *f = dynamic_cast<Frame*>(h);
- if (f)
- context= f->mouseContext(e.window);
- else if (dynamic_cast<Client*>(h))
- context = MouseContext::Window;
- else if (dynamic_cast<Screen*>(h))
- context = MouseContext::Root;
- else
- return; // not a valid mouse context
-
- int x_root = e.x_root, y_root = e.y_root;
-
- // compress changes to a window into a single change
- XEvent ce;
- while (XCheckTypedWindowEvent(**otk::display, e.window, e.type, &ce)) {
- x_root = ce.x_root;
- y_root = ce.y_root;
- }
-
- int screen;
- Client *c = openbox->findClient(e.window);
- if (c)
- screen = c->screen();
- else
- screen = otk::display->findScreen(e.root)->screen();
-
- if (!_dragging) {
- int dx = x_root - _press.pos.x();
- int dy = y_root - _press.pos.y();
- long threshold = 0;
- python_get_long("drag_threshold", &threshold);
- if (!(std::abs(dx) >= threshold || std::abs(dy) >= threshold))
- return; // not at the threshold yet
- }
- _dragging = true; // in a drag now
-
- // check if the movement is more than the threshold
-
- // run the MOTION python hook
- // kill off the Button1Mask etc, only want the modifiers
- unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
- Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
- unsigned int button = _press.button;
- MouseData data(screen, c, e.time, state, button, context,
- MouseAction::Motion, x_root, y_root,
- _press.pos, _press.clientarea);
- openbox->bindings()->fireButton(&data);
-}
-
-#ifdef XKB
-void Actions::xkbHandler(const XkbEvent &e)
-{
- Window w;
- int screen;
-
- otk::EventHandler::xkbHandler(e);
-
- switch (((XkbAnyEvent*)&e)->xkb_type) {
- case XkbBellNotify:
- w = ((XkbBellNotifyEvent*)&e)->window;
- Client *c = openbox->findClient(w);
- if (c)
- screen = c->screen();
- else
- screen = openbox->focusedScreen()->number();
- EventData data(screen, c, EventAction::Bell, 0);
- openbox->bindings()->fireEvent(&data);
- break;
- }
-}
-#endif // XKB
-
-}
-
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __actions_hh
-#define __actions_hh
-
-/*! @file actions.hh
- @brief The action interface for user-available actions
-*/
-
-#include "otk/point.hh"
-#include "otk/rect.hh"
-#include "otk/eventhandler.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-#include <Python.h>
-}
-
-#include <map>
-
-namespace ob {
-
-//! The action interface for user-available actions
-/*!
- When these actions are fired, hooks to the guile engine are fired so that
- guile code is run.
-*/
-class Actions : public otk::EventHandler {
-public:
-#ifndef SWIG // get rid of a swig warning
- struct ButtonReleaseAction {
- Window win;
- unsigned int button;
- Time time;
- ButtonReleaseAction() { win = 0; button = 0; time = 0; }
- };
-
- struct ButtonPressAction {
- Window win;
- unsigned int button;
- otk::Point pos;
- otk::Rect clientarea;
- ButtonPressAction() { button = 0; }
- };
-#endif // SWIG
-private:
- //! The last button release processed for CLICKs
- ButtonReleaseAction _release;
- //! The last button press processed for CLICKs
- ButtonPressAction _press;
- //! This is set to true once a drag has started and false when done to make
- //! sure the threshold isnt checked anymore once a drag is underway
- bool _dragging;
-
-public:
- //! Constructs an Actions object
- Actions();
- //! Destroys the Actions object
- virtual ~Actions();
-
- virtual void buttonPressHandler(const XButtonEvent &e);
- virtual void buttonReleaseHandler(const XButtonEvent &e);
-
- virtual void enterHandler(const XCrossingEvent &e);
- virtual void leaveHandler(const XCrossingEvent &e);
-
- virtual void keyPressHandler(const XKeyEvent &e);
- virtual void keyReleaseHandler(const XKeyEvent &e);
-
- virtual void motionHandler(const XMotionEvent &e);
-
-#ifdef XKB
- virtual void xkbHandler(const XkbEvent &e);
-#endif // XKB
-
-};
-
-}
-
-#endif // __actions_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "bindings.hh"
-#include "screen.hh"
-#include "openbox.hh"
-#include "client.hh"
-#include "frame.hh"
-#include "otk/display.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-
-#include "gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstdlib>
-#include <algorithm>
-
-namespace ob {
-
-static bool buttonvalue(const std::string &button, unsigned int *val)
-{
- if (button == "Left")
- *val = 1;
- else if (button == "Middle")
- *val = 2;
- else if (button == "Right")
- *val = 3;
- else if (button == "Up")
- *val = 4;
- else if (button == "Down")
- *val = 5;
- else {
- // try convert to number
- int i = atoi(button.c_str());
- if (i <= 0)
- return false;
- *val = i;
- }
- return true;
-}
-
-static bool modvalue(const std::string &mod, unsigned int *val)
-{
- if (mod == "C") { // control
- *val |= ControlMask;
- } else if (mod == "S") { // shift
- *val |= ShiftMask;
- } else if (mod == "A" || // alt/mod1
- mod == "M" ||
- mod == "Mod1" ||
- mod == "M1") {
- *val |= Mod1Mask;
- } else if (mod == "Mod2" || // mod2
- mod == "M2") {
- *val |= Mod2Mask;
- } else if (mod == "Mod3" || // mod3
- mod == "M3") {
- *val |= Mod3Mask;
- } else if (mod == "W" || // windows/mod4
- mod == "Mod4" ||
- mod == "M4") {
- *val |= Mod4Mask;
- } else if (mod == "Mod5" || // mod5
- mod == "M5") {
- *val |= Mod5Mask;
- } else { // invalid
- return false;
- }
- return true;
-}
-
-bool Bindings::translate(const std::string &str, Binding &b,bool askey) const
-{
- // parse out the base key name
- std::string::size_type keybegin = str.find_last_of('-');
- keybegin = (keybegin == std::string::npos) ? 0 : keybegin + 1;
- std::string key(str, keybegin);
-
- // parse out the requested modifier keys
- unsigned int modval = 0;
- std::string::size_type begin = 0, end;
- while (begin != keybegin) {
- end = str.find_first_of('-', begin);
-
- std::string mod(str, begin, end-begin);
- if (!modvalue(mod, &modval)) {
- printf(_("Invalid modifier element in key binding: %s\n"), mod.c_str());
- return false;
- }
-
- begin = end + 1;
- }
-
- // set the binding
- b.modifiers = modval;
- if (askey) {
- KeySym sym = XStringToKeysym(const_cast<char *>(key.c_str()));
- if (sym == NoSymbol) {
- printf(_("Invalid Key name in key binding: %s\n"), key.c_str());
- return false;
- }
- if (!(b.key = XKeysymToKeycode(**otk::display, sym)))
- printf(_("No valid keycode for Key in key binding: %s\n"), key.c_str());
- return b.key != 0;
- } else {
- return buttonvalue(key, &b.key);
- }
-}
-
-static void destroytree(KeyBindingTree *tree)
-{
- while (tree) {
- KeyBindingTree *c = tree->first_child;
- delete tree;
- tree = c;
- }
-}
-
-KeyBindingTree *Bindings::buildtree(const StringVect &keylist,
- KeyCallback callback, void *data) const
-{
- if (keylist.empty()) return 0; // nothing in the list.. return 0
-
- KeyBindingTree *ret = 0, *p;
-
- StringVect::const_reverse_iterator it, end = keylist.rend();
- for (it = keylist.rbegin(); it != end; ++it) {
- p = ret;
- ret = new KeyBindingTree();
- if (!p) {
- // this is the first built node, the bottom node of the tree
- ret->chain = false;
- ret->callbacks.push_back(KeyCallbackData(callback, data));
- }
- ret->first_child = p;
- if (!translate(*it, ret->binding)) {
- destroytree(ret);
- ret = 0;
- break;
- }
- }
- return ret;
-}
-
-
-Bindings::Bindings()
- : _curpos(&_keytree),
- _resetkey(0,0),
- _timer((otk::Timer *) 0),
- _keybgrab_callback(0, 0),
- _grabbed(0)
-{
- setResetKey("C-g"); // set the default reset key
-}
-
-
-Bindings::~Bindings()
-{
- if (_timer)
- delete _timer;
- if (_grabbed) {
- _grabbed = false;
- XUngrabKeyboard(**otk::display, CurrentTime);
- }
- removeAllKeys();
- //removeAllButtons(); // this is done by each client as they are unmanaged
- removeAllEvents();
-}
-
-
-void Bindings::assimilate(KeyBindingTree *node)
-{
- KeyBindingTree *a, *b, *tmp, *last;
-
- if (!_keytree.first_child) {
- // there are no nodes at this level yet
- _keytree.first_child = node;
- } else {
- a = _keytree.first_child;
- last = a;
- b = node;
- while (a) {
- last = a;
- if (a->binding != b->binding) {
- a = a->next_sibling;
- } else {
- tmp = b;
- b = b->first_child;
- delete tmp;
- a = a->first_child;
- }
- }
- if (last->binding != b->binding)
- last->next_sibling = b;
- else {
- last->first_child = b->first_child;
- delete b;
- }
- }
-}
-
-
-KeyBindingTree *Bindings::find(KeyBindingTree *search,
- bool *conflict) const {
- *conflict = false;
- KeyBindingTree *a, *b;
- a = _keytree.first_child;
- b = search;
- while (a && b) {
- if (a->binding != b->binding) {
- a = a->next_sibling;
- } else {
- if (a->chain == b->chain) {
- if (!a->chain) {
- // found it! (return the actual id, not the search's)
- return a;
- }
- } else {
- *conflict = true;
- return 0; // the chain status' don't match (conflict!)
- }
- b = b->first_child;
- a = a->first_child;
- }
- }
- return 0; // it just isn't in here
-}
-
-
-bool Bindings::addKey(const StringVect &keylist, KeyCallback callback,
- void *data)
-{
- KeyBindingTree *tree, *t;
- bool conflict;
-
- if (!(tree = buildtree(keylist, callback, data)))
- return false; // invalid binding requested
-
- t = find(tree, &conflict);
- if (conflict) {
- // conflicts with another binding
- destroytree(tree);
- return false;
- }
-
- if (t) {
- // already bound to something
- t->callbacks.push_back(KeyCallbackData(callback, data));
- destroytree(tree);
- } else {
- // grab the server here to make sure no key pressed go missed
- otk::display->grab();
- grabKeys(false);
-
- // assimilate this built tree into the main tree
- assimilate(tree); // assimilation destroys/uses the tree
-
- grabKeys(true);
- otk::display->ungrab();
- }
-
- return true;
-}
-
-/*
-bool Bindings::removeKey(const StringVect &keylist, KeyCallback callback, void *data)
-{
- assert(false); // XXX: function not implemented yet
-
- KeyBindingTree *tree;
- bool conflict;
-
- if (!(tree = buildtree(keylist, 0)))
- return false; // invalid binding requested
-
- KeyBindingTree *t = find(tree, &conflict);
- if (t) {
- KeyCallbackList::iterator it = std::find(t->callbacks.begin(),
- t->callbacks.end(),
- callback);
- if (it != t->callbacks.end()) {
- // grab the server here to make sure no key pressed go missed
- otk::display->grab();
- grabKeys(false);
-
- _curpos = &_keytree;
-
- // XXX do shit here ...
- Py_XDECREF(*it);
-
- grabKeys(true);
- otk::display->ungrab();
-
- return true;
- }
- }
- return false;
-}
-*/
-
-void Bindings::setResetKey(const std::string &key)
-{
- Binding b(0, 0);
- if (translate(key, b)) {
- _resetkey.key = b.key;
- _resetkey.modifiers = b.modifiers;
- }
-}
-
-
-static void remove_branch(KeyBindingTree *first)
-{
- KeyBindingTree *p = first;
-
- while (p) {
- if (p->first_child)
- remove_branch(p->first_child);
- KeyBindingTree *s = p->next_sibling;
- while(!p->callbacks.empty()) {
- p->callbacks.pop_front();
- }
- delete p;
- p = s;
- }
-}
-
-
-void Bindings::removeAllKeys()
-{
- grabKeys(false);
- if (_keytree.first_child) {
- remove_branch(_keytree.first_child);
- _keytree.first_child = 0;
- }
- grabKeys(true);
-}
-
-
-void Bindings::grabKeys(bool grab)
-{
- for (int i = 0; i < ScreenCount(**otk::display); ++i) {
- Screen *sc = openbox->screen(i);
- if (!sc) continue; // not a managed screen
- Window root = otk::display->screenInfo(i)->rootWindow();
- if (!grab) {
- otk::display->ungrabAllKeys(root);
- continue;
- }
- KeyBindingTree *p = _keytree.first_child;
- while (p) {
- otk::display->grabKey(p->binding.key, p->binding.modifiers,
- root, false, GrabModeAsync, GrabModeSync,
- false);
- p = p->next_sibling;
- }
- }
-}
-
-
-bool Bindings::grabKeyboard(int screen, KeyCallback callback, void *data)
-{
- assert(callback);
- if (_keybgrab_callback.callback) return false; // already grabbed
-
- if (!openbox->screen(screen))
- return false; // the screen is not managed
-
- Window root = otk::display->screenInfo(screen)->rootWindow();
- if (XGrabKeyboard(**otk::display, root, false, GrabModeAsync,
- GrabModeAsync, CurrentTime))
- return false;
- _keybgrab_callback.callback = callback;
- _keybgrab_callback.data = data;
- return true;
-}
-
-
-void Bindings::ungrabKeyboard()
-{
- if (!_keybgrab_callback.callback) return; // not grabbed
-
- _keybgrab_callback = KeyCallbackData(0, 0);
- if (!_grabbed) /* don't release out from under keychains */
- XUngrabKeyboard(**otk::display, CurrentTime);
- XUngrabPointer(**otk::display, CurrentTime);
-}
-
-
-bool Bindings::grabPointer(int screen)
-{
- if (!openbox->screen(screen))
- return false; // the screen is not managed
-
- Window root = otk::display->screenInfo(screen)->rootWindow();
- XGrabPointer(**otk::display, root, false, 0, GrabModeAsync,
- GrabModeAsync, None, None, CurrentTime);
- return true;
-}
-
-
-void Bindings::ungrabPointer()
-{
- XUngrabPointer(**otk::display, CurrentTime);
-}
-
-
-void Bindings::fireKey(int screen, unsigned int modifiers, unsigned int key,
- Time time, KeyAction::KA action)
-{
- if (_keybgrab_callback.callback) {
- Client *c = openbox->focusedClient();
- KeyData data(screen, c, time, modifiers, key, action);
- _keybgrab_callback.fire(&data);
- }
-
- // KeyRelease events only occur during keyboard grabs
- if (action == KeyAction::Release) return;
-
- if (key == _resetkey.key && modifiers == _resetkey.modifiers) {
- resetChains(this);
- XAllowEvents(**otk::display, AsyncKeyboard, CurrentTime);
- } else {
- KeyBindingTree *p = _curpos->first_child;
- while (p) {
- if (p->binding.key == key && p->binding.modifiers == modifiers) {
- if (p->chain) {
- if (_timer)
- delete _timer;
- _timer = new otk::Timer(5000, // 5 second timeout
- (otk::Timer::TimeoutHandler)resetChains,
- this);
- if (!_grabbed && !_keybgrab_callback.callback) {
- Window root = otk::display->screenInfo(screen)->rootWindow();
- //grab should never fail because we should have a sync grab at
- //this point
- XGrabKeyboard(**otk::display, root, 0, GrabModeAsync,
- GrabModeSync, CurrentTime);
- }
- _grabbed = true;
- _curpos = p;
- XAllowEvents(**otk::display, AsyncKeyboard, CurrentTime);
- } else {
- Client *c = openbox->focusedClient();
- KeyData data(screen, c, time, modifiers, key, action);
- KeyCallbackList::iterator it, end = p->callbacks.end();
- for (it = p->callbacks.begin(); it != end; ++it)
- it->fire(&data);
- XAllowEvents(**otk::display, AsyncKeyboard, CurrentTime);
- resetChains(this);
- }
- break;
- }
- p = p->next_sibling;
- }
- }
-}
-
-void Bindings::resetChains(Bindings *self)
-{
- if (self->_timer) {
- delete self->_timer;
- self->_timer = (otk::Timer *) 0;
- }
- self->_curpos = &self->_keytree;
- if (self->_grabbed) {
- self->_grabbed = false;
- if (!self->_keybgrab_callback.callback)
- XUngrabKeyboard(**otk::display, CurrentTime);
- }
-}
-
-
-bool Bindings::addButton(const std::string &but, MouseContext::MC context,
- MouseAction::MA action, MouseCallback callback,
- void *data)
-{
- assert(context >= 0 && context < MouseContext::NUM_MOUSE_CONTEXT);
- assert(action >= 0 && action < MouseAction::NUM_MOUSE_ACTION);
-
- Binding b(0,0);
- if (!translate(but, b, false))
- return false;
-
- ButtonBindingList::iterator it, end = _buttons[context].end();
-
- // look for a duplicate binding
- for (it = _buttons[context].begin(); it != end; ++it)
- if ((*it)->binding.key == b.key &&
- (*it)->binding.modifiers == b.modifiers) {
- break;
- }
-
- ButtonBinding *bind;
-
- // the binding didnt exist yet, add it
- if (it == end) {
- bind = new ButtonBinding();
- bind->binding.key = b.key;
- bind->binding.modifiers = b.modifiers;
- _buttons[context].push_back(bind);
- // grab the button on all clients
- for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
- Screen *s = openbox->screen(sn);
- if (!s) continue; // not managed
- Client::List::iterator c_it, c_end = s->clients.end();
- for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
- grabButton(true, bind->binding, context, *c_it);
- }
- }
- } else
- bind = *it;
- bind->callbacks[action].push_back(MouseCallbackData(callback, data));
- return true;
-}
-
-void Bindings::removeAllButtons()
-{
- for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
- ButtonBindingList::iterator it, end = _buttons[i].end();
- for (it = _buttons[i].begin(); it != end; ++it) {
- for (int a = 0; a < MouseAction::NUM_MOUSE_ACTION; ++a) {
- while (!(*it)->callbacks[a].empty()) {
- (*it)->callbacks[a].pop_front();
- }
- }
- // ungrab the button on all clients
- for (int sn = 0; sn < ScreenCount(**otk::display); ++sn) {
- Screen *s = openbox->screen(sn);
- if (!s) continue; // not managed
- Client::List::iterator c_it, c_end = s->clients.end();
- for (c_it = s->clients.begin(); c_it != c_end; ++c_it) {
- grabButton(false, (*it)->binding, (MouseContext::MC)i, *c_it);
- }
- }
- }
- }
-}
-
-void Bindings::grabButton(bool grab, const Binding &b,
- MouseContext::MC context, Client *client)
-{
- Window win;
- int mode = GrabModeAsync;
- unsigned int mask;
- switch(context) {
- case MouseContext::Frame:
- win = client->frame->window();
- mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
- break;
- case MouseContext::Window:
- win = client->frame->plate();
- mode = GrabModeSync; // this is handled in fireButton
- mask = ButtonPressMask; // can't catch more than this with Sync mode
- // the release event is manufactured by the
- // master buttonPressHandler
- break;
- default:
- // any other elements already get button events, don't grab on them
- return;
- }
- if (grab)
- otk::display->grabButton(b.key, b.modifiers, win, false, mask, mode,
- GrabModeAsync, None, None, false);
- else
- otk::display->ungrabButton(b.key, b.modifiers, win);
-}
-
-void Bindings::grabButtons(bool grab, Client *client)
-{
- for (int i = 0; i < MouseContext::NUM_MOUSE_CONTEXT; ++i) {
- ButtonBindingList::iterator it, end = _buttons[i].end();
- for (it = _buttons[i].begin(); it != end; ++it)
- grabButton(grab, (*it)->binding, (MouseContext::MC)i, client);
- }
-}
-
-void Bindings::fireButton(MouseData *data)
-{
- if (data->context == MouseContext::Window) {
- // Replay the event, so it goes to the client
- XAllowEvents(**otk::display, ReplayPointer, data->time);
- }
-
- ButtonBindingList::iterator it, end = _buttons[data->context].end();
- for (it = _buttons[data->context].begin(); it != end; ++it)
- if ((*it)->binding.key == data->button &&
- (*it)->binding.modifiers == data->state) {
- MouseCallbackList::iterator c_it,
- c_end = (*it)->callbacks[data->action].end();
- for (c_it = (*it)->callbacks[data->action].begin();
- c_it != c_end; ++c_it)
- c_it->fire(data);
- }
-}
-
-
-bool Bindings::addEvent(EventAction::EA action, EventCallback callback,
- void *data)
-{
- if (action < 0 || action >= EventAction::NUM_EVENT_ACTION) {
- return false;
- }
-#ifdef XKB
- if (action == EventAction::Bell && _eventlist[action].empty())
- XkbSelectEvents(**otk::display, XkbUseCoreKbd,
- XkbBellNotifyMask, XkbBellNotifyMask);
-#endif // XKB
- _eventlist[action].push_back(EventCallbackData(callback, data));
- return true;
-}
-
-bool Bindings::removeEvent(EventAction::EA action, EventCallback callback,
- void *data)
-{
- if (action < 0 || action >= EventAction::NUM_EVENT_ACTION) {
- return false;
- }
-
- EventCallbackList::iterator it = std::find(_eventlist[action].begin(),
- _eventlist[action].end(),
- EventCallbackData(callback,
- data));
- if (it != _eventlist[action].end()) {
- _eventlist[action].erase(it);
-#ifdef XKB
- if (action == EventAction::Bell && _eventlist[action].empty())
- XkbSelectEvents(**otk::display, XkbUseCoreKbd,
- XkbBellNotifyMask, 0);
-#endif // XKB
- return true;
- }
- return false;
-}
-
-void Bindings::removeAllEvents()
-{
- for (int i = 0; i < EventAction::NUM_EVENT_ACTION; ++i) {
- while (!_eventlist[i].empty()) {
- _eventlist[i].pop_front();
- }
- }
-}
-
-void Bindings::fireEvent(EventData *data)
-{
- EventCallbackList::iterator c_it, c_end = _eventlist[data->action].end();
- for (c_it = _eventlist[data->action].begin(); c_it != c_end; ++c_it)
- c_it->fire(data);
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __binding_hh
-#define __binding_hh
-
-/*! @file bindings.hh
- @brief I dunno.. some binding stuff?
-*/
-
-#include "actions.hh"
-#include "python.hh"
-#include "otk/timer.hh"
-
-#include <string>
-#include <list>
-#include <vector>
-
-namespace ob {
-
-class Client;
-
-struct MouseCallbackData {
- MouseCallback callback;
- void *data;
- MouseCallbackData(MouseCallback c, void *d) : callback(c), data(d) {}
- void fire(MouseData *d) { callback(d, data); }
- bool operator==(const MouseCallbackData &other) { return (callback ==
- other.callback &&
- data ==
- other.data); }
-};
-
-struct KeyCallbackData {
- KeyCallback callback;
- void *data;
- KeyCallbackData(KeyCallback c, void *d) : callback(c), data(d) {}
- void fire(KeyData *d) { callback(d, data); }
- bool operator==(const KeyCallbackData &other) { return (callback ==
- other.callback &&
- data ==
- other.data); }
-};
-
-struct EventCallbackData {
- EventCallback callback;
- void *data;
- EventCallbackData(EventCallback c, void *d) : callback(c), data(d) {}
- void fire(EventData *d) { callback(d, data); }
- bool operator==(const EventCallbackData &other) { return (callback ==
- other.callback &&
- data ==
- other.data); }
-};
-
-typedef std::list<MouseCallbackData> MouseCallbackList;
-typedef std::list<KeyCallbackData> KeyCallbackList;
-typedef std::list<EventCallbackData> EventCallbackList;
-
-typedef struct Binding {
- unsigned int modifiers;
- unsigned int key;
-
- bool operator==(struct Binding &b2) { return key == b2.key &&
- modifiers == b2.modifiers; }
- bool operator!=(struct Binding &b2) { return key != b2.key ||
- modifiers != b2.modifiers; }
- Binding(unsigned int mod, unsigned int k) { modifiers = mod; key = k; }
-} Binding;
-
-typedef struct KeyBindingTree {
- Binding binding;
- KeyCallbackList callbacks; // the callbacks given for the binding in add()
- bool chain; // true if this is a chain to another key (not an action)
-
- struct KeyBindingTree *next_sibling; // the next binding in the tree at the same
- // level
- struct KeyBindingTree *first_child; // the first child of this binding (next
- // binding in a chained sequence).
- KeyBindingTree() : binding(0, 0) {
- chain = true; next_sibling = first_child = 0;
- }
-} KeyBindingTree;
-
-typedef struct ButtonBinding {
- Binding binding;
- MouseCallbackList callbacks[MouseAction::NUM_MOUSE_ACTION];
- ButtonBinding() : binding(0, 0) {}
-};
-
-class Bindings {
-public:
- //! A list of strings
- typedef std::vector<std::string> StringVect;
-
-private:
- // root node of the tree (this doesn't have siblings!)
- KeyBindingTree _keytree;
- KeyBindingTree *_curpos; // position in the keytree
-
- Binding _resetkey; // the key which resets the key chain status
-
- otk::Timer *_timer;
-
- KeyBindingTree *find(KeyBindingTree *search, bool *conflict) const;
- KeyBindingTree *buildtree(const StringVect &keylist,
- KeyCallback callback, void *data) const;
- void assimilate(KeyBindingTree *node);
-
- static void resetChains(Bindings *self); // the timer's timeout function
-
- typedef std::list <ButtonBinding*> ButtonBindingList;
- ButtonBindingList _buttons[MouseContext::NUM_MOUSE_CONTEXT];
-
- void grabButton(bool grab, const Binding &b, MouseContext::MC context,
- Client *client);
-
- EventCallbackList _eventlist[EventAction::NUM_EVENT_ACTION];
-
- KeyCallbackData _keybgrab_callback;
-
- bool _grabbed;
-
-public:
- //! Initializes an Bindings object
- Bindings();
- //! Destroys the Bindings object
- virtual ~Bindings();
-
- //! Translates a binding string into the actual Binding
- bool translate(const std::string &str, Binding &b, bool askey = true) const;
-
- //! Adds a new key binding
- /*!
- A binding will fail to be added if the binding already exists (as part of
- a chain or not), or if any of the strings in the keylist are invalid.
- @return true if the binding could be added; false if it could not.
- */
- bool addKey(const StringVect &keylist, KeyCallback callback, void *data);
-
- ////! Removes a key binding
- ///*!
- // @return The callbackid of the binding, or '< 0' if there was no binding to
- // be removed.
- //*/
- //bool removeKey(const StringVect &keylist, KeyCallback callback, void *data);
-
- //! Removes all key bindings
- void removeAllKeys();
-
- void fireKey(int screen, unsigned int modifiers,unsigned int key, Time time,
- KeyAction::KA action);
-
- void setResetKey(const std::string &key);
-
- void grabKeys(bool grab);
-
- bool grabKeyboard(int screen, KeyCallback callback, void *data);
- void ungrabKeyboard();
-
- bool grabPointer(int screen);
- void ungrabPointer();
-
- bool addButton(const std::string &but, MouseContext::MC context,
- MouseAction::MA action, MouseCallback callback, void *data);
-
- void grabButtons(bool grab, Client *client);
-
- //! Removes all button bindings
- void removeAllButtons();
-
- void fireButton(MouseData *data);
-
- //! Bind a callback for an event
- bool addEvent(EventAction::EA action, EventCallback callback, void *data);
-
- //! Unbind the callback function from an event
- bool removeEvent(EventAction::EA action, EventCallback callback, void *data);
-
- //! Remove all callback functions
- void removeAllEvents();
-
- void fireEvent(EventData *data);
-};
-
-}
-
-#endif // __binding_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "client.hh"
-#include "frame.hh"
-#include "screen.hh"
-#include "openbox.hh"
-#include "bindings.hh"
-#include "otk/display.hh"
-#include "otk/property.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-
-#include "gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <cstring> // for memcpy
-#include <climits>
-#include <cassert>
-#include <algorithm>
-
-namespace ob {
-
-Client::Client(int screen, Window window)
- : otk::EventHandler(),
- frame(0), _screen(screen), _window(window)
-{
- assert(screen >= 0);
- assert(window);
-
- ignore_unmaps = 0;
-
- // update EVERYTHING the first time!!
-
- // defaults
- _wmstate = NormalState;
- _focused = false;
- _transient_for = 0;
- _layer = Layer_Normal;
- _urgent = false;
- _positioned = false;
- _disabled_decorations = 0;
- _group = None;
- _desktop = 0;
- _nicons = 0;
-
- getArea();
- getDesktop();
- getState(); // do this before updateTransientFor! (for _modal)
- getShaped();
-
- updateTransientFor();
- getMwmHints();
- getType(); // this can change the mwmhints for special cases
-
- updateProtocols();
-
- getGravity(); // get the attribute gravity
- updateNormalHints(); // this may override the attribute gravity
-
- // got the type, the mwmhints, the protocols, and the normal hints (min/max
- // sizes), so we're ready to set up
- // the decorations/functions
- setupDecorAndFunctions();
-
- // also get the initial_state and set _iconic if we aren't "starting"
- // when we're "starting" that means we should use whatever state was already
- // on the window over the initial map state, because it was already mapped
- updateWMHints(openbox->state() != Openbox::State_Starting);
- updateTitle();
- updateIconTitle();
- updateClass();
- updateStrut();
- updateIcons();
- updateKwmIcon();
-
- // this makes sure that these windows appear on all desktops
- if (/*_type == Type_Dock ||*/ _type == Type_Desktop)
- _desktop = 0xffffffff;
-
- // set the desktop hint, to make sure that it always exists, and to reflect
- // any changes we've made here
- otk::Property::set(_window, otk::Property::atoms.net_wm_desktop,
- otk::Property::atoms.cardinal, (unsigned)_desktop);
- changeState();
-}
-
-
-Client::~Client()
-{
- assert(_nicons > 0); // there should always be a default..
- for (int j = 0; j < _nicons; ++j)
- delete [] _icons[j].data;
- delete [] _icons;
-
- // clean up childrens' references
- while (!_transients.empty()) {
- _transients.front()->_transient_for = 0;
- _transients.pop_front();
- }
-
- // clean up parents reference to this
- if (_transient_for)
- _transient_for->_transients.remove(this); // remove from old parent
-
- if (openbox->state() != Openbox::State_Exiting) {
- // these values should not be persisted across a window unmapping/mapping
- otk::Property::erase(_window, otk::Property::atoms.net_wm_desktop);
- otk::Property::erase(_window, otk::Property::atoms.net_wm_state);
- } else {
- // if we're left in an iconic state, the client wont be mapped. this is
- // bad, since we will no longer be managing the window on restart
- if (_iconic)
- XMapWindow(**otk::display, _window);
- }
-}
-
-
-bool Client::validate() const
-{
- XSync(**otk::display, false); // get all events on the server
-
- XEvent e;
- if (XCheckTypedWindowEvent(**otk::display, _window, DestroyNotify, &e) ||
- XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &e)) {
- XPutBackEvent(**otk::display, &e);
- return false;
- }
-
- return true;
-}
-
-
-void Client::getGravity()
-{
- XWindowAttributes wattrib;
- Status ret;
-
- ret = XGetWindowAttributes(**otk::display, _window, &wattrib);
- assert(ret != BadWindow);
- _gravity = wattrib.win_gravity;
-}
-
-
-void Client::getDesktop()
-{
- // defaults to the current desktop
- _desktop = openbox->screen(_screen)->desktop();
- unsigned int d;
-
- if (otk::Property::get(_window, otk::Property::atoms.net_wm_desktop,
- otk::Property::atoms.cardinal,
- (long unsigned*)&d)) {
- if (d >= openbox->screen(_screen)->numDesktops() &&
- d != 0xffffffff)
- d = openbox->screen(_screen)->numDesktops() - 1;
- _desktop = d;
-#ifdef DEBUG
-// printf("Window requested desktop: %ld\n", _desktop);
-#endif
- }
-}
-
-
-void Client::getType()
-{
- _type = (WindowType) -1;
-
- unsigned long *val;
- unsigned long num;
- if (otk::Property::get(_window, otk::Property::atoms.net_wm_window_type,
- otk::Property::atoms.atom, &num, &val)) {
- // use the first value that we know about in the array
- for (unsigned long i = 0; i < num; ++i) {
- if (val[i] == otk::Property::atoms.net_wm_window_type_desktop)
- _type = Type_Desktop;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_dock)
- _type = Type_Dock;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_toolbar)
- _type = Type_Toolbar;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_menu)
- _type = Type_Menu;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_utility)
- _type = Type_Utility;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_splash)
- _type = Type_Splash;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_dialog)
- _type = Type_Dialog;
- else if (val[i] == otk::Property::atoms.net_wm_window_type_normal)
- _type = Type_Normal;
- else if (val[i] == otk::Property::atoms.kde_net_wm_window_type_override){
- // prevent this window from getting any decor or functionality
- _mwmhints.flags &= MwmFlag_Functions | MwmFlag_Decorations;
- _mwmhints.decorations = 0;
- _mwmhints.functions = 0;
- }
- if (_type != (WindowType) -1)
- break; // grab the first known type
- }
- delete val;
- }
-
- if (_type == (WindowType) -1) {
- /*
- * the window type hint was not set, which means we either classify ourself
- * as a normal window or a dialog, depending on if we are a transient.
- */
- if (_transient_for)
- _type = Type_Dialog;
- else
- _type = Type_Normal;
- }
-}
-
-
-void Client::setupDecorAndFunctions()
-{
- // start with everything (cept fullscreen)
- _decorations = Decor_Titlebar | Decor_Handle | Decor_Border | Decor_Icon |
- Decor_AllDesktops | Decor_Iconify | Decor_Maximize;
- _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
- Func_Shade;
- if (_delete_window) {
- _decorations |= Decor_Close;
- _functions |= Func_Close;
- }
-
- if (!(_min_size.width() < _max_size.width() ||
- _min_size.height() < _max_size.height())) {
- _decorations &= ~(Decor_Maximize | Decor_Handle);
- _functions &= ~(Func_Resize | Func_Maximize);
- }
-
- switch (_type) {
- case Type_Normal:
- // normal windows retain all of the possible decorations and
- // functionality, and are the only windows that you can fullscreen
- _functions |= Func_Fullscreen;
- break;
-
- case Type_Dialog:
- // dialogs cannot be maximized
- _decorations &= ~Decor_Maximize;
- _functions &= ~Func_Maximize;
- break;
-
- case Type_Menu:
- case Type_Toolbar:
- case Type_Utility:
- // these windows get less functionality
- _decorations &= ~(Decor_Iconify | Decor_Handle);
- _functions &= ~(Func_Iconify | Func_Resize);
- break;
-
- case Type_Desktop:
- case Type_Dock:
- case Type_Splash:
- // none of these windows are manipulated by the window manager
- _decorations = 0;
- _functions = 0;
- break;
- }
-
- // Mwm Hints are applied subtractively to what has already been chosen for
- // decor and functionality
- if (_mwmhints.flags & MwmFlag_Decorations) {
- if (! (_mwmhints.decorations & MwmDecor_All)) {
- if (! (_mwmhints.decorations & MwmDecor_Border))
- _decorations &= ~Decor_Border;
- if (! (_mwmhints.decorations & MwmDecor_Handle))
- _decorations &= ~Decor_Handle;
- if (! (_mwmhints.decorations & MwmDecor_Title))
- _decorations &= ~Decor_Titlebar;
- if (! (_mwmhints.decorations & MwmDecor_Iconify))
- _decorations &= ~Decor_Iconify;
- if (! (_mwmhints.decorations & MwmDecor_Maximize))
- _decorations &= ~Decor_Maximize;
- }
- }
-
- if (_mwmhints.flags & MwmFlag_Functions) {
- if (! (_mwmhints.functions & MwmFunc_All)) {
- if (! (_mwmhints.functions & MwmFunc_Resize))
- _functions &= ~Func_Resize;
- if (! (_mwmhints.functions & MwmFunc_Move))
- _functions &= ~Func_Move;
- if (! (_mwmhints.functions & MwmFunc_Iconify))
- _functions &= ~Func_Iconify;
- if (! (_mwmhints.functions & MwmFunc_Maximize))
- _functions &= ~Func_Maximize;
- // dont let mwm hints kill the close button
- //if (! (_mwmhints.functions & MwmFunc_Close))
- // _functions &= ~Func_Close;
- }
- }
-
- // can't maximize without moving/resizing
- if (!((_functions & Func_Move) && (_functions & Func_Resize)))
- _functions &= ~Func_Maximize;
-
- // finally, user specified disabled decorations are applied to subtract
- // decorations
- if (_disabled_decorations & Decor_Titlebar)
- _decorations &= ~Decor_Titlebar;
- if (_disabled_decorations & Decor_Handle)
- _decorations &= ~Decor_Handle;
- if (_disabled_decorations & Decor_Border)
- _decorations &= ~Decor_Border;
- if (_disabled_decorations & Decor_Iconify)
- _decorations &= ~Decor_Iconify;
- if (_disabled_decorations & Decor_Maximize)
- _decorations &= ~Decor_Maximize;
- if (_disabled_decorations & Decor_AllDesktops)
- _decorations &= ~Decor_AllDesktops;
- if (_disabled_decorations & Decor_Close)
- _decorations &= ~Decor_Close;
-
- // if we don't have a titlebar, then we cannot shade!
- if (!(_decorations & Decor_Titlebar))
- _functions &= ~Func_Shade;
-
- changeAllowedActions();
-
- if (frame) {
- frame->adjustSize(); // change the decors on the frame
- frame->adjustPosition(); // with more/less decorations, we may need to be
- // moved
- remaximize(); // with new decor, the window's maximized size may change
- }
-}
-
-
-void Client::getMwmHints()
-{
- unsigned long num = MwmHints::elements;
- unsigned long *hints;
-
- _mwmhints.flags = 0; // default to none
-
- if (!otk::Property::get(_window, otk::Property::atoms.motif_wm_hints,
- otk::Property::atoms.motif_wm_hints, &num,
- (unsigned long **)&hints))
- return;
-
- if (num >= MwmHints::elements) {
- // retrieved the hints
- _mwmhints.flags = hints[0];
- _mwmhints.functions = hints[1];
- _mwmhints.decorations = hints[2];
- }
-
- delete [] hints;
-}
-
-
-void Client::getArea()
-{
- XWindowAttributes wattrib;
- Status ret;
-
- ret = XGetWindowAttributes(**otk::display, _window, &wattrib);
- assert(ret != BadWindow);
-
- _area = otk::Rect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
- _border_width = wattrib.border_width;
-}
-
-
-void Client::getState()
-{
- _modal = _shaded = _max_horz = _max_vert = _fullscreen = _above = _below =
- _iconic = _skip_taskbar = _skip_pager = false;
-
- unsigned long *state;
- unsigned long num;
-
- if (otk::Property::get(_window, otk::Property::atoms.net_wm_state,
- otk::Property::atoms.atom, &num, &state)) {
- for (unsigned long i = 0; i < num; ++i) {
- if (state[i] == otk::Property::atoms.net_wm_state_modal)
- _modal = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_shaded)
- _shaded = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_hidden)
- _iconic = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_skip_taskbar)
- _skip_taskbar = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_skip_pager)
- _skip_pager = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_fullscreen)
- _fullscreen = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_maximized_vert)
- _max_vert = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_maximized_horz)
- _max_horz = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_above)
- _above = true;
- else if (state[i] == otk::Property::atoms.net_wm_state_below)
- _below = true;
- }
-
- delete [] state;
- }
-}
-
-void Client::getShaped()
-{
- _shaped = false;
-#ifdef SHAPE
- if (otk::display->shape()) {
- int foo;
- unsigned int ufoo;
- int s;
-
- XShapeSelectInput(**otk::display, _window, ShapeNotifyMask);
-
- XShapeQueryExtents(**otk::display, _window, &s, &foo,
- &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, &ufoo);
- _shaped = (s != 0);
- }
-#endif // SHAPE
-}
-
-Client *Client::searchFocusTree(Client *node, Client *skip)
-{
- List::const_iterator it, end = node->_transients.end();
- Client *ret;
-
- for (it = node->_transients.begin(); it != end; ++it) {
- if (*it == skip) continue; // circular?
- if ((ret = searchModalTree(*it, skip))) return ret; // got one
- if ((*it)->_focused) return *it; // got one
- }
- return 0;
-}
-
-void Client::calcLayer() {
- StackLayer l;
- bool fs = false;
-
- // are we fullscreen, or do we have a fullscreen transient parent?
- Client *c = this;
- while (c) {
- if (c->_fullscreen) {
- fs =true;
- break;
- }
- c = c->_transient_for;
- }
- if (!fs && _fullscreen) {
- // is one of our transients focused?
- c = searchFocusTree(this, this);
- if (c) fs = true;
- }
-
- if (_iconic) l = Layer_Icon;
- else if (fs) l = Layer_Fullscreen;
- else if (_type == Type_Desktop) l = Layer_Desktop;
- else if (_type == Type_Dock) {
- if (!_below) l = Layer_Top;
- else l = Layer_Normal;
- }
- else if (_above) l = Layer_Above;
- else if (_below) l = Layer_Below;
- else l = Layer_Normal;
-
- if (l != _layer) {
- _layer = l;
- if (frame) {
- /*
- if we don't have a frame, then we aren't mapped yet (and this would
- SIGSEGV :)
- */
- openbox->screen(_screen)->raiseWindow(this);
- }
- }
-}
-
-void Client::updateProtocols()
-{
- Atom *proto;
- int num_return = 0;
-
- _focus_notify = false;
- _delete_window = false;
-
- if (XGetWMProtocols(**otk::display, _window, &proto, &num_return)) {
- for (int i = 0; i < num_return; ++i) {
- if (proto[i] == otk::Property::atoms.wm_delete_window) {
- // this means we can request the window to close
- _delete_window = true;
- } else if (proto[i] == otk::Property::atoms.wm_take_focus)
- // if this protocol is requested, then the window will be notified
- // by the window manager whenever it receives focus
- _focus_notify = true;
- }
- XFree(proto);
- }
-}
-
-void Client::updateNormalHints()
-{
- XSizeHints size;
- long ret;
- int oldgravity = _gravity;
-
- // defaults
- _min_ratio = 0.0;
- _max_ratio = 0.0;
- _size_inc = otk::Size(1, 1);
- _base_size = otk::Size(0, 0);
- _min_size = otk::Size(0, 0);
- _max_size = otk::Size(INT_MAX, INT_MAX);
-
- // get the hints from the window
- if (XGetWMNormalHints(**otk::display, _window, &size, &ret)) {
- _positioned = (size.flags & (PPosition|USPosition));
-
- if (size.flags & PWinGravity) {
- _gravity = size.win_gravity;
-
- // if the client has a frame, i.e. has already been mapped and is
- // changing its gravity
- if (frame && _gravity != oldgravity) {
- // move our idea of the client's position based on its new gravity
- int x = frame->area().x(), y = frame->area().y();
- frame->frameGravity(x, y);
- _area = otk::Rect(otk::Point(x, y), _area.size());
- }
- }
-
- if (size.flags & PAspect) {
- if (size.min_aspect.y) _min_ratio = size.min_aspect.x/size.min_aspect.y;
- if (size.max_aspect.y) _max_ratio = size.max_aspect.x/size.max_aspect.y;
- }
-
- if (size.flags & PMinSize)
- _min_size = otk::Size(size.min_width, size.min_height);
-
- if (size.flags & PMaxSize)
- _max_size = otk::Size(size.max_width, size.max_height);
-
- if (size.flags & PBaseSize)
- _base_size = otk::Size(size.base_width, size.base_height);
-
- if (size.flags & PResizeInc)
- _size_inc = otk::Size(size.width_inc, size.height_inc);
- }
-}
-
-void Client::updateWMHints(bool initstate)
-{
- XWMHints *hints;
-
- // assume a window takes input if it doesnt specify
- _can_focus = true;
- bool ur = false;
-
- if ((hints = XGetWMHints(**otk::display, _window)) != NULL) {
- if (hints->flags & InputHint)
- _can_focus = hints->input;
-
- // only do this when initstate is true!
- if (initstate && (hints->flags & StateHint))
- _iconic = hints->initial_state == IconicState;
-
- if (hints->flags & XUrgencyHint)
- ur = true;
-
- if (hints->flags & WindowGroupHint) {
- if (hints->window_group != _group) {
- // XXX: remove from the old group if there was one
- _group = hints->window_group;
- // XXX: do stuff with the group
- }
- } else // no group!
- _group = None;
-
- if (hints->flags & IconPixmapHint) {
- updateKwmIcon(); // try get the kwm icon first, this is a fallback only
- if (_pixmap_icon == None) {
- _pixmap_icon = hints->icon_pixmap;
- if (hints->flags & IconMaskHint)
- _pixmap_icon_mask = hints->icon_mask;
- else
- _pixmap_icon_mask = None;
- }
- }
-
- XFree(hints);
- }
-
- if (ur != _urgent) {
- _urgent = ur;
-#ifdef DEBUG
- printf("Urgent Hint for 0x%lx: %s\n",
- (long)_window, _urgent ? "ON" : "OFF");
-#endif
- // fire the urgent callback if we're mapped, otherwise, wait until after
- // we're mapped
- if (frame)
- fireUrgent();
- }
-}
-
-void Client::updateTitle()
-{
- _title = "";
-
- // try netwm
- if (!otk::Property::get(_window, otk::Property::atoms.net_wm_name,
- otk::Property::utf8, &_title)) {
- // try old x stuff
- otk::Property::get(_window, otk::Property::atoms.wm_name,
- otk::Property::ascii, &_title);
- }
-
- if (_title.empty())
- _title = _("Unnamed Window");
-
- if (frame)
- frame->adjustTitle();
-}
-
-void Client::updateIconTitle()
-{
- _icon_title = "";
-
- // try netwm
- if (!otk::Property::get(_window, otk::Property::atoms.net_wm_icon_name,
- otk::Property::utf8, &_icon_title)) {
- // try old x stuff
- otk::Property::get(_window, otk::Property::atoms.wm_icon_name,
- otk::Property::ascii, &_icon_title);
- }
-
- if (_title.empty())
- _icon_title = _("Unnamed Window");
-}
-
-void Client::updateClass()
-{
- // set the defaults
- _app_name = _app_class = _role = "";
-
- otk::Property::StringVect v;
- unsigned long num = 2;
-
- if (otk::Property::get(_window, otk::Property::atoms.wm_class,
- otk::Property::ascii, &num, &v)) {
- if (num > 0) _app_name = v[0].c_str();
- if (num > 1) _app_class = v[1].c_str();
- }
-
- v.clear();
- num = 1;
- if (otk::Property::get(_window, otk::Property::atoms.wm_window_role,
- otk::Property::ascii, &num, &v)) {
- if (num > 0) _role = v[0].c_str();
- }
-}
-
-void Client::updateStrut()
-{
- unsigned long num = 4;
- unsigned long *data;
- if (!otk::Property::get(_window, otk::Property::atoms.net_wm_strut,
- otk::Property::atoms.cardinal, &num, &data))
- return;
-
- if (num == 4) {
- _strut.left = data[0];
- _strut.right = data[1];
- _strut.top = data[2];
- _strut.bottom = data[3];
-
- // updating here is pointless while we're being mapped cuz we're not in
- // the screen's client list yet
- if (frame)
- openbox->screen(_screen)->updateStruts();
- }
-
- delete [] data;
-}
-
-void Client::updateTransientFor()
-{
- Window t = 0;
- Client *c = 0;
-
- if (XGetTransientForHint(**otk::display, _window, &t) &&
- t != _window) { // cant be transient to itself!
- c = openbox->findClient(t);
- assert(c != this); // if this happens then we need to check for it
-
- if (!c /*XXX: && _group*/) {
- // not transient to a client, see if it is transient for a group
- if (//t == _group->leader() ||
- t == None ||
- t == otk::display->screenInfo(_screen)->rootWindow()) {
- // window is a transient for its group!
- // XXX: for now this is treated as non-transient.
- // this needs to be fixed!
- }
- }
- }
-
- // if anything has changed...
- if (c != _transient_for) {
- if (_transient_for)
- _transient_for->_transients.remove(this); // remove from old parent
- _transient_for = c;
- if (_transient_for)
- _transient_for->_transients.push_back(this); // add to new parent
- }
-}
-
-void Client::updateIcons()
-{
- unsigned long num;
- unsigned long *data;
- unsigned long w, h, i = 0;
-
- for (int j = 0; j < _nicons; ++j)
- delete [] _icons[j].data;
- if (_nicons > 0)
- delete [] _icons;
- _nicons = 0;
-
- if (otk::Property::get(_window, otk::Property::atoms.net_wm_icon,
- otk::Property::atoms.cardinal, &num, &data)) {
- // figure out how man valid icons are in here
- while (num - i > 2) {
- w = data[i++];
- h = data[i++];
- i += w * h;
- if (i > num) break;
- ++_nicons;
- }
-
- _icons = new Icon[_nicons];
-
- // store the icons
- i = 0;
- for (int j = 0; j < _nicons; ++j) {
- w = _icons[j].w = data[i++];
- h = _icons[j].h = data[i++];
- _icons[j].data = new unsigned long[w * h];
- ::memcpy(_icons[j].data, &data[i], w * h * sizeof(unsigned long));
- i += w * h;
- assert(i <= num);
- }
-
- delete [] data;
- }
-
- if (_nicons <= 0) {
- _nicons = 1;
- _icons = new Icon[1];
- _icons[i].w = 0;
- _icons[i].h = 0;
- _icons[i].data = 0;
- }
-
- assert(_nicons > 0); // there should always be a default..
-
- if (frame) frame->adjustIcon();
-}
-
-void Client::updateKwmIcon()
-{
- _pixmap_icon = _pixmap_icon_mask = None;
-
- unsigned long num = 2;
- Pixmap *data;
- if (otk::Property::get(_window, otk::Property::atoms.kwm_win_icon,
- otk::Property::atoms.kwm_win_icon, &num, &data)) {
- if (num == 2) {
- _pixmap_icon = data[0];
- _pixmap_icon_mask = data[1];
- }
- delete [] data;
- }
-}
-
-void Client::propertyHandler(const XPropertyEvent &e)
-{
- otk::EventHandler::propertyHandler(e);
-
- // validate cuz we query stuff off the client here
- if (!validate()) return;
-
- // compress changes to a single property into a single change
- XEvent ce;
- while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
- // XXX: it would be nice to compress ALL changes to a property, not just
- // changes in a row without other props between.
- if (ce.xproperty.atom != e.atom) {
- XPutBackEvent(**otk::display, &ce);
- break;
- }
- }
-
- if (e.atom == XA_WM_NORMAL_HINTS) {
- updateNormalHints();
- setupDecorAndFunctions(); // normal hints can make a window non-resizable
- } else if (e.atom == XA_WM_HINTS)
- updateWMHints();
- else if (e.atom == XA_WM_TRANSIENT_FOR) {
- updateTransientFor();
- getType();
- calcLayer(); // type may have changed, so update the layer
- setupDecorAndFunctions();
- }
- else if (e.atom == otk::Property::atoms.net_wm_name ||
- e.atom == otk::Property::atoms.wm_name)
- updateTitle();
- else if (e.atom == otk::Property::atoms.net_wm_icon_name ||
- e.atom == otk::Property::atoms.wm_icon_name)
- updateIconTitle();
- else if (e.atom == otk::Property::atoms.wm_class)
- updateClass();
- else if (e.atom == otk::Property::atoms.wm_protocols) {
- updateProtocols();
- setupDecorAndFunctions();
- }
- else if (e.atom == otk::Property::atoms.net_wm_strut)
- updateStrut();
- else if (e.atom == otk::Property::atoms.net_wm_icon)
- updateIcons();
- else if (e.atom == otk::Property::atoms.kwm_win_icon)
- updateKwmIcon();
-}
-
-void Client::setWMState(long state)
-{
- if (state == _wmstate) return; // no change
-
- switch (state) {
- case IconicState:
- iconify(true);
- break;
- case NormalState:
- iconify(false);
- break;
- }
-}
-
-void Client::setDesktop(unsigned int target)
-{
- if (target == _desktop) return;
-
- printf("Setting desktop %u\n", target);
-
- if (!(target < openbox->screen(_screen)->numDesktops() ||
- target == 0xffffffff))
- return;
-
- _desktop = target;
- // set the desktop hint
- otk::Property::set(_window, otk::Property::atoms.net_wm_desktop,
- otk::Property::atoms.cardinal, _desktop);
- frame->adjustState(); // the frame can display the current desktop state
- // 'move' the window to the new desktop
- showhide();
- openbox->screen(_screen)->updateStruts();
-}
-
-void Client::showhide()
-{
- bool show;
- Screen *s = openbox->screen(_screen);
-
- if (_iconic) show = false;
- else if (!(_desktop == s->desktop() ||
- _desktop == 0xffffffff)) show = false;
- else if (normal() && s->showingDesktop()) show = false;
- else show = true;
-
- if (show) frame->show();
- else frame->hide();
-}
-
-void Client::setState(Atom action, long data1, long data2)
-{
- bool shadestate = _shaded;
- bool fsstate = _fullscreen;
- bool maxh = _max_horz;
- bool maxv = _max_vert;
-
- if (!(action == otk::Property::atoms.net_wm_state_add ||
- action == otk::Property::atoms.net_wm_state_remove ||
- action == otk::Property::atoms.net_wm_state_toggle))
- return; // an invalid action was passed to the client message, ignore it
-
- for (int i = 0; i < 2; ++i) {
- Atom state = i == 0 ? data1 : data2;
-
- if (! state) continue;
-
- // if toggling, then pick whether we're adding or removing
- if (action == otk::Property::atoms.net_wm_state_toggle) {
- if (state == otk::Property::atoms.net_wm_state_modal)
- action = _modal ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_maximized_vert)
- action = _max_vert ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_maximized_horz)
- action = _max_horz ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_shaded)
- action = _shaded ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_skip_taskbar)
- action = _skip_taskbar ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_skip_pager)
- action = _skip_pager ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_fullscreen)
- action = _fullscreen ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_above)
- action = _above ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- else if (state == otk::Property::atoms.net_wm_state_below)
- action = _below ? otk::Property::atoms.net_wm_state_remove :
- otk::Property::atoms.net_wm_state_add;
- }
-
- if (action == otk::Property::atoms.net_wm_state_add) {
- if (state == otk::Property::atoms.net_wm_state_modal) {
- if (_modal) continue;
- _modal = true;
- } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
- maxv = true;
- } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
- if (_max_horz) continue;
- maxh = true;
- } else if (state == otk::Property::atoms.net_wm_state_shaded) {
- shadestate = true;
- } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
- _skip_taskbar = true;
- } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
- _skip_pager = true;
- } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
- fsstate = true;
- } else if (state == otk::Property::atoms.net_wm_state_above) {
- if (_above) continue;
- _above = true;
- } else if (state == otk::Property::atoms.net_wm_state_below) {
- if (_below) continue;
- _below = true;
- }
-
- } else { // action == otk::Property::atoms.net_wm_state_remove
- if (state == otk::Property::atoms.net_wm_state_modal) {
- if (!_modal) continue;
- _modal = false;
- } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
- maxv = false;
- } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
- maxh = false;
- } else if (state == otk::Property::atoms.net_wm_state_shaded) {
- shadestate = false;
- } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
- _skip_taskbar = false;
- } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
- _skip_pager = false;
- } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
- fsstate = false;
- } else if (state == otk::Property::atoms.net_wm_state_above) {
- if (!_above) continue;
- _above = false;
- } else if (state == otk::Property::atoms.net_wm_state_below) {
- if (!_below) continue;
- _below = false;
- }
- }
- }
- if (maxh != _max_horz || maxv != _max_vert) {
- if (maxh != _max_horz && maxv != _max_vert) { // toggling both
- if (maxh == maxv) { // both going the same way
- maximize(maxh, 0, true);
- } else {
- maximize(maxh, 1, true);
- maximize(maxv, 2, true);
- }
- } else { // toggling one
- if (maxh != _max_horz)
- maximize(maxh, 1, true);
- else
- maximize(maxv, 2, true);
- }
- }
- // change fullscreen state before shading, as it will affect if the window
- // can shade or not
- if (fsstate != _fullscreen)
- fullscreen(fsstate, true);
- if (shadestate != _shaded)
- shade(shadestate);
- calcLayer();
- changeState(); // change the hint to relect these changes
-}
-
-void Client::toggleClientBorder(bool addborder)
-{
- // adjust our idea of where the client is, based on its border. When the
- // border is removed, the client should now be considered to be in a
- // different position.
- // when re-adding the border to the client, the same operation needs to be
- // reversed.
- int oldx = _area.x(), oldy = _area.y();
- int x = oldx, y = oldy;
- switch(_gravity) {
- default:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- if (addborder) x -= _border_width * 2;
- else x += _border_width * 2;
- break;
- case NorthGravity:
- case SouthGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (addborder) x -= _border_width;
- else x += _border_width;
- break;
- }
- switch(_gravity) {
- default:
- case NorthWestGravity:
- case NorthGravity:
- case NorthEastGravity:
- break;
- case SouthWestGravity:
- case SouthGravity:
- case SouthEastGravity:
- if (addborder) y -= _border_width * 2;
- else y += _border_width * 2;
- break;
- case WestGravity:
- case EastGravity:
- case CenterGravity:
- case ForgetGravity:
- case StaticGravity:
- if (addborder) y -= _border_width;
- else y += _border_width;
- break;
- }
- _area = otk::Rect(otk::Point(x, y), _area.size());
-
- if (addborder) {
- XSetWindowBorderWidth(**otk::display, _window, _border_width);
-
- // move the client so it is back it the right spot _with_ its border!
- if (x != oldx || y != oldy)
- XMoveWindow(**otk::display, _window, x, y);
- } else
- XSetWindowBorderWidth(**otk::display, _window, 0);
-}
-
-void Client::clientMessageHandler(const XClientMessageEvent &e)
-{
- otk::EventHandler::clientMessageHandler(e);
-
- // validate cuz we query stuff off the client here
- if (!validate()) return;
-
- if (e.format != 32) return;
-
- if (e.message_type == otk::Property::atoms.wm_change_state) {
- // compress changes into a single change
- bool compress = false;
- XEvent ce;
- while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
- // XXX: it would be nice to compress ALL messages of a type, not just
- // messages in a row without other message types between.
- if (ce.xclient.message_type != e.message_type) {
- XPutBackEvent(**otk::display, &ce);
- break;
- }
- compress = true;
- }
- if (compress)
- setWMState(ce.xclient.data.l[0]); // use the found event
- else
- setWMState(e.data.l[0]); // use the original event
- } else if (e.message_type == otk::Property::atoms.net_wm_desktop) {
- // compress changes into a single change
- bool compress = false;
- XEvent ce;
- while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
- // XXX: it would be nice to compress ALL messages of a type, not just
- // messages in a row without other message types between.
- if (ce.xclient.message_type != e.message_type) {
- XPutBackEvent(**otk::display, &ce);
- break;
- }
- compress = true;
- }
- if (compress)
- setDesktop(e.data.l[0]); // use the found event
- else
- setDesktop(e.data.l[0]); // use the original event
- } else if (e.message_type == otk::Property::atoms.net_wm_state) {
- // can't compress these
-#ifdef DEBUG
- printf("net_wm_state %s %ld %ld for 0x%lx\n",
- (e.data.l[0] == 0 ? "Remove" : e.data.l[0] == 1 ? "Add" :
- e.data.l[0] == 2 ? "Toggle" : "INVALID"),
- e.data.l[1], e.data.l[2], _window);
-#endif
- setState(e.data.l[0], e.data.l[1], e.data.l[2]);
- } else if (e.message_type == otk::Property::atoms.net_close_window) {
-#ifdef DEBUG
- printf("net_close_window for 0x%lx\n", _window);
-#endif
- close();
- } else if (e.message_type == otk::Property::atoms.net_active_window) {
-#ifdef DEBUG
- printf("net_active_window for 0x%lx\n", _window);
-#endif
- if (openbox->screen(_screen)->showingDesktop())
- openbox->screen(_screen)->showDesktop(false);
- if (_iconic)
- iconify(false);
- else if (!frame->visible()) // if its not visible for other reasons, then
- return; // don't mess with it
- if (_shaded)
- shade(false);
- focus();
- openbox->screen(_screen)->raiseWindow(this);
- } else if (e.message_type == otk::Property::atoms.openbox_active_window) {
- if (openbox->screen(_screen)->showingDesktop())
- openbox->screen(_screen)->showDesktop(false);
- if (_iconic)
- iconify(false);
- else if (!frame->visible()) // if its not visible for other reasons, then
- return; // don't mess with it
- if (e.data.l[0] && _shaded)
- shade(false);
- focus();
- if (e.data.l[1])
- openbox->screen(_screen)->raiseWindow(this);
- } else if (e.message_type == otk::Property::atoms.openbox_restack_window) {
-#ifdef DEBUG
- printf("openbox_restack_window for 0x%lx\n", _window);
-#endif
- if (e.data.l[0] == 0)
- openbox->screen(_screen)->raiseWindow(this);
- else if (e.data.l[0] == 1)
- openbox->screen(_screen)->lowerWindow(this);
- }
-}
-
-#if defined(SHAPE)
-void Client::shapeHandler(const XShapeEvent &e)
-{
- otk::EventHandler::shapeHandler(e);
-
- if (e.kind == ShapeBounding) {
- _shaped = e.shaped;
- frame->adjustShape();
- }
-}
-#endif
-
-void Client::resize(Corner anchor, int w, int h)
-{
- if (!(_functions & Func_Resize)) return;
- internal_resize(anchor, w, h);
-}
-
-void Client::internal_resize(Corner anchor, int w, int h,
- bool user, int x, int y)
-{
- w -= _base_size.width();
- h -= _base_size.height();
-
- if (user) {
- // for interactive resizing. have to move half an increment in each
- // direction.
- int mw = w % _size_inc.width(); // how far we are towards the next size inc
- int mh = h % _size_inc.height();
- int aw = _size_inc.width() / 2; // amount to add
- int ah = _size_inc.height() / 2;
- // don't let us move into a new size increment
- if (mw + aw >= _size_inc.width()) aw = _size_inc.width() - mw - 1;
- if (mh + ah >= _size_inc.height()) ah = _size_inc.height() - mh - 1;
- w += aw;
- h += ah;
-
- // if this is a user-requested resize, then check against min/max sizes
- // and aspect ratios
-
- // smaller than min size or bigger than max size?
- if (w > _max_size.width()) w = _max_size.width();
- if (w < _min_size.width()) w = _min_size.width();
- if (h > _max_size.height()) h = _max_size.height();
- if (h < _min_size.height()) h = _min_size.height();
-
- // adjust the height ot match the width for the aspect ratios
- if (_min_ratio)
- if (h * _min_ratio > w) h = static_cast<int>(w / _min_ratio);
- if (_max_ratio)
- if (h * _max_ratio < w) h = static_cast<int>(w / _max_ratio);
- }
-
- // keep to the increments
- w /= _size_inc.width();
- h /= _size_inc.height();
-
- // you cannot resize to nothing
- if (w < 1) w = 1;
- if (h < 1) h = 1;
-
- // store the logical size
- _logical_size = otk::Size(w, h);
-
- w *= _size_inc.width();
- h *= _size_inc.height();
-
- w += _base_size.width();
- h += _base_size.height();
-
- if (x == INT_MIN || y == INT_MIN) {
- x = _area.x();
- y = _area.y();
- switch (anchor) {
- case TopLeft:
- break;
- case TopRight:
- x -= w - _area.width();
- break;
- case BottomLeft:
- y -= h - _area.height();
- break;
- case BottomRight:
- x -= w - _area.width();
- y -= h - _area.height();
- break;
- }
- }
-
- _area = otk::Rect(_area.position(), otk::Size(w, h));
-
- XResizeWindow(**otk::display, _window, w, h);
-
- // resize the frame to match the request
- frame->adjustSize();
- internal_move(x, y);
-}
-
-const Icon *Client::icon(const otk::Size &s) const
-{
- unsigned long req = s.width() * s.height();
- // si is the smallest image >= req
- // li is the largest image < req
- unsigned long smallest = 0xffffffff, largest = 0, si = 0, li = 0;
-
- assert(_nicons > 0); // there should always be a default..
- for (int i = 0; i < _nicons; ++i) {
- unsigned long size = _icons[i].w * _icons[i].h;
- if (size < smallest && size >= req) {
- smallest = size;
- si = i;
- }
- if (size > largest && size <= req) {
- largest = size;
- li = i;
- }
- }
- if (largest == 0) // didnt find one smaller than the requested size
- return &_icons[si];
- return &_icons[li];
-}
-
-void Client::move(int x, int y, bool final)
-{
- if (!(_functions & Func_Move)) return;
- frame->frameGravity(x, y); // get the client's position based on x,y for the
- // frame
- internal_move(x, y, final);
-}
-
-void Client::internal_move(int x, int y, bool final)
-{
- _area = otk::Rect(otk::Point(x, y), _area.size());
-
- // move the frame to be in the requested position
- if (frame) { // this can be called while mapping, before frame exists
- frame->adjustPosition();
-
- // send synthetic configure notify (we don't need to if we aren't mapped
- // yet)
- if (final) {
- XEvent event;
- event.type = ConfigureNotify;
- event.xconfigure.display = **otk::display;
- event.xconfigure.event = _window;
- event.xconfigure.window = _window;
-
- // root window coords with border in mind
- event.xconfigure.x = x - _border_width + frame->size().left;
- event.xconfigure.y = y - _border_width + frame->size().top;
-
- event.xconfigure.width = _area.width();
- event.xconfigure.height = _area.height();
- event.xconfigure.border_width = _border_width;
- event.xconfigure.above = frame->plate();
- event.xconfigure.override_redirect = False;
- XSendEvent(event.xconfigure.display, event.xconfigure.window, False,
- StructureNotifyMask, &event);
-#if 0//def DEBUG
- printf("Sent synthetic ConfigureNotify %d,%d %d,%d to 0x%lx\n",
- event.xconfigure.x, event.xconfigure.y, event.xconfigure.width,
- event.xconfigure.height, event.xconfigure.window);
-#endif
- }
- }
-}
-
-void Client::close()
-{
- XEvent ce;
-
- if (!(_functions & Func_Close)) return;
-
- // XXX: itd be cool to do timeouts and shit here for killing the client's
- // process off
- // like... if the window is around after 5 seconds, then the close button
- // turns a nice red, and if this function is called again, the client is
- // explicitly killed.
-
- ce.xclient.type = ClientMessage;
- ce.xclient.message_type = otk::Property::atoms.wm_protocols;
- ce.xclient.display = **otk::display;
- ce.xclient.window = _window;
- ce.xclient.format = 32;
- ce.xclient.data.l[0] = otk::Property::atoms.wm_delete_window;
- ce.xclient.data.l[1] = CurrentTime;
- ce.xclient.data.l[2] = 0l;
- ce.xclient.data.l[3] = 0l;
- ce.xclient.data.l[4] = 0l;
- XSendEvent(**otk::display, _window, false, NoEventMask, &ce);
-}
-
-void Client::changeState()
-{
- unsigned long state[2];
- state[0] = _wmstate;
- state[1] = None;
- otk::Property::set(_window, otk::Property::atoms.wm_state,
- otk::Property::atoms.wm_state, state, 2);
-
- Atom netstate[10];
- int num = 0;
- if (_modal)
- netstate[num++] = otk::Property::atoms.net_wm_state_modal;
- if (_shaded)
- netstate[num++] = otk::Property::atoms.net_wm_state_shaded;
- if (_iconic)
- netstate[num++] = otk::Property::atoms.net_wm_state_hidden;
- if (_skip_taskbar)
- netstate[num++] = otk::Property::atoms.net_wm_state_skip_taskbar;
- if (_skip_pager)
- netstate[num++] = otk::Property::atoms.net_wm_state_skip_pager;
- if (_fullscreen)
- netstate[num++] = otk::Property::atoms.net_wm_state_fullscreen;
- if (_max_vert)
- netstate[num++] = otk::Property::atoms.net_wm_state_maximized_vert;
- if (_max_horz)
- netstate[num++] = otk::Property::atoms.net_wm_state_maximized_horz;
- if (_above)
- netstate[num++] = otk::Property::atoms.net_wm_state_above;
- if (_below)
- netstate[num++] = otk::Property::atoms.net_wm_state_below;
- otk::Property::set(_window, otk::Property::atoms.net_wm_state,
- otk::Property::atoms.atom, netstate, num);
-
- calcLayer();
-
- if (frame)
- frame->adjustState();
-}
-
-void Client::changeAllowedActions(void)
-{
- Atom actions[9];
- int num = 0;
-
- actions[num++] = otk::Property::atoms.net_wm_action_change_desktop;
-
- if (_functions & Func_Shade)
- actions[num++] = otk::Property::atoms.net_wm_action_shade;
- if (_functions & Func_Close)
- actions[num++] = otk::Property::atoms.net_wm_action_close;
- if (_functions & Func_Move)
- actions[num++] = otk::Property::atoms.net_wm_action_move;
- if (_functions & Func_Iconify)
- actions[num++] = otk::Property::atoms.net_wm_action_minimize;
- if (_functions & Func_Resize)
- actions[num++] = otk::Property::atoms.net_wm_action_resize;
- if (_functions & Func_Fullscreen)
- actions[num++] = otk::Property::atoms.net_wm_action_fullscreen;
- if (_functions & Func_Maximize) {
- actions[num++] = otk::Property::atoms.net_wm_action_maximize_horz;
- actions[num++] = otk::Property::atoms.net_wm_action_maximize_vert;
- }
-
- otk::Property::set(_window, otk::Property::atoms.net_wm_allowed_actions,
- otk::Property::atoms.atom, actions, num);
-
- // make sure the window isn't breaking any rules now
-
- if (!(_functions & Func_Shade) && _shaded)
- if (frame) shade(false);
- else _shaded = false;
- if (!(_functions & Func_Iconify) && _iconic)
- if (frame) setDesktop(openbox->screen(_screen)->desktop());
- else _iconic = false;
- if (!(_functions & Func_Fullscreen) && _fullscreen)
- if (frame) fullscreen(false);
- else _fullscreen = false;
- if (!(_functions & Func_Maximize) && (_max_horz || _max_vert))
- if (frame) maximize(false, 0);
- else _max_vert = _max_horz = false;
-}
-
-void Client::remaximize()
-{
- int dir;
- if (_max_horz && _max_vert)
- dir = 0;
- else if (_max_horz)
- dir = 1;
- else if (_max_vert)
- dir = 2;
- else
- return; // not maximized
- _max_horz = _max_vert = false;
- maximize(true, dir, false);
-}
-
-void Client::applyStartupState()
-{
- // these are in a carefully crafted order..
-
- if (_iconic) {
- _iconic = false;
- iconify(true);
- }
- if (_fullscreen) {
- _fullscreen = false;
- fullscreen(true, false);
- }
- if (_shaded) {
- _shaded = false;
- shade(true);
- }
- if (_urgent)
- fireUrgent();
-
- if (_max_vert && _max_horz) {
- _max_vert = _max_horz = false;
- maximize(true, 0, false);
- } else if (_max_vert) {
- _max_vert = false;
- maximize(true, 2, false);
- } else if (_max_horz) {
- _max_horz = false;
- maximize(true, 1, false);
- }
-
- if (_skip_taskbar); // nothing to do for this
- if (_skip_pager); // nothing to do for this
- if (_modal); // nothing to do for this
- if (_above); // nothing to do for this
- if (_below); // nothing to do for this
-}
-
-void Client::fireUrgent()
-{
- // call the python UrgentWindow callbacks
- EventData data(_screen, this, EventAction::UrgentWindow, 0);
- openbox->bindings()->fireEvent(&data);
-}
-
-void Client::shade(bool shade)
-{
- if (!(_functions & Func_Shade) || // can't
- _shaded == shade) return; // already done
-
- // when we're iconic, don't change the wmstate
- if (!_iconic)
- _wmstate = shade ? IconicState : NormalState;
- _shaded = shade;
- changeState();
- frame->adjustSize();
-}
-
-void Client::maximize(bool max, int dir, bool savearea)
-{
- assert(dir == 0 || dir == 1 || dir == 2);
- if (!(_functions & Func_Maximize)) return; // can't
-
- // check if already done
- if (max) {
- if (dir == 0 && _max_horz && _max_vert) return;
- if (dir == 1 && _max_horz) return;
- if (dir == 2 && _max_vert) return;
- } else {
- if (dir == 0 && !_max_horz && !_max_vert) return;
- if (dir == 1 && !_max_horz) return;
- if (dir == 2 && !_max_vert) return;
- }
-
- const otk::Rect &a = openbox->screen(_screen)->area(_desktop);
- int x = frame->area().x(), y = frame->area().y(),
- w = _area.width(), h = _area.height();
-
- if (max) {
- if (savearea) {
- long dimensions[4];
- long *readdim;
- unsigned long n = 4;
-
- dimensions[0] = x;
- dimensions[1] = y;
- dimensions[2] = w;
- dimensions[3] = h;
-
- // get the property off the window and use it for the dimentions we are
- // already maxed on
- if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
- otk::Property::atoms.cardinal, &n,
- (long unsigned**) &readdim)) {
- if (n == 4) {
- if (_max_horz) {
- dimensions[0] = readdim[0];
- dimensions[2] = readdim[2];
- }
- if (_max_vert) {
- dimensions[1] = readdim[1];
- dimensions[3] = readdim[3];
- }
- }
- delete readdim;
- }
-
- otk::Property::set(_window, otk::Property::atoms.openbox_premax,
- otk::Property::atoms.cardinal,
- (long unsigned*)dimensions, 4);
- }
- if (dir == 0 || dir == 1) { // horz
- x = a.x();
- w = a.width();
- }
- if (dir == 0 || dir == 2) { // vert
- y = a.y();
- h = a.height() - frame->size().top - frame->size().bottom;
- }
- } else {
- long *dimensions;
- long unsigned n = 4;
-
- if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
- otk::Property::atoms.cardinal, &n,
- (long unsigned**) &dimensions)) {
- if (n == 4) {
- if (dir == 0 || dir == 1) { // horz
- x = (signed int)dimensions[0];
- w = (signed int)dimensions[2];
- }
- if (dir == 0 || dir == 2) { // vert
- y = (signed int)dimensions[1];
- h = (signed int)dimensions[3];
- }
- }
- delete dimensions;
- } else {
- // pick some fallbacks...
- if (dir == 0 || dir == 1) { // horz
- x = a.x() + a.width() / 4;
- w = a.width() / 2;
- }
- if (dir == 0 || dir == 2) { // vert
- y = a.y() + a.height() / 4;
- h = a.height() / 2;
- }
- }
- }
-
- if (dir == 0 || dir == 1) // horz
- _max_horz = max;
- if (dir == 0 || dir == 2) // vert
- _max_vert = max;
-
- if (!_max_horz && !_max_vert)
- otk::Property::erase(_window, otk::Property::atoms.openbox_premax);
-
- changeState(); // change the state hints on the client
-
- frame->frameGravity(x, y); // figure out where the client should be going
- internal_resize(TopLeft, w, h, true, x, y);
-}
-
-void Client::fullscreen(bool fs, bool savearea)
-{
- static FunctionFlags saved_func;
- static DecorationFlags saved_decor;
-
- if (!(_functions & Func_Fullscreen) || // can't
- _fullscreen == fs) return; // already done
-
- _fullscreen = fs;
- changeState(); // change the state hints on the client
-
- int x = _area.x(), y = _area.y(), w = _area.width(), h = _area.height();
-
- if (fs) {
- // save the functions and remove them
- saved_func = _functions;
- _functions = _functions & (Func_Close | Func_Fullscreen | Func_Iconify);
- // save the decorations and remove them
- saved_decor = _decorations;
- _decorations = 0;
- if (savearea) {
- long dimensions[4];
- dimensions[0] = _area.x();
- dimensions[1] = _area.y();
- dimensions[2] = _area.width();
- dimensions[3] = _area.height();
- otk::Property::set(_window, otk::Property::atoms.openbox_premax,
- otk::Property::atoms.cardinal,
- (long unsigned*)dimensions, 4);
- }
- const otk::ScreenInfo *info = otk::display->screenInfo(_screen);
- x = 0;
- y = 0;
- w = info->size().width();
- h = info->size().height();
- } else {
- _functions = saved_func;
- _decorations = saved_decor;
-
- long *dimensions;
- long unsigned n = 4;
-
- if (otk::Property::get(_window, otk::Property::atoms.openbox_premax,
- otk::Property::atoms.cardinal, &n,
- (long unsigned**) &dimensions)) {
- if (n == 4) {
- x = dimensions[0];
- y = dimensions[1];
- w = dimensions[2];
- h = dimensions[3];
- }
- delete dimensions;
- } else {
- // pick some fallbacks...
- const otk::Rect &a = openbox->screen(_screen)->area(_desktop);
- x = a.x() + a.width() / 4;
- y = a.y() + a.height() / 4;
- w = a.width() / 2;
- h = a.height() / 2;
- }
- }
-
- changeAllowedActions(); // based on the new _functions
-
- // when fullscreening, don't obey things like increments, fill the screen
- internal_resize(TopLeft, w, h, !fs, x, y);
-
- // raise (back) into our stacking layer
- openbox->screen(_screen)->raiseWindow(this);
-
- // try focus us when we go into fullscreen mode
- if (fs) focus();
-}
-
-void Client::iconify(bool iconic, bool curdesk)
-{
- if (_iconic == iconic) return; // nothing to do
-
-#ifdef DEBUG
- printf("%sconifying window: 0x%lx\n", (iconic ? "I" : "Uni"), _window);
-#endif
-
- _iconic = iconic;
-
- if (_iconic) {
- _wmstate = IconicState;
- ignore_unmaps++;
- // we unmap the client itself so that we can get MapRequest events, and
- // because the ICCCM tells us to!
- XUnmapWindow(**otk::display, _window);
- } else {
- if (curdesk)
- setDesktop(openbox->screen(_screen)->desktop());
- _wmstate = NormalState;
- XMapWindow(**otk::display, _window);
- }
- changeState();
- showhide();
- openbox->screen(_screen)->updateStruts();
-}
-
-void Client::disableDecorations(DecorationFlags flags)
-{
- _disabled_decorations = flags;
- setupDecorAndFunctions();
-}
-
-void Client::installColormap(bool install) const
-{
- XWindowAttributes wa;
- if (XGetWindowAttributes(**otk::display, _window, &wa)) {
- if (install)
- XInstallColormap(**otk::display, wa.colormap);
- else
- XUninstallColormap(**otk::display, wa.colormap);
- }
-}
-
-Client *Client::searchModalTree(Client *node, Client *skip)
-{
- List::const_iterator it, end = node->_transients.end();
- Client *ret;
-
- for (it = node->_transients.begin(); it != end; ++it) {
- if (*it == skip) continue; // circular?
- if ((ret = searchModalTree(*it, skip))) return ret; // got one
- if ((*it)->_modal) return *it; // got one
- }
- return 0;
-}
-
-Client *Client::findModalChild()
-{
- return searchModalTree(this, this);
-}
-
-
-bool Client::focus()
-{
- // if we have a modal child, then focus it, not us
- Client *c = findModalChild();
- if (c) return c->focus();
-
- // won't try focus if the client doesn't want it, or if the window isn't
- // visible on the screen
- if (!(frame->visible() && (_can_focus || _focus_notify))) return false;
-
- // do a check to see if the window has already been unmapped or destroyed
- // do this intelligently while watching out for unmaps we've generated
- // (ignore_unmaps > 0)
- XEvent ev;
- if (XCheckTypedWindowEvent(**otk::display, _window, DestroyNotify, &ev)) {
- XPutBackEvent(**otk::display, &ev);
- return false;
- }
- while (XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &ev)) {
- if (ignore_unmaps) {
- unmapHandler(ev.xunmap);
- } else {
- XPutBackEvent(**otk::display, &ev);
- return false;
- }
- }
-
- if (_can_focus)
- XSetInputFocus(**otk::display, _window,
- RevertToNone, CurrentTime);
-
- if (_focus_notify) {
- XEvent ce;
- ce.xclient.type = ClientMessage;
- ce.xclient.message_type = otk::Property::atoms.wm_protocols;
- ce.xclient.display = **otk::display;
- ce.xclient.window = _window;
- ce.xclient.format = 32;
- ce.xclient.data.l[0] = otk::Property::atoms.wm_take_focus;
- ce.xclient.data.l[1] = openbox->lastTime();
- ce.xclient.data.l[2] = 0l;
- ce.xclient.data.l[3] = 0l;
- ce.xclient.data.l[4] = 0l;
- XSendEvent(**otk::display, _window, False, NoEventMask, &ce);
- }
-
- XSync(**otk::display, False);
- return true;
-}
-
-
-void Client::unfocus() const
-{
- assert(openbox->focusedClient() == this);
- openbox->setFocusedClient(0);
-}
-
-
-void Client::focusHandler(const XFocusChangeEvent &e)
-{
-#ifdef DEBUG
-// printf("FocusIn for 0x%lx\n", e.window);
-#endif // DEBUG
-
- otk::EventHandler::focusHandler(e);
-
- _focused = true;
- frame->adjustFocus();
-
- calcLayer(); // focus state can affect the stacking layer
-
- openbox->setFocusedClient(this);
-}
-
-
-void Client::unfocusHandler(const XFocusChangeEvent &e)
-{
-#ifdef DEBUG
-// printf("FocusOut for 0x%lx\n", e.window);
-#endif // DEBUG
-
- otk::EventHandler::unfocusHandler(e);
-
- _focused = false;
- frame->adjustFocus();
-
- calcLayer(); // focus state can affect the stacking layer
-
- if (openbox->focusedClient() == this)
- openbox->setFocusedClient(0);
-}
-
-
-void Client::configureRequestHandler(const XConfigureRequestEvent &ec)
-{
-#ifdef DEBUG
- printf("ConfigureRequest for 0x%lx\n", ec.window);
-#endif // DEBUG
-
- otk::EventHandler::configureRequestHandler(ec);
-
- // compress these
- XConfigureRequestEvent e = ec;
- XEvent ev;
- while (XCheckTypedWindowEvent(**otk::display, window(), ConfigureRequest,
- &ev)) {
- // XXX if this causes bad things.. we can compress config req's with the
- // same mask.
- e.value_mask |= ev.xconfigurerequest.value_mask;
- if (ev.xconfigurerequest.value_mask & CWX)
- e.x = ev.xconfigurerequest.x;
- if (ev.xconfigurerequest.value_mask & CWY)
- e.y = ev.xconfigurerequest.y;
- if (ev.xconfigurerequest.value_mask & CWWidth)
- e.width = ev.xconfigurerequest.width;
- if (ev.xconfigurerequest.value_mask & CWHeight)
- e.height = ev.xconfigurerequest.height;
- if (ev.xconfigurerequest.value_mask & CWBorderWidth)
- e.border_width = ev.xconfigurerequest.border_width;
- if (ev.xconfigurerequest.value_mask & CWStackMode)
- e.detail = ev.xconfigurerequest.detail;
- }
-
- // if we are iconic (or shaded (fvwm does this)) ignore the event
- if (_iconic || _shaded) return;
-
- if (e.value_mask & CWBorderWidth)
- _border_width = e.border_width;
-
- // resize, then move, as specified in the EWMH section 7.7
- if (e.value_mask & (CWWidth | CWHeight)) {
- int w = (e.value_mask & CWWidth) ? e.width : _area.width();
- int h = (e.value_mask & CWHeight) ? e.height : _area.height();
-
- Corner corner;
- switch (_gravity) {
- case NorthEastGravity:
- case EastGravity:
- corner = TopRight;
- break;
- case SouthWestGravity:
- case SouthGravity:
- corner = BottomLeft;
- break;
- case SouthEastGravity:
- corner = BottomRight;
- break;
- default: // NorthWest, Static, etc
- corner = TopLeft;
- }
-
- // if moving AND resizing ...
- if (e.value_mask & (CWX | CWY)) {
- int x = (e.value_mask & CWX) ? e.x : _area.x();
- int y = (e.value_mask & CWY) ? e.y : _area.y();
- internal_resize(corner, w, h, false, x, y);
- } else // if JUST resizing...
- internal_resize(corner, w, h, false);
- } else if (e.value_mask & (CWX | CWY)) { // if JUST moving...
- int x = (e.value_mask & CWX) ? e.x : _area.x();
- int y = (e.value_mask & CWY) ? e.y : _area.y();
- internal_move(x, y);
- }
-
- if (e.value_mask & CWStackMode) {
- switch (e.detail) {
- case Below:
- case BottomIf:
- openbox->screen(_screen)->lowerWindow(this);
- break;
-
- case Above:
- case TopIf:
- default:
- openbox->screen(_screen)->raiseWindow(this);
- break;
- }
- }
-}
-
-
-void Client::unmapHandler(const XUnmapEvent &e)
-{
- if (ignore_unmaps) {
-#ifdef DEBUG
-// printf("Ignored UnmapNotify for 0x%lx (event 0x%lx)\n", e.window, e.event);
-#endif // DEBUG
- ignore_unmaps--;
- return;
- }
-
-#ifdef DEBUG
- printf("UnmapNotify for 0x%lx\n", e.window);
-#endif // DEBUG
-
- otk::EventHandler::unmapHandler(e);
-
- // this deletes us etc
- openbox->screen(_screen)->unmanageWindow(this);
-}
-
-
-void Client::destroyHandler(const XDestroyWindowEvent &e)
-{
-#ifdef DEBUG
- printf("DestroyNotify for 0x%lx\n", e.window);
-#endif // DEBUG
-
- otk::EventHandler::destroyHandler(e);
-
- // this deletes us etc
- openbox->screen(_screen)->unmanageWindow(this);
-}
-
-
-void Client::reparentHandler(const XReparentEvent &e)
-{
- // this is when the client is first taken captive in the frame
- if (e.parent == frame->plate()) return;
-
-#ifdef DEBUG
- printf("ReparentNotify for 0x%lx\n", e.window);
-#endif // DEBUG
-
- otk::EventHandler::reparentHandler(e);
-
- /*
- This event is quite rare and is usually handled in unmapHandler.
- However, if the window is unmapped when the reparent event occurs,
- the window manager never sees it because an unmap event is not sent
- to an already unmapped window.
- */
-
- // we don't want the reparent event, put it back on the stack for the X
- // server to deal with after we unmanage the window
- XEvent ev;
- ev.xreparent = e;
- XPutBackEvent(**otk::display, &ev);
-
- // this deletes us etc
- openbox->screen(_screen)->unmanageWindow(this);
-}
-
-void Client::mapRequestHandler(const XMapRequestEvent &e)
-{
-#ifdef DEBUG
- printf("MapRequest for already managed 0x%lx\n", e.window);
-#endif // DEBUG
-
- assert(_iconic); // we shouldn't be able to get this unless we're iconic
-
- // move to the current desktop (uniconify)
- iconify(false);
- // XXX: should we focus/raise the window? (basically a net_wm_active_window)
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __client_hh
-#define __client_hh
-
-/*! @file client.hh
- @brief The Client class maintains the state of a client window by handling
- property changes on the window and some client messages
-*/
-
-#include "screen.hh"
-#include "otk/strut.hh"
-#include "otk/rect.hh"
-#include "otk/eventhandler.hh"
-#include "otk/ustring.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-
-#ifdef SHAPE
-#include <X11/extensions/shape.h>
-#endif // SHAPE
-}
-
-#include <string>
-#include <list>
-
-namespace ob {
-
-class Frame;
-class Screen;
-
-struct Icon {
- unsigned long w, h;
- unsigned long *data;
-};
-
-//! The MWM Hints as retrieved from the window property
-/*!
- This structure only contains 3 elements, even though the Motif 2.0
- structure contains 5. We only use the first 3, so that is all gets defined.
-*/
-struct MwmHints {
- unsigned long flags; //!< A bitmask of Client::MwmFlags values
- unsigned long functions; //!< A bitmask of Client::MwmFunctions values
- unsigned long decorations;//!< A bitmask of Client::MwmDecorations values
- //! The number of elements in the Client::MwmHints struct
- static const unsigned int elements = 3;
-};
-
-//! Maintains the state of a client window.
-/*!
- Client maintains the state of a client window. The state consists of the
- hints that the application sets on the window, such as the title, or window
- gravity.
- <p>
- Client also manages client messages for the client window. When the
- application (or any application) requests something to be changed for the
- client, it will call the ActionHandler (for client messages) or update the
- class' member variables and call whatever is nessary to complete the
- change (such as causing a redraw of the titlebar after the title is changed).
-*/
-class Client : public otk::EventHandler {
-public:
-
- //! The frame window which decorates around the client window
- /*!
- NOTE: This should NEVER be used inside the client class's constructor!
- */
- Frame *frame;
-
- //! Holds a list of Clients
- typedef std::list<Client*> List;
-
- //! The possible stacking layers a client window can be a part of
- enum StackLayer {
- Layer_Icon, //!< 0 - iconified windows, in any order at all
- Layer_Desktop, //!< 1 - desktop windows
- Layer_Below, //!< 2 - normal windows w/ below
- Layer_Normal, //!< 3 - normal windows
- Layer_Above, //!< 4 - normal windows w/ above
- Layer_Top, //!< 5 - always-on-top-windows (docks?)
- Layer_Fullscreen, //!< 6 - fullscreeen windows
- Layer_Internal, //!< 7 - openbox windows/menus
- NUM_LAYERS
- };
-
- //! Corners of the client window, used for anchor positions
- enum Corner { TopLeft,
- TopRight,
- BottomLeft,
- BottomRight };
-
- //! Possible window types
- enum WindowType { Type_Desktop, //!< A desktop (bottom-most window)
- Type_Dock, //!< A dock bar/panel window
- Type_Toolbar, //!< A toolbar window, pulled off an app
- Type_Menu, //!< An unpinned menu from an app
- Type_Utility, //!< A small utility window such as a palette
- Type_Splash, //!< A splash screen window
- Type_Dialog, //!< A dialog window
- Type_Normal //!< A normal application window
- };
-
- //! Possible flags for MWM Hints (defined by Motif 2.0)
- enum MwmFlags { MwmFlag_Functions = 1 << 0, //!< The MMW Hints define funcs
- MwmFlag_Decorations = 1 << 1 //!< The MWM Hints define decor
- };
-
- //! Possible functions for MWM Hints (defined by Motif 2.0)
- enum MwmFunctions { MwmFunc_All = 1 << 0, //!< All functions
- MwmFunc_Resize = 1 << 1, //!< Allow resizing
- MwmFunc_Move = 1 << 2, //!< Allow moving
- MwmFunc_Iconify = 1 << 3, //!< Allow to be iconfied
- MwmFunc_Maximize = 1 << 4 //!< Allow to be maximized
- //MwmFunc_Close = 1 << 5 //!< Allow to be closed
- };
-
- //! Possible decorations for MWM Hints (defined by Motif 2.0)
- enum MemDecorations { MwmDecor_All = 1 << 0, //!< All decorations
- MwmDecor_Border = 1 << 1, //!< Show a border
- MwmDecor_Handle = 1 << 2, //!< Show a handle (bottom)
- MwmDecor_Title = 1 << 3, //!< Show a titlebar
- //MwmDecor_Menu = 1 << 4, //!< Show a menu
- MwmDecor_Iconify = 1 << 5, //!< Show an iconify button
- MwmDecor_Maximize = 1 << 6 //!< Show a maximize button
- };
-
- //! The things the user can do to the client window
- enum Function { Func_Resize = 1 << 0, //!< Allow resizing
- Func_Move = 1 << 1, //!< Allow moving
- Func_Iconify = 1 << 2, //!< Allow to be iconified
- Func_Maximize = 1 << 3, //!< Allow to be maximized
- Func_Shade = 1 << 4, //!< Allow to be shaded
- Func_Fullscreen = 1 << 5, //!< Allow to be made fullscreen
- Func_Close = 1 << 6 //!< Allow to be closed
- };
- //! Holds a bitmask of Client::Function values
- typedef unsigned char FunctionFlags;
-
- //! The decorations the client window wants to be displayed on it
- enum Decoration { Decor_Titlebar = 1 << 0, //!< Display a titlebar
- Decor_Handle = 1 << 1, //!< Display a handle (bottom)
- Decor_Border = 1 << 2, //!< Display a border
- Decor_Icon = 1 << 3, //!< Display the window's icon
- Decor_Iconify = 1 << 4, //!< Display an iconify button
- Decor_Maximize = 1 << 5, //!< Display a maximize button
- //! Display a button to toggle the window's placement on
- //! all desktops
- Decor_AllDesktops = 1 << 6,
- Decor_Close = 1 << 7 //!< Display a close button
- };
- //! Holds a bitmask of Client::Decoration values
- typedef unsigned char DecorationFlags;
-
- //! The event mask to grab on client windows
- static const long event_mask = PropertyChangeMask | FocusChangeMask |
- StructureNotifyMask;
-
- //! The mask of events to not let propogate past the client
- /*!
- This makes things like xprop work on the client window, but means we have
- to explicitly grab clicks that we want.
- */
- static const long no_propagate_mask = ButtonPressMask | ButtonReleaseMask |
- ButtonMotionMask;
-
- //! The number of unmap events to ignore on the window
- int ignore_unmaps;
-
-private:
- //! The screen number on which the client resides
- int _screen;
-
- //! The actual window that this class is wrapping up
- Window _window;
-
- //! The id of the group the window belongs to
- Window _group;
-
- //! The client which this client is a transient (child) for
- Client *_transient_for;
-
- //! The clients which are transients (children) of this client
- Client::List _transients;
-
- //! The desktop on which the window resides (0xffffffff for all desktops)
- unsigned int _desktop;
-
- //! Normal window title
- otk::ustring _title;
- //! Window title when iconifiged
- otk::ustring _icon_title;
-
- //! The application that created the window
- std::string _app_name;
- //! The class of the window, can used for grouping
- std::string _app_class;
- //! The specified role of the window, used for identification
- std::string _role;
-
- //! The type of window (what its function is)
- WindowType _type;
-
- //! Position and size of the window
- /*!
- This will not always be the actual position of the window on screen, it is
- rather, the position requested by the client, to which the window's gravity
- is applied.
- */
- otk::Rect _area;
-
- //! The window's strut
- /*!
- The strut defines areas of the screen that are marked off-bounds for window
- placement. In theory, where this window exists.
- */
- otk::Strut _strut;
-
- //! The logical size of the window
- /*!
- The "logical" size of the window is refers to the user's perception of the
- size of the window, and is the value that should be displayed to the user.
- For example, with xterms, this value it the number of characters being
- displayed in the terminal, instead of the number of pixels.
- */
- otk::Size _logical_size;
-
- //! Width of the border on the window.
- /*!
- The window manager will set this to 0 while the window is being managed,
- but needs to restore it afterwards, so it is saved here.
- */
- int _border_width;
-
- //! The minimum aspect ratio the client window can be sized to.
- /*!
- A value of 0 means this is ignored.
- */
- float _min_ratio;
- //! The maximum aspect ratio the client window can be sized to.
- /*!
- A value of 0 means this is ignored.
- */
- float _max_ratio;
-
- //! The minimum size of the client window
- /*!
- If the min is > the max, then the window is not resizable
- */
- otk::Size _min_size;
- //! The maximum size of the client window
- /*!
- If the min is > the max, then the window is not resizable
- */
- otk::Size _max_size;
- //! The size of increments to resize the client window by
- otk::Size _size_inc;
- //! The base size of the client window
- /*!
- This value should be subtracted from the window's actual size when
- displaying its size to the user, or working with its min/max size
- */
- otk::Size _base_size;
-
- //! Window decoration and functionality hints
- MwmHints _mwmhints;
-
- //! Where to place the decorated window in relation to the undecorated window
- int _gravity;
-
- //! The state of the window, one of WithdrawnState, IconicState, or
- //! NormalState
- long _wmstate;
-
- //! True if the client supports the delete_window protocol
- bool _delete_window;
-
- //! Was the window's position requested by the application? if not, we should
- //! place the window ourselves when it first appears
- bool _positioned;
-
- //! Can the window receive input focus?
- bool _can_focus;
- //! Urgency flag
- bool _urgent;
- //! Notify the window when it receives focus?
- bool _focus_notify;
- //! Does the client window have the input focus?
- bool _focused;
-
- //! The window uses shape extension to be non-rectangular?
- bool _shaped;
-
- //! The window is modal, so it must be processed before any windows it is
- //! related to can be focused
- bool _modal;
- //! Only the window's titlebar is displayed
- bool _shaded;
- //! The window is iconified
- bool _iconic;
- //! The window is maximized to fill the screen vertically
- bool _max_vert;
- //! The window is maximized to fill the screen horizontally
- bool _max_horz;
- //! The window should not be displayed by pagers
- bool _skip_pager;
- //! The window should not be displayed by taskbars
- bool _skip_taskbar;
- //! The window is a 'fullscreen' window, and should be on top of all others
- bool _fullscreen;
- //! The window should be on top of other windows of the same type
- bool _above;
- //! The window should be underneath other windows of the same type
- bool _below;
-
- //! The layer in which the window will be stacked, windows in lower layers
- //! are always below windows in higher layers.
- StackLayer _layer;
-
- //! A bitmask of values in the Client::Decoration enum
- /*!
- The values in the variable are the decorations that the client wants to be
- displayed around it.
- */
- DecorationFlags _decorations;
-
- //! A bitmask of values in the Client::Decoration enum.
- /*!
- Specifies the decorations that should NOT be displayed on the client.
- */
- DecorationFlags _disabled_decorations;
-
- //! A bitmask of values in the Client::Function enum
- /*!
- The values in the variable specify the ways in which the user is allowed to
- modify this window.
- */
- FunctionFlags _functions;
-
- //! Icons for the client as specified on the client window
- Icon *_icons;
- //! The number of icons in _icons
- int _nicons;
-
- Pixmap _pixmap_icon;
- Pixmap _pixmap_icon_mask;
-
- //! Retrieves the window's initial gravity
- void getGravity();
- //! Retrieves the desktop hint's value and sets Client::_desktop
- void getDesktop();
- //! Retrieves the window's type and sets Client::_type
- void getType();
- //! Gets the MWM Hints and adjusts Client::_functions and
- //! Client::_decorations
- void getMwmHints();
- //! Gets the position and size of the window and sets Client::_area
- void getArea();
- //! Gets the net_state hint and sets the boolean flags for any states set in
- //! the hint
- void getState();
- //! Determines if the window uses the Shape extension and sets
- //! Client::_shaped
- void getShaped();
-
- //! Set up what decor should be shown on the window and what functions should
- //! be allowed (Client::_decorations and Client::_functions).
- /*!
- This also updates the NET_WM_ALLOWED_ACTIONS hint.
- */
- void setupDecorAndFunctions();
-
- //! Sets the wm_state to the specified value
- void setWMState(long state);
- //! Adjusts the window's net_state
- /*!
- This should not be called as part of the window mapping process! It is for
- use when updating the state post-mapping.<br>
- Client::applyStartupState is used to do the same things during the mapping
- process.
- */
- void setState(Atom action, long data1, long data2);
-
- //! Sends the window to the specified desktop
- void setDesktop(unsigned int desktop);
-
- //! Calculates the stacking layer for the client window
- void calcLayer();
-
- //! Update the protocols that the window supports and adjusts things if they
- //! change
- void updateProtocols();
- //! Updates the WMNormalHints and adjusts things if they change
- void updateNormalHints();
- //! Updates the WMHints and adjusts things if they change
- /*!
- @param initstate Whether to read the initial_state property from the
- WMHints. This should only be used during the mapping
- process.
- */
- void updateWMHints(bool initstate = false);
- //! Updates the window's title
- void updateTitle();
- //! Updates the window's icon title
- void updateIconTitle();
- //! Updates the window's application name and class
- void updateClass();
- //! Updates the strut for the client
- void updateStrut();
- //! Updates the window's transient status, and any parents of it
- void updateTransientFor();
- //! Updates the window's icons
- void updateIcons();
- //! Updates the window's kwm icon
- void updateKwmIcon();
-
- //! Change the client's state hints to match the class' data
- void changeState();
- //! Change the allowed actions set on the client
- void changeAllowedActions();
-
- //! Request the client to close its window.
- void close();
-
- //! Shades or unshades the client window
- /*!
- @param shade true if the window should be shaded; false if it should be
- unshaded.
- */
- void shade(bool shade);
-
- //! Recursively searches the client 'tree' for a modal client, always skips
- //! the topmost node (the window you're starting with).
- Client *Client::searchModalTree(Client *node, Client *skip);
-
- //! Recursively searches the client 'tree' for a focused client, always skips
- //! the topmost node (the window you're starting with).
- Client *Client::searchFocusTree(Client *node, Client *skip);
-
- //! Fires the urgent callbacks which lets the user do what they want with
- //! urgent windows
- void fireUrgent();
-
- //! Fullscreen's or unfullscreen's the client window
- /*!
- @param fs true if the window should be made fullscreen; false if it should
- be returned to normal state.
- @param savearea true to have the client's current size and position saved;
- otherwise, they are not. You should not save when mapping a
- new window that is set to fullscreen. This has no effect
- when restoring a window from fullscreen.
- */
- void fullscreen(bool fs, bool savearea = true);
-
- //! Iconifies or uniconifies the client window
- /*!
- @param iconic true if the window should be iconified; false if it should be
- restored.
- @param curdesk If iconic is false, then this determines if the window will
- be uniconified to the current viewable desktop (true) or to
- its previous desktop (false)
- */
- void iconify(bool iconic, bool curdesk = true);
-
- //! Maximize or unmaximize the client window
- /*!
- @param max true if the window should be maximized; false if it should be
- returned to normal size.
- @param dir 0 to set both horz and vert, 1 to set horz, 2 to set vert.
- @param savearea true to have the client's current size and position saved;
- otherwise, they are not. You should not save when mapping a
- new window that is set to fullscreen. This has no effect
- when unmaximizing a window.
- */
- void maximize(bool max, int dir, bool savearea = true);
-
- //! Internal version of the Client::move function
- /*!
- @param x The X coordinate to move to.
- @param y The Y coordinate to move to.
- @param final true if this is the final move, false if there are more move
- events coming. The client is not notified of the move when
- final is false.
- */
- void internal_move(int x, int y, bool final = true);
- //! Internal version of the Client::resize function
- /*!
- This also maintains things like the client's minsize, and size increments.
- @param anchor The corner to keep in the same position when resizing.
- @param w The width component of the new size for the client.
- @param h The height component of the new size for the client.
- @param user Specifies whether this is a user-requested change or a
- program requested change.
- @param x An optional X coordinate to which the window will be moved
- after resizing.
- @param y An optional Y coordinate to which the window will be moved
- after resizing.
- The x and y coordinates must both be sepcified together, or they will have
- no effect. When they are specified, the anchor is ignored.
- */
- void internal_resize(Corner anchor, int w, int h,
- bool user = true, int x = INT_MIN, int y = INT_MIN);
-
- //! Removes or reapplies the client's border to its window
- /*!
- Used when managing and unmanaging a window.
- @param addborder true if adding the border to the client; false if removing
- from the client
- */
- void toggleClientBorder(bool addborder);
-
- //! Applies the states requested when the window mapped
- /*!
- This should be called only once, during the window mapping process. It
- applies things like maximized, and fullscreen.
- */
- void applyStartupState();
-
-public:
- //! Constructs a new Client object around a specified window id
- /*!
- @param window The window id that the Client class should handle
- @param screen The screen on which the window resides
- */
- Client(int screen, Window window);
- //! Destroys the Client object
- virtual ~Client();
-
- //! Returns the screen on which the clien resides
- inline int screen() const { return _screen; }
-
- //! Returns the window id that the Client object is handling
- inline Window window() const { return _window; }
-
- //! Returns the type of the window, one of the Client::WindowType values
- inline WindowType type() const { return _type; }
- //! Returns if the window should be treated as a normal window.
- /*!
- Some windows (desktops, docks, splash screens) have special rules applied
- to them in a number of places regarding focus or user interaction.
- */
- inline bool normal() const {
- return ! (_type == Type_Desktop || _type == Type_Dock ||
- _type == Type_Splash);
- }
-
- //! Returns the desktop on which the window resides
- /*!
- This value is a 0-based index.<br>
- A value of 0xffffffff indicates that the window exists on all desktops.
- */
- inline unsigned int desktop() const { return _desktop; }
- //! Returns the window's title
- inline const otk::ustring &title() const { return _title; }
- //! Returns the window's title when it is iconified
- inline const otk::ustring &iconTitle() const { return _title; }
- //! Returns the application's name to whom the window belongs
- inline const std::string &appName() const { return _app_name; }
- //! Returns the class of the window
- inline const std::string &appClass() const { return _app_class; }
- //! Returns the program-specified role of the window
- inline const std::string &role() const { return _role; }
- //! Returns if the window can be focused
- /*!
- @return true if the window can receive focus; otherwise, false
- */
- inline bool canFocus() const { return _can_focus; }
- //! Returns if the window has indicated that it needs urgent attention
- inline bool urgent() const { return _urgent; }
- //! Returns if the window wants to be notified when it receives focus
- inline bool focusNotify() const { return _focus_notify; }
- //! Returns if the window is the focused window
- inline bool focused() const { return _focused; }
- //! Returns if the window uses the Shape extension
- inline bool shaped() const { return _shaped; }
- //! Returns the window's gravity
- /*!
- This value determines where to place the decorated window in relation to
- its position without decorations.<br>
- One of: NorthWestGravity, SouthWestGravity, EastGravity, ...,
- SouthGravity, StaticGravity, ForgetGravity
- */
- inline int gravity() const { return _gravity; }
- //! Returns if the application requested the initial position for the window
- /*!
- If the application did not request a position (this function returns false)
- then the window should be placed intelligently by the window manager
- initially
- */
- inline bool positionRequested() const { return _positioned; }
- //! Returns the decorations that the client window wishes to be displayed on
- //! it
- inline DecorationFlags decorations() const { return _decorations; }
- //! Returns the decorations that the user has requested to be disabled on the
- //! client
- inline DecorationFlags disabledDecorations() const
- { return _disabled_decorations; }
- //! Returns the functions that the user can perform on the window
- inline FunctionFlags functions() const { return _functions; }
-
- //! Return the client this window is transient for
- inline Client *transientFor() const { return _transient_for; }
-
- //! Returns if the window is modal
- /*!
- If the window is modal, then no other windows that it is related to can get
- focus while it exists/remains modal.
- */
- inline bool modal() const { return _modal; }
- //! The window should not be displayed by pagers
- inline bool skipPager() const { return _skip_pager; }
- //! The window should not be displayed by taskbars
- inline bool skipTaskbar() const { return _skip_taskbar; }
- //! Returns if the window is shaded
- /*!
- When the window is shaded, only its titlebar is visible.
- */
- inline bool shaded() const { return _shaded; }
- //! Returns if the window is in fullscreen mode
- inline bool fullscreen() const { return _fullscreen; }
- //! Returns if the window is iconified
- /*!
- When the window is iconified, it is not visible at all (except in iconbars/
- panels/etc that want to show lists of iconified windows
- */
- inline bool iconic() const { return _iconic; }
- //! Returns if the window is maximized vertically
- inline bool maxVert() const { return _max_vert; }
- //! Returns if the window is maximized horizontally
- inline bool maxHorz() const { return _max_horz; }
- //! Returns the window's stacking layer
- inline StackLayer layer() const { return _layer; }
-
- //! Returns the logical size of the window
- /*!
- The "logical" size of the window is refers to the user's perception of the
- size of the window, and is the value that should be displayed to the user.
- For example, with xterms, this value it the number of characters being
- displayed in the terminal, instead of the number of pixels.
- */
- const otk::Size &logicalSize() const { return _logical_size; }
-
- //! Returns the position and size of the client relative to the root window
- /*!
- Note that this value is *not* the size and position of the window's
- frame, though the position will often line up.<br>
- If you want the frame's area, use Frame::area() instead.
- */
- inline const otk::Rect &area() const { return _area; }
-
- //! Returns the client's strut definition
- inline const otk::Strut &strut() const { return _strut; }
-
- //! Returns an icon for the window
- /*!
- The icon chosen will be the smallest icon available that is still bigger or
- equal to the specified Size.<br>
- If none that meet the requirements is found, the largest icon that is
- smaller than the specified size will be returned.
- */
- const Icon *icon(const otk::Size &s) const;
-
- //! Returns the pixmap for the pixmap icon specified on the window (or None)
- /*!
- The icon given by Client::icon should take precedence over this icon/mask.
- */
- Pixmap pixmapIcon() const { return _pixmap_icon; }
- //! Returns the mask for the pixmap icon specified on the window (or None)
- /*!
- The icon given by Client::icon should take precedence over this icon/mask.
- */
- Pixmap pixmapIconMask() const { return _pixmap_icon_mask; }
-
- //! Move the window (actually, its frame) to a position.
- /*!
- This moves the window so that the top-left corner of its frame will be at
- the position specified.
- @param x The X coordinate to move to.
- @param y The Y coordinate to move to.
- @param final true if this is the final move, false if there are more move
- events coming. The client is not notified of the move when
- final is false.
- */
- void move(int x, int y, bool final = true);
-
- //! Resizes the client window, anchoring it in a given corner
- /*!
- This also maintains things like the client's minsize, and size increments.
- @param anchor The corner to keep in the same position when resizing.
- @param w The width component of the new size for the client.
- @param h The height component of the new size for the client.
- */
- void resize(Corner anchor, int w, int h);
-
- //! Reapplies the maximized state to the window
- /*!
- Use this to make the window readjust its maximized size to new
- surroundings (struts, etc).
- */
- void remaximize();
-
- //! Shows the window if it should be shown, or hides it
- /*!
- Used when changing desktops, the window's state, etc.
- */
- void showhide();
-
- //! Choose a mask of decorations to not display on the client
- /*!
- Pass a value of 0 to the function to turn all decorations back on. Note
- that you cannot add decorations to a window with this, you can only remove
- decorations that would otherwise have been displayed.
- @param flags The mask of values from Client::Decoration to specify which
- decorations should not be displayed.
- */
- void disableDecorations(DecorationFlags flags);
-
- //! Return a modal child of the client window
- /*!
- @return A modal child of the client window, or 0 if none was found.
- */
- Client *findModalChild();
-
- //! Attempt to focus the client window
- bool focus();
-
- //! Remove focus from the client window
- void unfocus() const;
-
- //! Validate client, by making sure no Destroy or Unmap events exist in
- //! the event queue for the window.
- /*!
- @return true if the client is valid; false if the client has already
- been unmapped/destroyed, and so is invalid.
- */
- bool validate() const;
-
- void installColormap(bool install) const;
-
- virtual void focusHandler(const XFocusChangeEvent &e);
- virtual void unfocusHandler(const XFocusChangeEvent &e);
- virtual void propertyHandler(const XPropertyEvent &e);
- virtual void clientMessageHandler(const XClientMessageEvent &e);
- virtual void configureRequestHandler(const XConfigureRequestEvent &e);
- virtual void unmapHandler(const XUnmapEvent &e);
- virtual void destroyHandler(const XDestroyWindowEvent &e);
- virtual void reparentHandler(const XReparentEvent &e);
- virtual void mapRequestHandler(const XMapRequestEvent &e);
-#if defined(SHAPE)
- virtual void shapeHandler(const XShapeEvent &e);
-#endif // SHAPE
-
- friend void Screen::manageWindow(Window);
- friend void Screen::unmanageWindow(Client *);
-};
-
-}
-
-#endif // __client_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-/*
- python_get_stringlist("DESKTOP_NAMES", &desktop_names);
-
- python_get_string("THEME", &theme);
- // initialize the screen's style
- otk::RenderStyle::setStyle(_screen, theme);
- // draw the root window
- otk::bexec("obsetroot " + otk::RenderStyle::style(_screen)->rootArgs(),
- info->displayString());
-
-
- if (!python_get_string("TITLEBAR_LAYOUT", &titlebar_layout)) {
- fprintf(stderr, _("Unable to load config.%s\n"), "TITLEBAR_LAYOUT");
- ::exit(1);
- }
-
- if (!python_get_long("DOUBLE_CLICK_DELAY", &double_click_delay)) {
- fprintf(stderr, _("Unable to load config.%s\n"), "DOUBLE_CLICK_DELAY");
- ::exit(1);
- }
- if (!python_get_long("DRAG_THRESHOLD", &drag_threshold)) {
- fprintf(stderr, _("Unable to load config.%s\n"), "DRAG_THRESHOLD");
- ::exit(1);
- }
- if (!python_get_long("NUMBER_OF_DESKTOPS", (long*)&num_desktops)) {
- fprintf(stderr, _("Unable to load config.%s\n"), "NUMBER_OF_DESKTOPS");
- ::exit(1);
- }
-
- // Set the net_desktop_names property
- otk::Property::set(root,
- otk::Property::atoms.net_desktop_names,
- otk::Property::utf8, desktop_names);
- // the above set() will cause screen::updateDesktopNames to fire right away
- // so we have a list of desktop names
-
- XEvent ce;
- ce.xclient.type = ClientMessage;
- ce.xclient.message_type = otk::Property::atoms.net_number_of_desktops;
- ce.xclient.display = **otk::display;
- ce.xclient.window = root;
- ce.xclient.format = 32;
- ce.xclient.data.l[0] = num_desktops;
- XSendEvent(**otk::display, root, False,
- SubstructureNotifyMask | SubstructureRedirectMask, &ce);
-}
-
-Config::Config(int screen)
- : _screen(screen)
-{
-}
-
-Config::~Config()
-{
-}
-
-*/
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __config_hh
-#define __config_hh
-
-/*! @file config.hh
- @brief The Config class contains functions for accessing config variables
- in the scripts.
-*/
-
-namespace ob {
-
-}
-
-#endif // __config_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-extern "C" {
-#ifdef SHAPE
-#include <X11/extensions/shape.h>
-#endif // SHAPE
-}
-
-#include "frame.hh"
-#include "config.hh"
-#include "openbox.hh"
-#include "otk/display.hh"
-#include "otk/surface.hh"
-
-#include <string>
-#include <cassert>
-
-namespace ob {
-
-const long Frame::event_mask;
-
-Window createWindow(const otk::ScreenInfo *info, Window parent,
- unsigned long mask, XSetWindowAttributes *attrib)
-{
- return XCreateWindow(**otk::display, parent, 0, 0, 1, 1, 0,
- info->depth(), InputOutput, info->visual(),
- mask, attrib);
-
-}
-
-Frame::Frame(Client *client)
- : _client(client),
- _visible(false),
- _plate(0),
- _title(0),
- _label(0),
- _handle(0),
- _lgrip(0),
- _rgrip(0),
- _max(0),
- _desk(0),
- _iconify(0),
- _icon(0),
- _close(0),
- _frame_sur(0),
- _title_sur(0),
- _label_sur(0),
- _handle_sur(0),
- _grip_sur(0),
- _max_sur(0),
- _desk_sur(0),
- _iconify_sur(0),
- _icon_sur(0),
- _close_sur(0),
- _max_press(false),
- _desk_press(false),
- _iconify_press(false),
- _icon_press(false),
- _close_press(false),
- _press_button(0)
-{
- assert(client);
-
- XSetWindowAttributes attrib;
- unsigned long mask;
- const otk::ScreenInfo *info = otk::display->screenInfo(client->screen());
-
- // create all of the decor windows (except title bar buttons)
- mask = CWOverrideRedirect | CWEventMask;
- attrib.event_mask = Frame::event_mask;
- attrib.override_redirect = true;
- _frame = createWindow(info, info->rootWindow(), mask, &attrib);
-
- mask = 0;
- _plate = createWindow(info, _frame, mask, &attrib);
- mask = CWEventMask;
- attrib.event_mask = (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
- ExposureMask);
- _title = createWindow(info, _frame, mask, &attrib);
- _label = createWindow(info, _title, mask, &attrib);
- _max = createWindow(info, _title, mask, &attrib);
- _close = createWindow(info, _title, mask, &attrib);
- _desk = createWindow(info, _title, mask, &attrib);
- _icon = createWindow(info, _title, mask, &attrib);
- _iconify = createWindow(info, _title, mask, &attrib);
- _handle = createWindow(info, _frame, mask, &attrib);
- mask |= CWCursor;
- attrib.cursor = openbox->cursors().ll_angle;
- _lgrip = createWindow(info, _handle, mask, &attrib);
- attrib.cursor = openbox->cursors().lr_angle;
- _rgrip = createWindow(info, _handle, mask, &attrib);
-
- // the other stuff is shown based on decor settings
- XMapWindow(**otk::display, _plate);
- XMapWindow(**otk::display, _lgrip);
- XMapWindow(**otk::display, _rgrip);
- XMapWindow(**otk::display, _label);
-
- applyStyle(*otk::RenderStyle::style(_client->screen()));
-
- _layout = "ITMC";
- python_get_string("titlebar_layout", &_layout);
-
- // register all of the windows with the event dispatcher
- Window *w = allWindows();
- for (unsigned int i = 0; w[i]; ++i)
- openbox->registerHandler(w[i], this);
- delete [] w;
-}
-
-Frame::~Frame()
-{
- // unregister all of the windows with the event dispatcher
- Window *w = allWindows();
- for (unsigned int i = 0; w[i]; ++i)
- openbox->clearHandler(w[i]);
- delete [] w;
-
- XDestroyWindow(**otk::display, _rgrip);
- XDestroyWindow(**otk::display, _lgrip);
- XDestroyWindow(**otk::display, _handle);
- XDestroyWindow(**otk::display, _max);
- XDestroyWindow(**otk::display, _icon);
- XDestroyWindow(**otk::display, _iconify);
- XDestroyWindow(**otk::display, _desk);
- XDestroyWindow(**otk::display, _close);
- XDestroyWindow(**otk::display, _label);
- XDestroyWindow(**otk::display, _title);
- XDestroyWindow(**otk::display, _frame);
-
- if (_frame_sur) delete _frame_sur;
- if (_title_sur) delete _title_sur;
- if (_label_sur) delete _label_sur;
- if (_handle_sur) delete _handle_sur;
- if (_grip_sur) delete _grip_sur;
- if (_max_sur) delete _max_sur;
- if (_desk_sur) delete _desk_sur;
- if (_iconify_sur) delete _iconify_sur;
- if (_icon_sur) delete _icon_sur;
- if (_close_sur) delete _close_sur;
-}
-
-void Frame::show()
-{
- if (!_visible) {
- _visible = true;
- XMapWindow(**otk::display, _frame);
- }
-}
-
-void Frame::hide()
-{
- if (_visible) {
- _visible = false;
- XUnmapWindow(**otk::display, _frame);
- }
-}
-
-void Frame::buttonPressHandler(const XButtonEvent &e)
-{
- if (_press_button) return;
- _press_button = e.button;
-
- if (e.window == _max) {
- _max_press = true;
- renderMax();
- }
- if (e.window == _close) {
- _close_press = true;
- renderClose();
- }
- if (e.window == _desk) {
- _desk_press = true;
- renderDesk();
- }
- if (e.window == _iconify) {
- _iconify_press = true;
- renderIconify();
- }
- if (e.window == _icon) {
- _icon_press = true;
- renderIcon();
- }
-}
-
-void Frame::buttonReleaseHandler(const XButtonEvent &e)
-{
- if (e.button != _press_button) return;
- _press_button = 0;
-
- if (e.window == _max) {
- _max_press = false;
- renderMax();
- }
- if (e.window == _close) {
- _close_press = false;
- renderClose();
- }
- if (e.window == _desk) {
- _desk_press = false;
- renderDesk();
- }
- if (e.window == _iconify) {
- _iconify_press = false;
- renderIconify();
- }
- if (e.window == _icon) {
- _icon_press = false;
- renderIcon();
- }
-}
-
-MouseContext::MC Frame::mouseContext(Window win) const
-{
- if (win == _frame) return MouseContext::Frame;
- if (win == _title ||
- win == _label) return MouseContext::Titlebar;
- if (win == _handle) return MouseContext::Handle;
- if (win == _plate) return MouseContext::Window;
- if (win == _lgrip ||
- win == _rgrip) return MouseContext::Grip;
- if (win == _max) return MouseContext::MaximizeButton;
- if (win == _close) return MouseContext::CloseButton;
- if (win == _desk) return MouseContext::AllDesktopsButton;
- if (win == _iconify)return MouseContext::IconifyButton;
- if (win == _icon) return MouseContext::IconButton;
- return (MouseContext::MC) -1;
-}
-
-Window *Frame::allWindows() const
-{
- Window *w = new Window[12 + 1];
- unsigned int i = 0;
- w[i++] = _frame;
- w[i++] = _plate;
- w[i++] = _title;
- w[i++] = _label;
- w[i++] = _handle;
- w[i++] = _lgrip;
- w[i++] = _rgrip;
- w[i++] = _max;
- w[i++] = _desk;
- w[i++] = _close;
- w[i++] = _icon;
- w[i++] = _iconify;
- w[i] = 0;
- return w;
-}
-
-void Frame::applyStyle(const otk::RenderStyle &style)
-{
- // set static border colors
- XSetWindowBorder(**otk::display, _frame, style.frameBorderColor()->pixel());
- XSetWindowBorder(**otk::display, _title, style.frameBorderColor()->pixel());
- XSetWindowBorder(**otk::display, _handle, style.frameBorderColor()->pixel());
- XSetWindowBorder(**otk::display, _lgrip, style.frameBorderColor()->pixel());
- XSetWindowBorder(**otk::display, _rgrip, style.frameBorderColor()->pixel());
-
- // size all the fixed-size elements
- geom.font_height = style.labelFont()->height();
- if (geom.font_height < 1) geom.font_height = 1;
- geom.button_size = geom.font_height - 2;
- if (geom.button_size < 1) geom.button_size = 1;
- geom.handle_height = style.handleWidth();
- if (geom.handle_height < 1) geom.handle_height = 1;
- geom.bevel = style.bevelWidth();
-
- XResizeWindow(**otk::display, _lgrip, geom.grip_width(), geom.handle_height);
- XResizeWindow(**otk::display, _rgrip, geom.grip_width(), geom.handle_height);
-
- XResizeWindow(**otk::display, _max, geom.button_size, geom.button_size);
- XResizeWindow(**otk::display, _close, geom.button_size, geom.button_size);
- XResizeWindow(**otk::display, _desk, geom.button_size, geom.button_size);
- XResizeWindow(**otk::display, _iconify, geom.button_size, geom.button_size);
- XResizeWindow(**otk::display, _icon, geom.button_size, geom.button_size);
-}
-
-void Frame::styleChanged(const otk::RenderStyle &style)
-{
- applyStyle(style);
-
- // size/position everything
- adjustSize();
- adjustPosition();
-}
-
-void Frame::adjustFocus()
-{
- // XXX optimizations later...
- adjustSize();
-}
-
-void Frame::adjustTitle()
-{
- // XXX optimizations later...
- adjustSize();
-}
-
-static void render(int screen, const otk::Size &size, Window win,
- otk::Surface **surface,
- const otk::RenderTexture &texture, bool freedata=true)
-{
- otk::Surface *s = new otk::Surface(screen, size);
- if (texture.parentRelative())
- XSetWindowBackgroundPixmap(**otk::display, win, ParentRelative);
- else {
- otk::display->renderControl(screen)->drawBackground(*s, texture);
- XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
- }
- XClearWindow(**otk::display, win);
- if (*surface) delete *surface;
- if (freedata) s->freePixelData();
- *surface = s;
-}
-
-void Frame::adjustSize()
-{
- _decorations = _client->decorations();
- const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
-
- if (_decorations & Client::Decor_Border) {
- geom.bwidth = style->frameBorderWidth();
- geom.cbwidth = style->clientBorderWidth();
- } else {
- geom.bwidth = geom.cbwidth = 0;
- }
- _innersize.left = _innersize.top = _innersize.bottom = _innersize.right =
- geom.cbwidth;
- geom.width = _client->area().width() + geom.cbwidth * 2;
- assert(geom.width > 0);
-
- // set border widths
- XSetWindowBorderWidth(**otk::display, _plate, geom.cbwidth);
- XSetWindowBorderWidth(**otk::display, _frame, geom.bwidth);
- XSetWindowBorderWidth(**otk::display, _title, geom.bwidth);
- XSetWindowBorderWidth(**otk::display, _handle, geom.bwidth);
- XSetWindowBorderWidth(**otk::display, _lgrip, geom.bwidth);
- XSetWindowBorderWidth(**otk::display, _rgrip, geom.bwidth);
-
- // position/size and map/unmap all the windows
-
- if (_decorations & Client::Decor_Titlebar) {
- XMoveResizeWindow(**otk::display, _title, -geom.bwidth, -geom.bwidth,
- geom.width, geom.title_height());
- _innersize.top += geom.title_height() + geom.bwidth;
- XMapWindow(**otk::display, _title);
-
- // layout the title bar elements
- layoutTitle();
- } else {
- XUnmapWindow(**otk::display, _title);
- // make all the titlebar stuff not render
- _decorations &= ~(Client::Decor_Icon | Client::Decor_Iconify |
- Client::Decor_Maximize | Client::Decor_Close |
- Client::Decor_AllDesktops);
- }
-
- if (_decorations & Client::Decor_Handle) {
- geom.handle_y = _innersize.top + _client->area().height() + geom.cbwidth;
- XMoveResizeWindow(**otk::display, _handle, -geom.bwidth, geom.handle_y,
- geom.width, geom.handle_height);
- XMoveWindow(**otk::display, _lgrip, -geom.bwidth, -geom.bwidth);
- XMoveWindow(**otk::display, _rgrip,
- -geom.bwidth + geom.width - geom.grip_width(),
- -geom.bwidth);
- _innersize.bottom += geom.handle_height + geom.bwidth;
- XMapWindow(**otk::display, _handle);
- } else
- XUnmapWindow(**otk::display, _handle);
-
- XResizeWindow(**otk::display, _frame, geom.width,
- (_client->shaded() ? geom.title_height() :
- _innersize.top + _innersize.bottom +
- _client->area().height()));
-
- // do this in two steps because clients whose gravity is set to
- // 'Static' don't end up getting moved at all with an XMoveResizeWindow
- XMoveWindow(**otk::display, _plate, _innersize.left - geom.cbwidth,
- _innersize.top - geom.cbwidth);
- XResizeWindow(**otk::display, _plate, _client->area().width(),
- _client->area().height());
-
- _size.left = _innersize.left + geom.bwidth;
- _size.right = _innersize.right + geom.bwidth;
- _size.top = _innersize.top + geom.bwidth;
- _size.bottom = _innersize.bottom + geom.bwidth;
-
- _area = otk::Rect(_area.position(), otk::Size(_client->area().width() +
- _size.left + _size.right,
- _client->area().height() +
- _size.top + _size.bottom));
-
- // render all the elements
- int screen = _client->screen();
- bool focus = _client->focused();
- if (_decorations & Client::Decor_Titlebar) {
- render(screen, otk::Size(geom.width, geom.title_height()), _title,
- &_title_sur, *(focus ? style->titlebarFocusBackground() :
- style->titlebarUnfocusBackground()), false);
-
- renderLabel();
- renderMax();
- renderDesk();
- renderIconify();
- renderIcon();
- renderClose();
- }
-
- if (_decorations & Client::Decor_Handle) {
- render(screen, otk::Size(geom.width, geom.handle_height), _handle,
- &_handle_sur, *(focus ? style->handleFocusBackground() :
- style->handleUnfocusBackground()));
- render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip,
- &_grip_sur, *(focus ? style->gripFocusBackground() :
- style->gripUnfocusBackground()));
- if ((focus ? style->gripFocusBackground() :
- style->gripUnfocusBackground())->parentRelative())
- XSetWindowBackgroundPixmap(**otk::display, _rgrip, ParentRelative);
- else {
- XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap());
- }
- XClearWindow(**otk::display, _rgrip);
- }
-
- XSetWindowBorder(**otk::display, _plate,
- focus ? style->clientBorderFocusColor()->pixel() :
- style->clientBorderUnfocusColor()->pixel());
-
- adjustShape();
-}
-
-void Frame::renderLabel()
-{
- const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen());
- const otk::RenderControl *control =
- otk::display->renderControl(_client->screen());
- const otk::Font *font = style->labelFont();
-
- otk::Surface *s = new otk::Surface(_client->screen(),
- otk::Size(geom.label_width,
- geom.label_height()));
- const otk::RenderTexture *tx = (_client->focused() ?
- style->labelFocusBackground() :
- style->labelUnfocusBackground());
- if (tx->parentRelative()) {
- otk::pixel32 *dest = s->pixelData(), *src;
- int w = _title_sur->size().width();
-
- src = _title_sur->pixelData() + w * geom.bevel + geom.title_x;
-
- // get the background under the label
- int xd = s->size().width();
- int yd = s->size().height();
- for (int y = 0; y < yd; ++y, src += w - xd)
- for (int x = 0; x < xd; ++x, ++dest, ++src)
- *dest = *src;
- control->drawImage(*s, 0, 0, 0); // no image but draw the new background
- } else
- control->drawBackground(*s, *tx);
-
- otk::ustring t = _client->title(); // the actual text to draw
- int x = geom.bevel; // x coord for the text
-
- if (x * 2 < geom.label_width) {
- // find a string that will fit inside the area for text
- otk::ustring::size_type text_len = t.size();
- int length;
- int maxsize = geom.label_width - geom.bevel * 2;
-
- do {
- t.resize(text_len);
- length = font->measureString(t);// this returns an unsigned, so check < 0
- if (length < 0) length = maxsize;// if the string's that long just adjust
- } while (length > maxsize && text_len-- > 0);
-
- // justify the text
- switch (style->labelTextJustify()) {
- case otk::RenderStyle::RightBottomJustify:
- x += maxsize - length;
- break;
- case otk::RenderStyle::CenterJustify:
- x += (maxsize - length) / 2;
- break;
- case otk::RenderStyle::LeftTopJustify:
- break;
- }
-
- if (text_len > 0)
- control->drawString(*s, *font, x, 0,
- *(_client->focused() ? style->textFocusColor() :
- style->textUnfocusColor()), t);
- }
-
- XSetWindowBackgroundPixmap(**otk::display, _label, s->pixmap());
- XClearWindow(**otk::display, _label);
- if (_label_sur) delete _label_sur;
- s->freePixelData();
- _label_sur = s;
-}
-
-static void renderButton(int screen, bool focus, bool press, Window win,
- otk::Surface **sur, int butsize,
- const otk::PixmapMask *mask, int xoffset, int yoffset,
- otk::Surface *bgsurface)
-{
- const otk::RenderStyle *style = otk::RenderStyle::style(screen);
- const otk::RenderControl *control = otk::display->renderControl(screen);
- otk::Surface *s = new otk::Surface(screen, otk::Size(butsize, butsize));
-
- const otk::RenderTexture *tx = (focus ?
- (press ?
- style->buttonPressFocusBackground() :
- style->buttonUnpressFocusBackground()) :
- (press ?
- style->buttonPressUnfocusBackground() :
- style->buttonUnpressUnfocusBackground()));
- const otk::RenderColor *maskcolor = (focus ?
- style->buttonFocusColor() :
- style->buttonUnfocusColor());
- if (tx->parentRelative()) {
- otk::pixel32 *dest = s->pixelData(), *src;
- int w = bgsurface->size().width();
-
- src = bgsurface->pixelData() + w * yoffset + xoffset;
-
- // get the background under the button
- for (int y = 0; y < butsize; ++y, src += w - butsize)
- for (int x = 0; x < butsize; ++x, ++dest, ++src)
- *dest = *src;
- control->drawImage(*s, 0, 0, 0); // no image but draw the new background
- } else
- control->drawBackground(*s, *tx);
- control->drawMask(*s, *maskcolor, *mask);
-
- XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap());
- XClearWindow(**otk::display, win);
- if (*sur) delete *sur;
- s->freePixelData();
- *sur = s;
-}
-
-void Frame::renderMax()
-{
- if (!(_decorations & Client::Decor_Maximize)) return;
- bool press = _max_press || _client->maxVert() || _client->maxHorz();
- renderButton(_client->screen(), _client->focused(), press, _max,
- &_max_sur, geom.button_size,
- otk::RenderStyle::style(_client->screen())->maximizeMask(),
- geom.max_x, (geom.bevel + 1), _title_sur);
-}
-
-void Frame::renderDesk()
-{
- if (!(_decorations & Client::Decor_AllDesktops)) return;
- bool press = _desk_press || _client->desktop() == 0xffffffff;
- renderButton(_client->screen(), _client->focused(), press, _desk,
- &_desk_sur, geom.button_size,
- otk::RenderStyle::style(_client->screen())->alldesktopsMask(),
- geom.desktop_x, (geom.bevel + 1), _title_sur);
-}
-
-void Frame::renderIconify()
-{
- if (!(_decorations & Client::Decor_Iconify)) return;
- renderButton(_client->screen(), _client->focused(), _iconify_press, _iconify,
- &_iconify_sur, geom.button_size,
- otk::RenderStyle::style(_client->screen())->iconifyMask(),
- geom.iconify_x, (geom.bevel + 1), _title_sur);
-}
-
-void Frame::renderClose()
-{
- if (!(_decorations & Client::Decor_Close)) return;
- renderButton(_client->screen(), _client->focused(), _close_press, _close,
- &_close_sur, geom.button_size,
- otk::RenderStyle::style(_client->screen())->closeMask(),
- geom.close_x, (geom.bevel + 1), _title_sur);
-}
-
-void Frame::renderIcon()
-{
- if (!(_decorations & Client::Decor_Icon)) return;
- const int screen = _client->screen();
- const otk::RenderControl *control = otk::display->renderControl(screen);
-
- otk::Surface *s = new otk::Surface(screen, otk::Size(geom.button_size,
- geom.button_size));
- otk::pixel32 *dest = s->pixelData(), *src;
- int w = _title_sur->size().width();
-
- src = _title_sur->pixelData() + w * (geom.bevel + 1) + geom.icon_x;
-
- // get the background under the icon button
- for (int y = 0; y < geom.button_size; ++y, src += w - geom.button_size)
- for (int x = 0; x < geom.button_size; ++x, ++dest, ++src)
- *dest = *src;
- // draw the icon over it
- const Icon *icon = _client->icon(otk::Size(geom.button_size,
- geom.button_size));
- control->drawImage(*s, icon->w, icon->h, icon->data);
- if (!icon->data) {
- Pixmap p = _client->pixmapIcon(), m = _client->pixmapIconMask();
- if (p != None)
- control->drawImage(*s, p, m);
- }
-
- XSetWindowBackgroundPixmap(**otk::display, _icon, s->pixmap());
- XClearWindow(**otk::display, _icon);
- if (_icon_sur) delete _icon_sur;
- _icon_sur = s;
-}
-
-void Frame::layoutTitle()
-{
- // figure out whats being shown, and the width of the label
- geom.label_width = geom.width - geom.bevel * 2;
- bool n, d, i, t, m ,c;
- n = d = i = t = m = c = false;
- for (const char *l = _layout.c_str(); *l; ++l) {
- switch (*l) {
- case 'n':
- case 'N':
- if (!(_decorations & Client::Decor_Icon)) break;
- n = true;
- geom.label_width -= geom.button_size + geom.bevel;
- break;
- case 'd':
- case 'D':
- if (!(_decorations & Client::Decor_AllDesktops)) break;
- d = true;
- geom.label_width -= geom.button_size + geom.bevel;
- break;
- case 'i':
- case 'I':
- if (!(_decorations & Client::Decor_Iconify)) break;
- i = true;
- geom.label_width -= geom.button_size + geom.bevel;
- break;
- case 't':
- case 'T':
- t = true;
- break;
- case 'm':
- case 'M':
- if (!(_decorations & Client::Decor_Maximize)) break;
- m = true;
- geom.label_width -= geom.button_size + geom.bevel;
- break;
- case 'c':
- case 'C':
- if (!(_decorations & Client::Decor_Close)) break;
- c = true;
- geom.label_width -= geom.button_size + geom.bevel;
- break;
- }
- }
- if (geom.label_width < 1) geom.label_width = 1;
-
- XResizeWindow(**otk::display, _label, geom.label_width, geom.font_height);
-
- if (!n) {
- _decorations &= ~Client::Decor_Icon;
- XUnmapWindow(**otk::display, _icon);
- }
- if (!d) {
- _decorations &= ~Client::Decor_AllDesktops;
- XUnmapWindow(**otk::display, _desk);
- }
- if (!i) {
- _decorations &= ~Client::Decor_Iconify;
- XUnmapWindow(**otk::display, _iconify);
- }
- if (!t)
- XUnmapWindow(**otk::display, _label);
- if (!m) {
- _decorations &= ~Client::Decor_Maximize;
- XUnmapWindow(**otk::display, _max);
- }
- if (!c) {
- _decorations &= ~Client::Decor_Close;
- XUnmapWindow(**otk::display, _close);
- }
-
- int x = geom.bevel;
- for (const char *lc = _layout.c_str(); *lc; ++lc) {
- switch (*lc) {
- case 'n':
- case 'N':
- if (!n) break;
- geom.icon_x = x;
- XMapWindow(**otk::display, _icon);
- XMoveWindow(**otk::display, _icon, x, geom.bevel + 1);
- x += geom.button_size + geom.bevel;
- break;
- case 'd':
- case 'D':
- if (!d) break;
- geom.desktop_x = x;
- XMapWindow(**otk::display, _desk);
- XMoveWindow(**otk::display, _desk, x, geom.bevel + 1);
- x += geom.button_size + geom.bevel;
- break;
- case 'i':
- case 'I':
- if (!i) break;
- geom.iconify_x = x;
- XMapWindow(**otk::display, _iconify);
- XMoveWindow(**otk::display, _iconify, x, geom.bevel + 1);
- x += geom.button_size + geom.bevel;
- break;
- case 't':
- case 'T':
- if (!t) break;
- geom.title_x = x;
- XMapWindow(**otk::display, _label);
- XMoveWindow(**otk::display, _label, x, geom.bevel);
- x += geom.label_width + geom.bevel;
- break;
- case 'm':
- case 'M':
- if (!m) break;
- geom.max_x = x;
- XMapWindow(**otk::display, _max);
- XMoveWindow(**otk::display, _max, x, geom.bevel + 1);
- x += geom.button_size + geom.bevel;
- break;
- case 'c':
- case 'C':
- if (!c) break;
- geom.close_x = x;
- XMapWindow(**otk::display, _close);
- XMoveWindow(**otk::display, _close, x, geom.bevel + 1);
- x += geom.button_size + geom.bevel;
- break;
- }
- }
-}
-
-void Frame::adjustPosition()
-{
- int x, y;
- x = _client->area().x();
- y = _client->area().y();
- clientGravity(x, y);
- XMoveWindow(**otk::display, _frame, x, y);
- _area = otk::Rect(otk::Point(x, y), _area.size());
-}
-
-
-void Frame::adjustShape()
-{
-#ifdef SHAPE
- if (!_client->shaped()) {
- // clear the shape on the frame window
- XShapeCombineMask(**otk::display, _frame, ShapeBounding,
- _innersize.left,
- _innersize.top,
- None, ShapeSet);
- } else {
- // make the frame's shape match the clients
- XShapeCombineShape(**otk::display, _frame, ShapeBounding,
- _innersize.left,
- _innersize.top,
- _client->window(), ShapeBounding, ShapeSet);
-
- int num = 0;
- XRectangle xrect[2];
-
- if (_decorations & Client::Decor_Titlebar) {
- xrect[0].x = -geom.bevel;
- xrect[0].y = -geom.bevel;
- xrect[0].width = geom.width + geom.bwidth * 2;
- xrect[0].height = geom.title_height() + geom.bwidth * 2;
- ++num;
- }
-
- if (_decorations & Client::Decor_Handle) {
- xrect[1].x = -geom.bevel;
- xrect[1].y = geom.handle_y;
- xrect[1].width = geom.width + geom.bwidth * 2;
- xrect[1].height = geom.handle_height + geom.bwidth * 2;
- ++num;
- }
-
- XShapeCombineRectangles(**otk::display, _frame,
- ShapeBounding, 0, 0, xrect, num,
- ShapeUnion, Unsorted);
- }
-#endif // SHAPE
-}
-
-void Frame::adjustState()
-{
- renderDesk();
- renderMax();
-}
-
-void Frame::adjustIcon()
-{
- renderIcon();
-}
-
-void Frame::grabClient()
-{
- // reparent the client to the frame
- XReparentWindow(**otk::display, _client->window(), _plate, 0, 0);
- /*
- When reparenting the client window, it is usually not mapped yet, since
- this occurs from a MapRequest. However, in the case where Openbox is
- starting up, the window is already mapped, so we'll see unmap events for
- it. There are 2 unmap events generated that we see, one with the 'event'
- member set the root window, and one set to the client, but both get handled
- and need to be ignored.
- */
- if (openbox->state() == Openbox::State_Starting)
- _client->ignore_unmaps += 2;
-
- // select the event mask on the client's parent (to receive config/map req's)
- // the ButtonPress is to catch clicks on the client border
- XSelectInput(**otk::display, _plate, (SubstructureRedirectMask |
- ButtonPressMask));
-
- // map the client so it maps when the frame does
- XMapWindow(**otk::display, _client->window());
-
- adjustSize();
- adjustPosition();
-}
-
-
-void Frame::releaseClient()
-{
- XEvent ev;
-
- // check if the app has already reparented its window away
- if (XCheckTypedWindowEvent(**otk::display, _client->window(),
- ReparentNotify, &ev)) {
- XPutBackEvent(**otk::display, &ev);
- // re-map the window since the unmanaging process unmaps it
- XMapWindow(**otk::display, _client->window());
- } else {
- // according to the ICCCM - if the client doesn't reparent itself, then we
- // will reparent the window to root for them
- XReparentWindow(**otk::display, _client->window(),
- otk::display->screenInfo(_client->screen())->rootWindow(),
- _client->area().x(), _client->area().y());
- }
-}
-
-
-void Frame::clientGravity(int &x, int &y)
-{
- // horizontal
- switch (_client->gravity()) {
- default:
- case NorthWestGravity:
- case SouthWestGravity:
- case WestGravity:
- break;
-
- case NorthGravity:
- case SouthGravity:
- case CenterGravity:
- x -= (_size.left + _size.right) / 2;
- break;
-
- case NorthEastGravity:
- case SouthEastGravity:
- case EastGravity:
- x -= _size.left + _size.right;
- break;
-
- case ForgetGravity:
- case StaticGravity:
- x -= _size.left;
- break;
- }
-
- // vertical
- switch (_client->gravity()) {
- default:
- case NorthWestGravity:
- case NorthEastGravity:
- case NorthGravity:
- break;
-
- case CenterGravity:
- case EastGravity:
- case WestGravity:
- y -= (_size.top + _size.bottom) / 2;
- break;
-
- case SouthWestGravity:
- case SouthEastGravity:
- case SouthGravity:
- y -= _size.top + _size.bottom;
- break;
-
- case ForgetGravity:
- case StaticGravity:
- y -= _size.top;
- break;
- }
-}
-
-
-void Frame::frameGravity(int &x, int &y)
-{
- // horizontal
- switch (_client->gravity()) {
- default:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- break;
- case NorthGravity:
- case CenterGravity:
- case SouthGravity:
- x += (_size.left + _size.right) / 2;
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- x += _size.left + _size.right;
- break;
- case StaticGravity:
- case ForgetGravity:
- x += _size.left;
- break;
- }
-
- // vertical
- switch (_client->gravity()) {
- default:
- case NorthWestGravity:
- case WestGravity:
- case SouthWestGravity:
- break;
- case NorthGravity:
- case CenterGravity:
- case SouthGravity:
- y += (_size.top + _size.bottom) / 2;
- break;
- case NorthEastGravity:
- case EastGravity:
- case SouthEastGravity:
- y += _size.top + _size.bottom;
- break;
- case StaticGravity:
- case ForgetGravity:
- y += _size.top;
- break;
- }
-}
-
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __frame_hh
-#define __frame_hh
-
-/*! @file frame.hh
-*/
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include "client.hh"
-#include "python.hh"
-#include "otk/strut.hh"
-#include "otk/rect.hh"
-#include "otk/renderstyle.hh"
-#include "otk/ustring.hh"
-#include "otk/surface.hh"
-#include "otk/eventhandler.hh"
-
-#include <string>
-#include <vector>
-
-namespace ob {
-
-//! Varius geometry settings in the frame decorations
-struct FrameGeometry {
- int width; // title and handle
- int font_height;
- int title_height() { return font_height + bevel*2; }
- int label_width;
- int label_height() { return font_height; }
- int handle_height; // static, from the style
- int icon_x; // x-position of the window icon button
- int title_x; // x-position of the window title
- int iconify_x; // x-position of the window iconify button
- int desktop_x; // x-position of the window all-desktops button
- int max_x; // x-position of the window maximize button
- int close_x; // x-position of the window close button
- int handle_y;
- int button_size; // static, from the style
- int grip_width() { return button_size * 2; }
- int bevel; // static, from the style
- int bwidth; // frame elements' border width
- int cbwidth; // client border width
-};
-
-//! Holds and decorates a frame around an Client (client window)
-/*!
- The frame is responsible for calling XSelectInput on the client window's new
- parent with the SubstructureRedirectMask so that structure events for the
- client are sent to the window manager.
-*/
-class Frame : public otk::StyleNotify, public otk::EventHandler {
-public:
-
- //! The event mask to grab on frame windows
- static const long event_mask = EnterWindowMask | LeaveWindowMask;
-
-private:
- Client *_client;
-
- //! The size of the frame on each side of the client window
- otk::Strut _size;
-
- //! The size of the frame on each side of the client window inside the border
- otk::Strut _innersize;
-
- //! The position and size of the entire frame (including borders)
- otk::Rect _area;
-
- bool _visible;
-
- //! The decorations that are being displayed in the frame.
- Client::DecorationFlags _decorations;
-
- // decoration windows
- Window _frame; // sits under everything
- Window _plate; // sits entirely under the client window
- Window _title; // the titlebar
- Window _label; // the section of the titlebar which shows the window name
- Window _handle; // bottom bar
- Window _lgrip; // lefthand resize grab on the handle
- Window _rgrip; // righthand resize grab on the handle
- Window _max; // maximize button
- Window _desk; // all-desktops button
- Window _iconify; // iconify button
- Window _icon; // window icon button
- Window _close; // close button
-
- // surfaces for each
- otk::Surface *_frame_sur;
- otk::Surface *_title_sur;
- otk::Surface *_label_sur;
- otk::Surface *_handle_sur;
- otk::Surface *_grip_sur;
- otk::Surface *_max_sur;
- otk::Surface *_desk_sur;
- otk::Surface *_iconify_sur;
- otk::Surface *_icon_sur;
- otk::Surface *_close_sur;
-
- otk::ustring _layout; // layout of the titlebar
-
- bool _max_press;
- bool _desk_press;
- bool _iconify_press;
- bool _icon_press;
- bool _close_press;
- unsigned int _press_button; // mouse button that started the press
-
- FrameGeometry geom;
-
- void applyStyle(const otk::RenderStyle &style);
- void layoutTitle();
- void renderLabel();
- void renderMax();
- void renderDesk();
- void renderIconify();
- void renderClose();
- void renderIcon();
-
-public:
- //! Constructs an Frame object for a client
- /*!
- @param client The client which will be decorated by the new Frame
- */
- Frame(Client *client);
- //! Destroys the Frame object
- virtual ~Frame();
-
- //! Returns the size of the frame on each side of the client
- const otk::Strut& size() const { return _size; }
-
- //! Set the style to decorate the frame with
- virtual void styleChanged(const otk::RenderStyle &style);
-
- //! Reparents the client window from the root window onto the frame
- void grabClient();
- //! Reparents the client window back to the root window
- void releaseClient();
-
- //! Update the frame's size to match the client
- void adjustSize();
- //! Update the frame's position to match the client
- void adjustPosition();
- //! Shape the frame window to the client window
- void adjustShape();
- //! Update the frame to match the client's new state (for things like toggle
- //! buttons, focus, and the title) XXX break this up
- void adjustState();
- void adjustFocus();
- void adjustTitle();
- void adjustIcon();
-
- //! Applies gravity to the client's position to find where the frame should
- //! be positioned.
- /*!
- @return The proper coordinates for the frame, based on the client.
- */
- void clientGravity(int &x, int &y);
-
- //! Reversly applies gravity to the frame's position to find where the client
- //! should be positioned.
- /*!
- @return The proper coordinates for the client, based on the frame.
- */
- void frameGravity(int &x, int &y);
-
- //! The position and size of the frame window
- inline const otk::Rect& area() const { return _area; }
-
- //! Returns if the frame is visible
- inline bool visible() const { return _visible; }
-
- //! Shows the frame
- void show();
- //! Hides the frame
- void hide();
-
- void buttonPressHandler(const XButtonEvent &e);
- void buttonReleaseHandler(const XButtonEvent &e);
-
- //! Returns the MouseContext for the given window id
- /*!
- Returns '-1' if no valid mouse context exists in the frame for the given
- id.
- */
- ob::MouseContext::MC mouseContext(Window win) const;
-
- //! Gets the window id of the frame's base top-level parent
- inline Window window() const { return _frame; }
- //! Gets the window id of the client's parent window
- inline Window plate() const { return _plate; }
-
- //! Returns a null terminated array of the window ids that make up the
- //! frame's decorations.
- Window *allWindows() const;
-};
-
-}
-
-#endif // __frame_hh
+++ /dev/null
-/* Convenience header for conditional use of GNU <libintl.h>.
- Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- USA. */
-
-#ifndef _LIBGETTEXT_H
-#define _LIBGETTEXT_H 1
-
-
-/* NLS can be disabled through the configure --disable-nls option. */
-#if ENABLE_NLS
-
-/* Get declarations of GNU message catalog functions. */
-# include <libintl.h>
-
-#else
-
-/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
- chokes if dcgettext is defined as a macro. So include it now, to make
- later inclusions of <locale.h> a NOP. We don't include <libintl.h>
- as well because people using "gettext.h" will not include <libintl.h>,
- and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
- is OK. */
-#if defined(__sun)
-# include <locale.h>
-#endif
-
-/* Disabled NLS.
- The casts to 'const char *' serve the purpose of producing warnings
- for invalid uses of the value returned from these functions.
- On pre-ANSI systems without 'const', the config.h file is supposed to
- contain "#define const". */
-# define gettext(Msgid) ((const char *) (Msgid))
-# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
-# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
-# define ngettext(Msgid1, Msgid2, N) \
- ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define dngettext(Domainname, Msgid1, Msgid2, N) \
- ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
- ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
-# define textdomain(Domainname) ((const char *) (Domainname))
-# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
-# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
-
-#endif
-
-/* A pseudo function call that serves as a marker for the automated
- extraction of messages, but does not call gettext(). The run-time
- translation is done at a different place in the code.
- The argument, String, should be a literal string. Concatenated strings
- and other string expressions won't work.
- The macro's expansion is not parenthesized, so that it is suitable as
- initializer for static 'char[]' or 'const char[]' variables. */
-#define gettext_noop(String) String
-
-#endif /* _LIBGETTEXT_H */
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-/*! @file main.cc
- @brief Main entry point for the application
-*/
-
-#include "config.h"
-
-extern "C" {
-#ifdef HAVE_UNISTD_H
-# include <sys/types.h>
-# include <unistd.h>
-#endif // HAVE_UNISTD_H
-
-#include "gettext.h"
-}
-
-#include "openbox.hh"
-#include "otk/util.hh"
-
-#include <clocale>
-#include <cstdio>
-
-int main(int argc, char **argv) {
- // initialize the locale
- if (!setlocale(LC_ALL, ""))
- printf("Couldn't set locale from environment.\n");
- bindtextdomain(PACKAGE, LOCALEDIR);
- bind_textdomain_codeset(PACKAGE, "UTF-8");
- textdomain(PACKAGE);
-
- ob::Openbox *openbox = new ob::Openbox(argc, argv);
- openbox->eventLoop();
-
- if (openbox->doRestart()) {
- std::string prog = openbox->restartProgram();
-
- delete openbox; // shutdown the current one!
-
- if (!prog.empty()) {
- execl("/bin/sh", "/bin/sh", "-c", prog.c_str(), NULL);
- perror(prog.c_str());
- }
-
- // fall back in case the above execlp doesn't work
- execvp(argv[0], argv);
- execvp(otk::basename(argv[0]).c_str(), argv);
- }
-
- delete openbox; // shutdown
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "openbox.hh"
-#include "client.hh"
-#include "screen.hh"
-#include "actions.hh"
-#include "bindings.hh"
-#include "python.hh"
-#include "otk/property.hh"
-#include "otk/assassin.hh"
-#include "otk/property.hh"
-#include "otk/util.hh"
-#include "otk/rendercolor.hh"
-#include "otk/renderstyle.hh"
-#include "otk/messagedialog.hh"
-
-extern "C" {
-#include <X11/cursorfont.h>
-
-#ifdef HAVE_SIGNAL_H
-# include <signal.h>
-#endif // HAVE_SIGNAL_H
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif // HAVE_FCNTL_H
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif // HAVE_SYS_WAIT_H
-
-#include "gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-
-namespace otk {
-extern void initialize();
-extern void destroy();
-}
-
-namespace ob {
-
-Openbox *openbox = (Openbox *) 0;
-
-
-void Openbox::signalHandler(int signal)
-{
- switch (signal) {
- case SIGUSR1:
- printf("Caught SIGUSR1 signal. Restarting.\n");
- openbox->restart();
- break;
-
- case SIGCHLD:
- wait(NULL);
- break;
-
- case SIGHUP:
- case SIGINT:
- case SIGTERM:
- case SIGPIPE:
- printf("Caught signal %d. Exiting.\n", signal);
- openbox->shutdown();
- break;
-
- case SIGFPE:
- case SIGSEGV:
- printf("Caught signal %d. Aborting and dumping core.\n", signal);
- abort();
- }
-}
-
-
-Openbox::Openbox(int argc, char **argv)
- : otk::EventDispatcher(),
- otk::EventHandler()
-{
- struct sigaction action;
-
- _state = State_Starting; // initializing everything
-
- openbox = this;
-
- _argv = argv;
- _shutdown = false;
- _restart = false;
- _rcfilepath = otk::expandTilde("~/.openbox/rc3");
- _scriptfilepath = otk::expandTilde("~/.openbox/user.py");
- _focused_client = 0;
- _sync = false;
- _single = false;
- _remote = false;
-
- parseCommandLine(argc, argv);
-
- otk::initialize();
-
- XSynchronize(**otk::display, _sync);
-
- // set up the signal handler
- action.sa_handler = Openbox::signalHandler;
- action.sa_mask = sigset_t();
- action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
- sigaction(SIGUSR1, &action, (struct sigaction *) 0);
- sigaction(SIGPIPE, &action, (struct sigaction *) 0);
- sigaction(SIGSEGV, &action, (struct sigaction *) 0);
- sigaction(SIGFPE, &action, (struct sigaction *) 0);
- sigaction(SIGTERM, &action, (struct sigaction *) 0);
- sigaction(SIGINT, &action, (struct sigaction *) 0);
- sigaction(SIGHUP, &action, (struct sigaction *) 0);
- sigaction(SIGCHLD, &action, (struct sigaction *) 0);
-
- // anything that died while we were restarting won't give us a SIGCHLD
- while (waitpid(-1, NULL, WNOHANG) > 0);
-
- _actions = new Actions();
- _bindings = new Bindings();
-
- setMasterHandler(_actions); // set as the master event handler
-
- // create the mouse cursors we'll use
- _cursors.session = XCreateFontCursor(**otk::display, XC_left_ptr);
- _cursors.move = XCreateFontCursor(**otk::display, XC_fleur);
- _cursors.ll_angle = XCreateFontCursor(**otk::display, XC_ll_angle);
- _cursors.lr_angle = XCreateFontCursor(**otk::display, XC_lr_angle);
- _cursors.ul_angle = XCreateFontCursor(**otk::display, XC_ul_angle);
- _cursors.ur_angle = XCreateFontCursor(**otk::display, XC_ur_angle);
-
- // initialize all the screens
- _focused_screen = 0;
- _managed_count = 0;
-
- for (int i = 0, max = ScreenCount(**otk::display); i < max; ++i) {
- Screen *screen;
- // in single mode skip the screens we don't want to manage
- if (_single && i != DefaultScreen(**otk::display)) {
- _screens.push_back(0);
- continue;
- }
- // try manage the screen
- screen = new Screen(i);
- if (screen->managed()) {
- _screens.push_back(screen);
- if (!_focused_screen) // set this to the first screen managed
- _focused_screen = screen;
- _managed_count++;
- } else {
- delete screen;
- _screens.push_back(0);
- }
- }
-
- if (!_managed_count) {
- printf(_("No screens were found without a window manager. Exiting.\n"));
- ::exit(1);
- }
-
- assert(_focused_screen);
-
- // initialize scripting
- python_init(argv[0]);
-
- // load the theme XXX TEMP SHIT
- otk::RenderStyle::setStyle(0, "");
-
- int ret = python_exec(_scriptfilepath.c_str());
- if (ret == 2) {
- std::string msg;
- msg += _("An error occured while executing the python scripts.");
- msg += "\n\n";
- msg += _("See the exact error message in Openbox's output for details.");
- otk::MessageDialog dia(this, _("Python Error"), msg);
- otk::DialogButton ok(_("Okay"), true);
- otk::DialogButton retry(_("Restart"));
- dia.addButton(ok);
- dia.addButton(retry);
- dia.show();
- dia.focus();
- const otk::DialogButton &res = dia.run();
- if (res == retry) {
- _restart = _shutdown = true;
- return;
- }
- }
-
- if (ret)
- python_exec(SCRIPTDIR"/defaults.py"); // system default bahaviors
-
- ScreenList::iterator it, end = _screens.end();
- for (it = _screens.begin(); it != end; ++it)
- if (*it) (*it)->manageExisting();
-
- // grab any keys set up before the screens existed
- //_bindings->grabKeys(true);
-
- // set up input focus
- setFocusedClient(0);
-
- _state = State_Normal; // done starting
-}
-
-
-Openbox::~Openbox()
-{
- _state = State_Exiting; // time to kill everything
-
- std::for_each(_screens.begin(), _screens.end(), otk::PointerAssassin());
-
- delete _bindings;
- delete _actions;
-
- python_destroy();
-
- XSetInputFocus(**otk::display, PointerRoot, RevertToNone,
- CurrentTime);
- XSync(**otk::display, false);
-
- otk::destroy();
-}
-
-
-void Openbox::parseCommandLine(int argc, char **argv)
-{
- bool err = false;
-
- for (int i = 1; i < argc; ++i) {
- std::string arg(argv[i]);
-
- if (arg == "-rc") {
- if (++i >= argc)
- err = true;
- else
- _rcfilepath = argv[i];
- } else if (arg == "-menu") {
- if (++i >= argc)
- err = true;
- else
- _menufilepath = argv[i];
- } else if (arg == "-script") {
- if (++i >= argc)
- err = true;
- else
- _scriptfilepath = argv[i];
- } else if (arg == "-sync") {
- _sync = true;
- } else if (arg == "-single") {
- _single = true;
- } else if (arg == "-remote") {
- _remote = true;
- } else if (arg == "-version") {
- showVersion();
- ::exit(0);
- } else if (arg == "-help") {
- showHelp();
- ::exit(0);
- } else
- err = true;
-
- if (err) {
- showHelp();
- exit(1);
- }
- }
-}
-
-
-void Openbox::showVersion()
-{
- printf(_("Openbox - version %s\n"), VERSION);
- printf(" (c) 2002 - 2002 Ben Jansens\n\n");
-}
-
-
-void Openbox::showHelp()
-{
- showVersion(); // show the version string and copyright
-
- // print program usage and command line options
- printf(_("Usage: %s [OPTIONS...]\n\
- Options:\n\
- -remote optimize for a remote (low bandwidth) connection to the\n\
- display/Xserver.\n\
- -single run on a single screen (default is to run every one).\n\
- -rc <string> use alternate resource file.\n\
- -menu <string> use alternate menu file.\n\
- -script <string> use alternate startup script file.\n\
- -sync run in synchronous mode (for debugging X errors).\n\
- -version display version and exit.\n\
- -help display this help text and exit.\n\n"), _argv[0]);
-
- printf(_("Compile time options:\n\
- Debugging: %s\n\
- Shape: %s\n\
- Xinerama: %s\n\
- Xkb: %s\n"),
-#ifdef DEBUG
- _("yes"),
-#else // !DEBUG
- _("no"),
-#endif // DEBUG
-
-#ifdef SHAPE
- _("yes"),
-#else // !SHAPE
- _("no"),
-#endif // SHAPE
-
-#ifdef XINERAMA
- _("yes"),
-#else // !XINERAMA
- _("no"),
-#endif // XINERAMA
-
-#ifdef XKB
- _("yes")
-#else // !XKB
- _("no")
-#endif // XKB
- );
-}
-
-
-void Openbox::eventLoop()
-{
- while (true) {
- dispatchEvents(false); // from otk::EventDispatcher
-// XFlush(**otk::display); // flush here before we go wait for timers
- // .. the XPending() should have done this last
- // already, it does a flush when it returns 0
- // don't wait if we're to shutdown
- if (_shutdown) break;
- otk::Timer::dispatchTimers(!_sync); // wait if not in sync mode
- }
-}
-
-
-void Openbox::addClient(Window window, Client *client)
-{
- _clients[window] = client;
-}
-
-
-void Openbox::removeClient(Window window)
-{
- _clients.erase(window);
-}
-
-
-Client *Openbox::findClient(Window window)
-{
- /*
- NOTE: we dont use _clients[] to find the value because that will insert
- a new null into the hash, which really sucks when we want to clean up the
- hash at shutdown!
- */
- ClientMap::iterator it = _clients.find(window);
- if (it != _clients.end())
- return it->second;
- else
- return (Client*) 0;
-}
-
-
-void Openbox::setFocusedClient(Client *c)
-{
- // sometimes this is called with the already-focused window, this is
- // important for the python scripts to work (eg, c = 0 twice). don't just
- // return if _focused_client == c
-
- assert(_focused_screen);
-
- // uninstall the old colormap
- if (_focused_client)
- _focused_client->installColormap(false);
- else
- _focused_screen->installColormap(false);
-
- _focused_client = c;
- if (c) {
- _focused_screen = _screens[c->screen()];
-
- // install the client's colormap
- c->installColormap(true);
- } else {
- XSetInputFocus(**otk::display, _focused_screen->focuswindow(),
- RevertToNone, CurrentTime);
-
- // install the root window colormap
- _focused_screen->installColormap(true);
- }
- // set the NET_ACTIVE_WINDOW hint for all screens
- ScreenList::iterator it, end = _screens.end();
- for (it = _screens.begin(); it != end; ++it) {
- int num = (*it)->number();
- Window root = otk::display->screenInfo(num)->rootWindow();
- otk::Property::set(root, otk::Property::atoms.net_active_window,
- otk::Property::atoms.window,
- (c && _focused_screen == *it) ? c->window() : None);
- }
-
- // call the python Focus callbacks
- EventData data(_focused_screen->number(), c, EventAction::Focus, 0);
- _bindings->fireEvent(&data);
-}
-
-}
-
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __openbox_hh
-#define __openbox_hh
-
-/*! @file openbox.hh
- @brief The main class for the Openbox window manager
-*/
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "otk/display.hh"
-#include "otk/screeninfo.hh"
-#include "otk/eventdispatcher.hh"
-#include "otk/eventhandler.hh"
-
-namespace ob {
-
-class Screen;
-class Client;
-class Actions;
-class Bindings;
-
-//! Mouse cursors used throughout Openbox
-struct Cursors {
- Cursor session; //!< The default mouse cursor
- Cursor move; //!< For moving a window
- Cursor ll_angle; //!< For resizing the bottom left corner of a window
- Cursor lr_angle; //!< For resizing the bottom right corner of a window
- Cursor ul_angle; //!< For resizing the top left corner of a window
- Cursor ur_angle; //!< For resizing the right corner of a window
-};
-
-class Openbox;
-
-//! The single instance of the Openbox class for the application
-/*!
- Since this variable is globally available in the application, the Openbox
- class does not need to be passed around to any of the other classes.
-*/
-extern Openbox *openbox;
-
-//! The main class for the Openbox window manager
-/*!
- Only a single instance of the Openbox class may be used in the application. A
- pointer to this instance is held in the Openbox::instance static member
- variable.
- Instantiation of this class begins the window manager. After instantiation,
- the Openbox::eventLoop function should be called. The eventLoop method does
- not exit until the window manager is ready to be destroyed. Destruction of
- the Openbox class instance will shutdown the window manager.
-*/
-class Openbox : public otk::EventDispatcher, public otk::EventHandler
-{
-public:
- //! The posible running states of the window manager
- enum RunState {
- State_Starting, //!< The window manager is starting up (being created)
- State_Normal, //!< The window manager is running in its normal state
- State_Exiting //!< The window manager is exiting (being destroyed)
- };
-
- //! A map for looking up a specific client class from the window id
- typedef std::map<Window, Client *> ClientMap;
-
- //! A list of Screen classes
- typedef std::vector<Screen *> ScreenList;
-
-private:
- // stuff that can be passed on the command line
- //! Path to the config file to use/in use
- /*!
- Defaults to $(HOME)/.openbox/rc3
- */
- std::string _rcfilepath;
- //! Path to the menu file to use/in use
- /*!
- Defaults to $(HOME)/.openbox/menu3
- */
- std::string _menufilepath;
- //! Path to the script file to execute on startup
- /*!
- Defaults to $(HOME)/.openbox/user.py
- */
- std::string _scriptfilepath;
- //! The value of argv, i.e. how this application was executed
- char **_argv;
- //! Run the application in synchronous mode? (for debugging)
- bool _sync;
- //! Should Openbox run on a single screen or on all available screens?
- bool _single;
- //! Optimize for a remote/low-bandwidth connection to the display?
- bool _remote;
-
- //! A list of all managed clients
- ClientMap _clients;
-
- //! A list of all the managed screens
- ScreenList _screens;
-
- //! The number of managed screens
- int _managed_count;
-
- //! The action interface through which all user-available actions occur
- Actions *_actions;
-
- //! The interface through which keys/buttons are grabbed and handled
- Bindings *_bindings;
-
- //! The running state of the window manager
- RunState _state;
-
- //! Mouse cursors used throughout Openbox
- Cursors _cursors;
-
- //! When set to true, the Openbox::eventLoop function will stop and return
- bool _shutdown;
-
- //! When set to true, and Openbox is about to exit, it will spawn a new
- //! process
- bool _restart;
-
- //! If this contains anything, a restart will try to execute the program in
- //! this variable, and will fallback to reexec'ing itself if that fails
- std::string _restart_prog;
-
- //! The client with input focus
- /*!
- Updated by the clients themselves.
- */
- Client *_focused_client;
-
- //! The screen with input focus
- /*!
- Updated by the clients when they update the Openbox::focused_client
- property.
- */
- Screen *_focused_screen;
-
- //! Parses the command line used when executing this application
- void parseCommandLine(int argv, char **argv);
- //! Displays the version string to stdout
- void showVersion();
- //! Displays usage information and help to stdout
- void showHelp();
-
- //! Handles signal events for the application
- static void signalHandler(int signal);
-
-public:
- //! Openbox constructor.
- /*!
- \param argc Number of command line arguments, as received in main()
- \param argv The command line arguments, as received in main()
- */
- Openbox(int argc, char **argv);
- //! Openbox destructor.
- virtual ~Openbox();
-
- //! Returns the state of the window manager (starting, exiting, etc)
- inline RunState state() const { return _state; }
-
- //! Returns the Actions instance for the window manager
- inline Actions *actions() const { return _actions; }
-
- //! Returns the Bindings instance for the window manager
- inline Bindings *bindings() const { return _bindings; }
-
- //! Returns a managed screen or a null pointer
- /*!
- ALWAYS check the return value for a non-null, as any unmanaged screens
- will return one. This includes screen(0) if the first managed screen is 1.
- */
- inline Screen *screen(int num) {
- assert(num >= 0); assert(num < (signed)ScreenCount(**otk::display));
- if (num < 0 || num >= (signed)_screens.size()) return 0;
- return _screens[num];
- }
-
- inline int managedScreenCount() const { return _managed_count; }
-
- inline Screen *managedScreen(int num) {
- assert(num >= 0); assert(num < _managed_count);
- if (num < 0 || num >= _managed_count) return 0;
- ScreenList::iterator it, end = _screens.end();
- int i = -1;
- for (it = _screens.begin(); it != end; ++it)
- if (*it && ++i == num)
- return *it;
- }
-
- //! Returns the mouse cursors used throughout Openbox
- inline const Cursors &cursors() const { return _cursors; }
-
- //! The main function of the Openbox class
- /*!
- This function should be called after instantiating the Openbox class.
- It loops indefinately while handling all events for the application.
- The Openbox::shutdown method will cause this function to exit.
- */
- void eventLoop();
-
- //! Adds an Client to the client list for lookups
- void addClient(Window window, Client *client);
-
- //! Removes an Client from the client list for lookups
- void removeClient(Window window);
-
- //! Finds an Client based on its window id
- Client *findClient(Window window);
-
- //! The client with input focus
- inline Client *focusedClient() { return _focused_client; }
-
- //! Change the client which has focus.
- /*!
- This is called by the clients themselves when their focus state changes.
- */
- void setFocusedClient(Client *c);
-
- //! The screen with input focus
- inline Screen *focusedScreen() { return _focused_screen; }
-
- //! Requests that the window manager exit
- /*!
- Causes the Openbox::eventLoop function to stop looping, so that the window
- manager can be destroyed.
- */
- inline void shutdown() { _shutdown = true; }
-
- inline void restart(const std::string &bin = "") {
- _shutdown = true; _restart = true; _restart_prog = bin;
- }
-
- //! True if Openbox should be restarted instead of exiting
- inline bool doRestart() const { return _restart; }
-
- //! The command line requested to be executed in place of restarting
- //! Openbox the way it was run previously.
- inline const std::string &restartProgram() const { return _restart_prog; }
-};
-
-}
-
-#endif // __openbox_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "python.hh"
-#include "openbox.hh"
-#include "actions.hh"
-#include "python.hh"
-#include "bindings.hh"
-#include "otk/display.hh"
-#include "otk/util.hh"
-
-extern "C" {
-#include <Python.h>
-
-#include "gettext.h"
-#define _(str) gettext(str)
-}
-
-namespace ob {
-
-static PyObject *get = NULL;
-
-void python_init(char *argv0)
-{
- // start the python engine
- Py_SetProgramName(argv0);
- Py_Initialize();
- // prepend the openbox directories for python scripts to the sys path
- PyRun_SimpleString("import sys");
- PyRun_SimpleString("sys.path.insert(0, '" SCRIPTDIR "')");
- PyRun_SimpleString(const_cast<char*>(("sys.path.insert(0, '" +
- otk::expandTilde("~/.openbox/python") +
- "')").c_str()));
-
- return;
- PyObject *obmodule = PyImport_ImportModule("config");
- if (obmodule == NULL) {
- PyErr_Print();
- return;
- }
- PyObject *configdict = PyModule_GetDict(obmodule);
- Py_DECREF(obmodule);
-
- get = PyDict_GetItemString(configdict, "get");
- if (get == NULL) {
- PyErr_Print();
- return;
- }
-}
-
-void python_destroy()
-{
- Py_Finalize();
-}
-
-int python_exec(const std::string &path)
-{
- FILE *rcpyfd = fopen(path.c_str(), "r");
- if (!rcpyfd) {
- fprintf(stderr, _("Unabled to open python file %s\n"), path.c_str());
- return 1;
- }
-
- //PyRun_SimpleFile(rcpyfd, const_cast<char*>(path.c_str()));
-
- PyObject *module = PyImport_AddModule("__main__");
- assert(module);
- PyObject *dict = PyModule_GetDict(module);
- assert(dict);
- PyObject *result = PyRun_File(rcpyfd, const_cast<char*>(path.c_str()),
- Py_file_input, dict, dict);
- int ret = result == NULL ? 2 : 0;
- if (result == NULL)
- PyErr_Print();
-
- Py_XDECREF(result);
-
- Py_DECREF(dict);
-
- fclose(rcpyfd);
- return ret;
-}
-
-bool python_get_long(const char *name, long *value)
-{
- return false;
- if (get == NULL) return false;
- bool ret = false;
-
- PyObject *val = PyObject_CallFunction(get, "ss", "openbox", name);
- if (val == NULL)
- PyErr_Print();
- else if (PyInt_Check(val)) {
- *value = PyInt_AsLong(val);
- ret = true;
- } else if (PyLong_Check(val)) {
- *value = PyLong_AsLong(val);
- ret = true;
- }
- Py_XDECREF(val);
- return ret;
-}
-
-bool python_get_string(const char *name, otk::ustring *value)
-{
- return false;
- if (get == NULL) return false;
- bool ret = false;
-
- PyObject *val = PyObject_CallFunction(get, "ss", "openbox", name);
- if (val == NULL)
- PyErr_Print();
- else if (PyString_Check(val)) {
- *value = std::string(PyString_AsString(val), PyString_Size(val));
- ret = true;
- }
- Py_XDECREF(val);
- return ret;
-}
-
-bool python_get_stringlist(const char *name, std::vector<otk::ustring> *value)
-{
- return false;
- if (get == NULL) return false;
- bool ret = false;
-
- PyObject *val = PyObject_CallFunction(get, "ss", "openbox", name);
- if (val == NULL)
- PyErr_Print();
- else if (PyList_Check(val)) {
- for (int i = 0, end = PyList_Size(val); i < end; ++i) {
- PyObject *str = PyList_GET_ITEM(val, i);
- if (PyString_Check(str))
- value->push_back(std::string(PyString_AsString(str),
- PyString_Size(str)));
- }
- }
- Py_XDECREF(val);
- return ret;
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __python_hh
-#define __python_hh
-
-/*! @file python.hh
- @brief wee
-*/
-
-#include "otk/point.hh"
-#include "otk/rect.hh"
-#include "otk/property.hh"
-#include "otk/display.hh"
-#include "otk/ustring.hh"
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include <string>
-#include <vector>
-
-
-namespace ob {
-
-class Client;
-
-struct MouseContext {
- enum MC {
- Frame,
- Titlebar,
- Handle,
- Window,
- IconButton,
- MaximizeButton,
- CloseButton,
- IconifyButton,
- AllDesktopsButton,
- Grip,
- Root,
- MenuItem
-#ifndef DOXYGEN_IGNORE
- , NUM_MOUSE_CONTEXT
-#endif
- };
-};
-
-struct MouseAction {
- enum MA {
- Press,
- Release,
- Click,
- DoubleClick,
- Motion
-#ifndef DOXYGEN_IGNORE
- , NUM_MOUSE_ACTION
-#endif
- };
-};
-
-struct KeyContext {
- enum KC {
- Menu,
- All
-#ifndef DOXYGEN_IGNORE
- , NUM_KEY_CONTEXT
-#endif
- };
-};
-
-struct KeyAction {
- enum KA {
- Press,
- Release
-#ifndef DOXYGEN_IGNORE
- , NUM_KEY_ACTION
-#endif
- };
-};
-
-struct EventAction {
- enum EA {
- EnterWindow, //!< Occurs when the mouse enters a window
- LeaveWindow, //!< Occurs when the mouse leaves a window
- //! Occurs while a window is being managed. The handler should call
- //! Client::move on the window
- PlaceWindow,
- //! Occurs while a window is being managed, just before the window is
- //! displayed
- /*!
- Note that the window's state may not be completely stabilized by this
- point. The NewWindow event should be used when possible.
- */
- DisplayingWindow,
- //! Occurs when a window is finished being managed
- NewWindow,
- //! Occurs when a window has been closed and is going to be unmanaged
- CloseWindow,
- //! Occurs when the window manager manages a screen
- /*!
- This event occurs on each managed screen during startup.
- */
- Startup,
- //! Occurs when the window manager unmanages a screen
- /*!
- This event occurs on each managed screen during shutdown.
- */
- Shutdown,
- //! Occurs when the input focus target changes
- /*!
- The data.client will be None of no client is focused.
- */
- Focus,
- //! Occurs when the system is fired through X.
- /*!
- The data.client will hold the client associated with the bell if
- one has been specified, or None.
- */
- Bell,
- //! Occurs when a client toggles its urgent status.
- /*!
- The Client::urgent method can be used to get the status.
- */
- UrgentWindow
-#ifndef DOXYGEN_IGNORE
- , NUM_EVENT_ACTION
-#endif
- };
-};
-
-class MouseData {
-public:
- int screen;
- Client *client;
- Time time;
- unsigned int state;
- unsigned int button;
- MouseContext::MC context;
- MouseAction::MA action;
- int xroot;
- int yroot;
- int pressx;
- int pressy;
- int press_clientx;
- int press_clienty;
- int press_clientwidth;
- int press_clientheight;
-
- MouseData(int screen, Client *client, Time time, unsigned int state,
- unsigned int button, MouseContext::MC context,
- MouseAction::MA action, int xroot, int yroot,
- const otk::Point &initpos, const otk::Rect &initarea) {
- this->screen = screen;
- this->client = client;
- this->time = time;
- this->state = state;
- this->button = button;
- this->context= context;
- this->action = action;
- this->xroot = xroot;
- this->yroot = yroot;
- this->pressx = initpos.x();
- this->pressy = initpos.y();
- this->press_clientx = initarea.x();
- this->press_clienty = initarea.y();
- this->press_clientwidth = initarea.width();
- this->press_clientheight = initarea.height();
- }
- MouseData(int screen, Client *client, Time time, unsigned int state,
- unsigned int button, MouseContext::MC context,
- MouseAction::MA action) {
- this->screen = screen;
- this->client = client;
- this->time = time;
- this->state = state;
- this->button = button;
- this->context= context;
- this->action = action;
- this->xroot = xroot;
- this->yroot = yroot;
- this->pressx = 0;
- this->pressy = 0;
- this->press_clientx = 0;
- this->press_clienty = 0;
- this->press_clientwidth = 0;
- this->press_clientheight = 0;
- }
-};
-
-class EventData {
-public:
- int screen;
- Client *client;
- unsigned int state;
- EventAction::EA action;
-
- EventData(int screen, Client *client, EventAction::EA action,
- unsigned int state) {
- this->screen = screen;
- this->client = client;
- this->action = action;
- this->state = state;
- }
-};
-
-class KeyData {
-public:
- int screen;
- Client *client;
- Time time;
- unsigned int state;
- char *key;
- KeyAction::KA action;
-
- KeyData(int screen, Client *client, Time time, unsigned int state,
- unsigned int key, KeyAction::KA action) {
- this->screen = screen;
- this->client = client;
- this->time = time;
- this->state = state;
- this->key = XKeysymToString(XKeycodeToKeysym(**otk::display,
- key, 0));
- this->action = action;
- }
-};
-
-// The void*'s will be used to hold the native language's function pointer
-typedef void (*MouseCallback)(MouseData*, void*);
-typedef void (*KeyCallback)(KeyData*, void*);
-typedef void (*EventCallback)(EventData*, void*);
-
-void python_init(char *argv0);
-void python_destroy();
-//! Returns 0 for success, 1 for failing to open the file, 2 for an exception
-int python_exec(const std::string &path);
-
-bool python_get_long(const char *name, long *value);
-bool python_get_string(const char *name, otk::ustring *value);
-bool python_get_stringlist(const char *name, std::vector<otk::ustring> *value);
-
-}
-
-
-#endif // __python_hh
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-
-#include "config.h"
-
-#include "screen.hh"
-#include "client.hh"
-#include "openbox.hh"
-#include "frame.hh"
-#include "bindings.hh"
-#include "python.hh"
-#include "otk/display.hh"
-#include "otk/property.hh"
-#include "otk/util.hh"
-
-extern "C" {
-#ifdef HAVE_UNISTD_H
-# include <sys/types.h>
-# include <unistd.h>
-#endif // HAVE_UNISTD_H
-
-#include "gettext.h"
-#define _(str) gettext(str)
-}
-
-#include <vector>
-#include <algorithm>
-#include <cstdio>
-#include <cstring>
-
-static bool running;
-static int anotherWMRunning(Display *display, XErrorEvent *) {
- printf(_("Another window manager already running on display %s.\n"),
- DisplayString(display));
- running = true;
- return -1;
-}
-
-
-namespace ob {
-
-
-Screen::Screen(int screen)
- : _number(screen)
-{
- assert(screen >= 0); assert(screen < ScreenCount(**otk::display));
- _info = otk::display->screenInfo(screen);
-
- ::running = false;
- XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
- XSelectInput(**otk::display, _info->rootWindow(),
- Screen::event_mask);
- XSync(**otk::display, false);
- XSetErrorHandler(old);
-
- _managed = !::running;
- if (! _managed) return; // was unable to manage the screen
-
-#ifdef DEBUG
- printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
- _number, XVisualIDFromVisual(_info->visual()), _info->depth());
-#endif
-
- otk::Property::set(_info->rootWindow(), otk::Property::atoms.openbox_pid,
- otk::Property::atoms.cardinal, (unsigned long) getpid());
-
- // set the mouse cursor for the root window (the default cursor)
- XDefineCursor(**otk::display, _info->rootWindow(),
- openbox->cursors().session);
-
- // set up notification of netwm support
- changeSupportedAtoms();
-
- // Set the netwm properties for geometry
- unsigned long geometry[] = { _info->size().width(),
- _info->size().height() };
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_desktop_geometry,
- otk::Property::atoms.cardinal, geometry, 2);
-
- _desktop = 0;
-
- changeNumDesktops(4); // set the hint
- changeDesktop(0); // set the hint
-
- // don't start in showing-desktop mode
- _showing_desktop = false;
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_showing_desktop,
- otk::Property::atoms.cardinal, 0);
-
- // create the window which gets focus when no clients get it
- XSetWindowAttributes attr;
- attr.override_redirect = true;
- _focuswindow = XCreateWindow(**otk::display, _info->rootWindow(),
- -100, -100, 1, 1, 0, 0, InputOnly,
- _info->visual(), CWOverrideRedirect, &attr);
- XMapRaised(**otk::display, _focuswindow);
-
- // these may be further updated if any pre-existing windows are found in
- // the manageExising() function
- changeClientList(); // initialize the client lists, which will be empty
-
- updateDesktopLayout();
-
- // register this class as the event handler for the root window
- openbox->registerHandler(_info->rootWindow(), this);
-
- // call the python Startup callbacks
- EventData data(_number, 0, EventAction::Startup, 0);
- openbox->bindings()->fireEvent(&data);
-}
-
-
-Screen::~Screen()
-{
- if (! _managed) return;
-
- XSelectInput(**otk::display, _info->rootWindow(), NoEventMask);
-
- // unmanage all windows
- while (!clients.empty())
- unmanageWindow(clients.front());
-
- // call the python Shutdown callbacks
- EventData data(_number, 0, EventAction::Shutdown, 0);
- openbox->bindings()->fireEvent(&data);
-
- XDestroyWindow(**otk::display, _focuswindow);
- XDestroyWindow(**otk::display, _supportwindow);
-}
-
-
-void Screen::manageExisting()
-{
- unsigned int i, j, nchild;
- Window r, p, *children;
- XQueryTree(**otk::display, _info->rootWindow(), &r, &p,
- &children, &nchild);
-
- // preen the window list of all icon windows... for better dockapp support
- for (i = 0; i < nchild; i++) {
- if (children[i] == None) continue;
-
- XWMHints *wmhints = XGetWMHints(**otk::display,
- children[i]);
-
- if (wmhints) {
- if ((wmhints->flags & IconWindowHint) &&
- (wmhints->icon_window != children[i])) {
- for (j = 0; j < nchild; j++) {
- if (children[j] == wmhints->icon_window) {
- children[j] = None;
- break;
- }
- }
- }
-
- XFree(wmhints);
- }
- }
-
- // manage shown windows
- for (i = 0; i < nchild; ++i) {
- if (children[i] == None)
- continue;
-
- XWindowAttributes attrib;
- if (XGetWindowAttributes(**otk::display, children[i], &attrib)) {
- if (attrib.override_redirect) continue;
-
- if (attrib.map_state != IsUnmapped) {
- manageWindow(children[i]);
- }
- }
- }
-
- XFree(children);
-}
-
-void Screen::updateDesktopLayout()
-{
- //const unsigned long _NET_WM_ORIENTATION_HORZ = 0;
- const unsigned long _NET_WM_ORIENTATION_VERT = 1;
- //const unsigned long _NET_WM_TOPLEFT = 0;
- const unsigned long _NET_WM_TOPRIGHT = 1;
- const unsigned long _NET_WM_BOTTOMRIGHT = 2;
- const unsigned long _NET_WM_BOTTOMLEFT = 3;
-
- // defaults
- _layout.orientation = DesktopLayout::Horizontal;
- _layout.start_corner = DesktopLayout::TopLeft;
- _layout.rows = 1;
- _layout.columns = _num_desktops;
-
- unsigned long *data, num = 4;
- if (otk::Property::get(_info->rootWindow(),
- otk::Property::atoms.net_desktop_layout,
- otk::Property::atoms.cardinal,
- &num, &data)) {
- if (num == 4) {
- if (data[0] == _NET_WM_ORIENTATION_VERT)
- _layout.orientation = DesktopLayout::Vertical;
- if (data[3] == _NET_WM_TOPRIGHT)
- _layout.start_corner = DesktopLayout::TopRight;
- else if (data[3] == _NET_WM_BOTTOMRIGHT)
- _layout.start_corner = DesktopLayout::BottomRight;
- else if (data[3] == _NET_WM_BOTTOMLEFT)
- _layout.start_corner = DesktopLayout::BottomLeft;
-
- // fill in a zero rows/columns
- if (!(data[1] == 0 && data[2] == 0)) { // both 0's is bad data..
- if (data[1] == 0) {
- data[1] = (_num_desktops + _num_desktops % data[2]) / data[2];
- } else if (data[2] == 0) {
- data[2] = (_num_desktops + _num_desktops % data[1]) / data[1];
- }
- _layout.columns = data[1];
- _layout.rows = data[2];
- }
-
- // bounds checking
- if (_layout.orientation == DesktopLayout::Horizontal) {
- if (_layout.rows > _num_desktops) _layout.rows = _num_desktops;
- if (_layout.columns > (_num_desktops + _num_desktops % _layout.rows) /
- _layout.rows)
- _layout.columns = (_num_desktops + _num_desktops % _layout.rows) /
- _layout.rows;
- } else {
- if (_layout.columns > _num_desktops) _layout.columns = _num_desktops;
- if (_layout.rows > (_num_desktops + _num_desktops % _layout.columns) /
- _layout.columns)
- _layout.rows = (_num_desktops + _num_desktops % _layout.columns) /
- _layout.columns;
- }
- }
- delete [] data;
- }
-}
-
-void Screen::updateStruts()
-{
- struct ApplyStrut {
- void operator()(otk::Strut &self, const otk::Strut &other) {
- self.left = std::max(self.left, other.left);
- self.right = std::max(self.right, other.right);
- self.top = std::max(self.top, other.top);
- self.bottom = std::max(self.bottom, other.bottom);
- }
- } apply;
-
- StrutList::iterator sit, send = _struts.end();
- // reset them all
- for (sit = _struts.begin(); sit != send; ++sit)
- sit->left = sit->right = sit->top = sit->bottom = 0;
-
- std::list<Client*>::const_iterator it, end = clients.end();
- for (it = clients.begin(); it != end; ++it) {
- if ((*it)->iconic()) continue; // these dont count in the strut
-
- unsigned int desk = (*it)->desktop();
- const otk::Strut &s = (*it)->strut();
-
- if (desk == 0xffffffff)
- for (unsigned int i = 0, e = _struts.size(); i < e; ++i)
- apply(_struts[i], s);
- else if (desk < _struts.size())
- apply(_struts[desk], s);
- else
- assert(false); // invalid desktop otherwise..
- // apply to the 'all desktops' strut
- apply(_struts.back(), s);
- }
- changeWorkArea();
-}
-
-
-void Screen::changeWorkArea()
-{
- unsigned long *dims = new unsigned long[4 * _num_desktops];
- for (unsigned int i = 0; i < _num_desktops + 1; ++i) {
- otk::Rect old_area = _area[i];
-/*
-#ifdef XINERAMA
- // reset to the full areas
- if (isXineramaActive())
- xineramaUsableArea = getXineramaAreas();
-#endif // XINERAMA
-*/
-
- _area[i] = otk::Rect(_struts[i].left, _struts[i].top,
- _info->size().width() - (_struts[i].left +
- _struts[i].right),
- _info->size().height() - (_struts[i].top +
- _struts[i].bottom));
-
-/*
-#ifdef XINERAMA
- if (isXineramaActive()) {
- // keep each of the ximerama-defined areas inside the strut
- RectList::iterator xit, xend = xineramaUsableArea.end();
- for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
- if (xit->x() < usableArea.x()) {
- xit->setX(usableArea.x());
- xit->setWidth(xit->width() - usableArea.x());
- }
- if (xit->y() < usableArea.y()) {
- xit->setY(usableArea.y());
- xit->setHeight(xit->height() - usableArea.y());
- }
- if (xit->x() + xit->width() > usableArea.width())
- xit->setWidth(usableArea.width() - xit->x());
- if (xit->y() + xit->height() > usableArea.height())
- xit->setHeight(usableArea.height() - xit->y());
- }
- }
-#endif // XINERAMA
-*/
- if (old_area != _area[i]) {
- // the area has changed, adjust all the maximized windows
- std::list<Client*>::iterator it, end = clients.end();
- for (it = clients.begin(); it != end; ++it)
- if (i < _num_desktops) {
- if ((*it)->desktop() == i)
- (*it)->remaximize();
- } else {
- // the 'all desktops' size
- if ((*it)->desktop() == 0xffffffff)
- (*it)->remaximize();
- }
- }
-
- // don't set these for the 'all desktops' area
- if (i < _num_desktops) {
- dims[(i * 4) + 0] = _area[i].x();
- dims[(i * 4) + 1] = _area[i].y();
- dims[(i * 4) + 2] = _area[i].width();
- dims[(i * 4) + 3] = _area[i].height();
- }
- }
- otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_workarea,
- otk::Property::atoms.cardinal, dims, 4 * _num_desktops);
- delete [] dims;
-}
-
-
-void Screen::changeSupportedAtoms()
-{
- // create the netwm support window
- _supportwindow = XCreateSimpleWindow(**otk::display,
- _info->rootWindow(),
- 0, 0, 1, 1, 0, 0, 0);
-
- // set supporting window
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_supporting_wm_check,
- otk::Property::atoms.window, _supportwindow);
-
- //set properties on the supporting window
- otk::Property::set(_supportwindow, otk::Property::atoms.net_wm_name,
- otk::Property::utf8, "Openbox");
- otk::Property::set(_supportwindow,
- otk::Property::atoms.net_supporting_wm_check,
- otk::Property::atoms.window, _supportwindow);
-
-
- Atom supported[] = {
- otk::Property::atoms.net_current_desktop,
- otk::Property::atoms.net_number_of_desktops,
- otk::Property::atoms.net_desktop_geometry,
- otk::Property::atoms.net_desktop_viewport,
- otk::Property::atoms.net_active_window,
- otk::Property::atoms.net_workarea,
- otk::Property::atoms.net_client_list,
- otk::Property::atoms.net_client_list_stacking,
- otk::Property::atoms.net_desktop_names,
- otk::Property::atoms.net_close_window,
- otk::Property::atoms.net_desktop_layout,
- otk::Property::atoms.net_showing_desktop,
- otk::Property::atoms.net_wm_name,
- otk::Property::atoms.net_wm_visible_name,
- otk::Property::atoms.net_wm_icon_name,
- otk::Property::atoms.net_wm_visible_icon_name,
- otk::Property::atoms.net_wm_desktop,
- otk::Property::atoms.net_wm_strut,
- otk::Property::atoms.net_wm_window_type,
- otk::Property::atoms.net_wm_window_type_desktop,
- otk::Property::atoms.net_wm_window_type_dock,
- otk::Property::atoms.net_wm_window_type_toolbar,
- otk::Property::atoms.net_wm_window_type_menu,
- otk::Property::atoms.net_wm_window_type_utility,
- otk::Property::atoms.net_wm_window_type_splash,
- otk::Property::atoms.net_wm_window_type_dialog,
- otk::Property::atoms.net_wm_window_type_normal,
-/*
- otk::Property::atoms.net_wm_moveresize,
- otk::Property::atoms.net_wm_moveresize_size_topleft,
- otk::Property::atoms.net_wm_moveresize_size_topright,
- otk::Property::atoms.net_wm_moveresize_size_bottomleft,
- otk::Property::atoms.net_wm_moveresize_size_bottomright,
- otk::Property::atoms.net_wm_moveresize_move,
-*/
- otk::Property::atoms.net_wm_allowed_actions,
- otk::Property::atoms.net_wm_action_move,
- otk::Property::atoms.net_wm_action_resize,
- otk::Property::atoms.net_wm_action_minimize,
- otk::Property::atoms.net_wm_action_shade,
-/* otk::Property::atoms.net_wm_action_stick,*/
- otk::Property::atoms.net_wm_action_maximize_horz,
- otk::Property::atoms.net_wm_action_maximize_vert,
- otk::Property::atoms.net_wm_action_fullscreen,
- otk::Property::atoms.net_wm_action_change_desktop,
- otk::Property::atoms.net_wm_action_close,
-
- otk::Property::atoms.net_wm_state,
- otk::Property::atoms.net_wm_state_modal,
- otk::Property::atoms.net_wm_state_maximized_vert,
- otk::Property::atoms.net_wm_state_maximized_horz,
- otk::Property::atoms.net_wm_state_shaded,
- otk::Property::atoms.net_wm_state_skip_taskbar,
- otk::Property::atoms.net_wm_state_skip_pager,
- otk::Property::atoms.net_wm_state_hidden,
- otk::Property::atoms.net_wm_state_fullscreen,
- otk::Property::atoms.net_wm_state_above,
- otk::Property::atoms.net_wm_state_below,
- };
- const int num_supported = sizeof(supported)/sizeof(Atom);
-
- otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_supported,
- otk::Property::atoms.atom, supported, num_supported);
-}
-
-
-void Screen::changeClientList()
-{
- Window *windows;
- unsigned int size = clients.size();
-
- // create an array of the window ids
- if (size > 0) {
- Window *win_it;
-
- windows = new Window[size];
- win_it = windows;
- std::list<Client*>::const_iterator it = clients.begin();
- const std::list<Client*>::const_iterator end = clients.end();
- for (; it != end; ++it, ++win_it)
- *win_it = (*it)->window();
- } else
- windows = (Window*) 0;
-
- otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_client_list,
- otk::Property::atoms.window, windows, size);
-
- if (size)
- delete [] windows;
-
- changeStackingList();
-}
-
-
-void Screen::changeStackingList()
-{
- Window *windows;
- unsigned int size = _stacking.size();
-
- assert(size == clients.size()); // just making sure.. :)
-
-
- // create an array of the window ids (from bottom to top, reverse order!)
- if (size > 0) {
- Window *win_it;
-
- windows = new Window[size];
- win_it = windows;
- std::list<Client*>::const_reverse_iterator it = _stacking.rbegin();
- const std::list<Client*>::const_reverse_iterator end = _stacking.rend();
- for (; it != end; ++it, ++win_it)
- *win_it = (*it)->window();
- } else
- windows = (Window*) 0;
-
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_client_list_stacking,
- otk::Property::atoms.window, windows, size);
-
- if (size)
- delete [] windows;
-}
-
-
-void Screen::manageWindow(Window window)
-{
- Client *client = 0;
- XWMHints *wmhint;
- XSetWindowAttributes attrib_set;
- XEvent e;
- XWindowAttributes attrib;
-
- otk::display->grab();
-
- // check if it has already been unmapped by the time we started mapping
- // the grab does a sync so we don't have to here
- if (XCheckTypedWindowEvent(**otk::display, window, DestroyNotify, &e) ||
- XCheckTypedWindowEvent(**otk::display, window, UnmapNotify, &e)) {
- XPutBackEvent(**otk::display, &e);
-
- otk::display->ungrab();
- return; // don't manage it
- }
-
- if (!XGetWindowAttributes(**otk::display, window, &attrib) ||
- attrib.override_redirect) {
- otk::display->ungrab();
- return; // don't manage it
- }
-
- // is the window a docking app
- if ((wmhint = XGetWMHints(**otk::display, window))) {
- if ((wmhint->flags & StateHint) &&
- wmhint->initial_state == WithdrawnState) {
- //slit->addClient(w); // XXX: make dock apps work!
-
- otk::display->ungrab();
- XFree(wmhint);
- return;
- }
- XFree(wmhint);
- }
-
- // choose the events we want to receive on the CLIENT window
- attrib_set.event_mask = Client::event_mask;
- attrib_set.do_not_propagate_mask = Client::no_propagate_mask;
- XChangeWindowAttributes(**otk::display, window,
- CWEventMask|CWDontPropagate, &attrib_set);
-
- // create the Client class, which gets all of the hints on the window
- client = new Client(_number, window);
- // register for events
- openbox->registerHandler(window, client);
- // add to the wm's map
- openbox->addClient(window, client);
-
- // we dont want a border on the client
- client->toggleClientBorder(false);
-
- // specify that if we exit, the window should not be destroyed and should be
- // reparented back to root automatically
- XChangeSaveSet(**otk::display, window, SetModeInsert);
-
- // create the decoration frame for the client window
- client->frame = new Frame(client);
- // register the plate for events (map req's)
- // this involves removing itself from the handler list first, since it is
- // auto added to the list, being a widget. we won't get any events on the
- // plate except for events for the client (SubstructureRedirectMask)
- openbox->clearHandler(client->frame->plate());
- openbox->registerHandler(client->frame->plate(), client);
-
- // add to the wm's map
- Window *w = client->frame->allWindows();
- for (unsigned int i = 0; w[i]; ++i)
- openbox->addClient(w[i], client);
- delete [] w;
-
- // reparent the client to the frame
- client->frame->grabClient();
-
- if (openbox->state() != Openbox::State_Starting) {
- // position the window intelligenty .. hopefully :)
- // call the python PLACEWINDOW binding
- EventData data(_number, client, EventAction::PlaceWindow, 0);
- openbox->bindings()->fireEvent(&data);
- }
-
- EventData ddata(_number, client, EventAction::DisplayingWindow, 0);
- openbox->bindings()->fireEvent(&ddata);
-
- client->showhide();
-
- client->applyStartupState();
-
- otk::display->ungrab();
-
- // add to the screen's list
- clients.push_back(client);
- // once the client is in the list, update our strut to include the new
- // client's (it is good that this happens after window placement!)
- updateStruts();
- // this puts into the stacking order, then raises it
- _stacking.push_back(client);
- raiseWindow(client);
- // update the root properties
- changeClientList();
-
- openbox->bindings()->grabButtons(true, client);
-
- EventData ndata(_number, client, EventAction::NewWindow, 0);
- openbox->bindings()->fireEvent(&ndata);
-
-#ifdef DEBUG
- printf("Managed window 0x%lx frame 0x%lx\n",
- window, client->frame->window());
-#endif
-}
-
-
-void Screen::unmanageWindow(Client *client)
-{
- Frame *frame = client->frame;
-
- // call the python CLOSEWINDOW binding
- EventData data(_number, client, EventAction::CloseWindow, 0);
- openbox->bindings()->fireEvent(&data);
-
- openbox->bindings()->grabButtons(false, client);
-
- // remove from the wm's map
- openbox->removeClient(client->window());
- Window *w = frame->allWindows();
- for (unsigned int i = 0; w[i]; ++i)
- openbox->addClient(w[i], client);
- delete [] w;
- // unregister for handling events
- openbox->clearHandler(client->window());
-
- // remove the window from our save set
- XChangeSaveSet(**otk::display, client->window(), SetModeDelete);
-
- // we dont want events no more
- XSelectInput(**otk::display, client->window(), NoEventMask);
-
- frame->hide();
-
- // give the client its border back
- client->toggleClientBorder(true);
-
- // reparent the window out of the frame
- frame->releaseClient();
-
-#ifdef DEBUG
- Window framewin = client->frame->window();
-#endif
- delete client->frame;
- client->frame = 0;
-
- // remove from the stacking order
- _stacking.remove(client);
-
- // remove from the screen's list
- clients.remove(client);
-
- // once the client is out of the list, update our strut to remove it's
- // influence
- updateStruts();
-
- // unset modal before dropping our focus
- client->_modal = false;
-
- // unfocus the client (calls the focus callbacks)
- if (client->focused()) client->unfocus();
-
-#ifdef DEBUG
- printf("Unmanaged window 0x%lx frame 0x%lx\n", client->window(), framewin);
-#endif
-
- delete client;
-
- // update the root properties
- changeClientList();
-}
-
-void Screen::lowerWindow(Client *client)
-{
- Window wins[2]; // only ever restack 2 windows.
-
- assert(!_stacking.empty()); // this would be bad
-
- std::list<Client*>::iterator it = --_stacking.end();
- const std::list<Client*>::iterator end = _stacking.begin();
-
- if (client->modal() && client->transientFor()) {
- // don't let a modal window lower below its transient_for
- it = std::find(_stacking.begin(), _stacking.end(), client->transientFor());
- assert(it != _stacking.end());
-
- wins[0] = (it == _stacking.begin() ? _focuswindow :
- ((*(--std::list<Client*>::const_iterator(it)))->
- frame->window()));
- wins[1] = client->frame->window();
- if (wins[0] == wins[1]) return; // already right above the window
-
- _stacking.remove(client);
- _stacking.insert(it, client);
- } else {
- for (; it != end && (*it)->layer() < client->layer(); --it);
- if (*it == client) return; // already the bottom, return
-
- wins[0] = (*it)->frame->window();
- wins[1] = client->frame->window();
-
- _stacking.remove(client);
- _stacking.insert(++it, client);
- }
-
- XRestackWindows(**otk::display, wins, 2);
- changeStackingList();
-}
-
-void Screen::raiseWindow(Client *client)
-{
- Window wins[2]; // only ever restack 2 windows.
-
- assert(!_stacking.empty()); // this would be bad
-
- Client *m = client->findModalChild();
- // if we have a modal child, raise it instead, we'll go along tho later
- if (m) raiseWindow(m);
-
- // remove the client before looking so we can't run into ourselves
- _stacking.remove(client);
-
- std::list<Client*>::iterator it = _stacking.begin();
- const std::list<Client*>::iterator end = _stacking.end();
-
- // the stacking list is from highest to lowest
- for (; it != end && ((*it)->layer() > client->layer() || m == *it); ++it);
-
- /*
- if our new position is the top, we want to stack under the _focuswindow
- otherwise, we want to stack under the previous window in the stack.
- */
- wins[0] = (it == _stacking.begin() ? _focuswindow :
- ((*(--std::list<Client*>::const_iterator(it)))->frame->window()));
- wins[1] = client->frame->window();
-
- _stacking.insert(it, client);
-
- XRestackWindows(**otk::display, wins, 2);
-
- changeStackingList();
-}
-
-void Screen::changeDesktop(unsigned int desktop)
-{
- if (desktop >= _num_desktops) return;
-
- printf("Moving to desktop %u\n", desktop);
-
- unsigned int old = _desktop;
-
- _desktop = desktop;
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_current_desktop,
- otk::Property::atoms.cardinal, _desktop);
-
- if (old == _desktop) return;
-
- std::list<Client*>::iterator it, end = clients.end();
- for (it = clients.begin(); it != end; ++it)
- (*it)->showhide();
-
- // force the callbacks to fire
- if (!openbox->focusedClient())
- openbox->setFocusedClient(0);
-}
-
-void Screen::changeNumDesktops(unsigned int num)
-{
- assert(num > 0);
-
- if (!(num > 0)) return;
-
- // move windows on desktops that will no longer exist!
- std::list<Client*>::iterator it, end = clients.end();
- for (it = clients.begin(); it != end; ++it) {
- unsigned int d = (*it)->desktop();
- if (d >= num && d != 0xffffffff) {
- XEvent ce;
- ce.xclient.type = ClientMessage;
- ce.xclient.message_type = otk::Property::atoms.net_wm_desktop;
- ce.xclient.display = **otk::display;
- ce.xclient.window = (*it)->window();
- ce.xclient.format = 32;
- ce.xclient.data.l[0] = num - 1;
- XSendEvent(**otk::display, _info->rootWindow(), false,
- SubstructureNotifyMask | SubstructureRedirectMask, &ce);
- }
- }
-
- _num_desktops = num;
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_number_of_desktops,
- otk::Property::atoms.cardinal, _num_desktops);
-
- // set the viewport hint
- unsigned long *viewport = new unsigned long[_num_desktops * 2];
- memset(viewport, 0, sizeof(unsigned long) * _num_desktops * 2);
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_desktop_viewport,
- otk::Property::atoms.cardinal,
- viewport, _num_desktops * 2);
- delete [] viewport;
-
- // change our struts/area to match
- _area.resize(_num_desktops + 1);
- _struts.resize(_num_desktops + 1);
- updateStruts();
-
- // the number of rows/columns will differ
- updateDesktopLayout();
-
- // may be some unnamed desktops that we need to fill in with names
- updateDesktopNames();
-
- // change our desktop if we're on one that no longer exists!
- if (_desktop >= _num_desktops)
- changeDesktop(_num_desktops - 1);
-}
-
-
-void Screen::updateDesktopNames()
-{
- unsigned long num;
-
- if (!otk::Property::get(_info->rootWindow(),
- otk::Property::atoms.net_desktop_names,
- otk::Property::utf8, &num, &_desktop_names))
- _desktop_names.clear();
- while (_desktop_names.size() < _num_desktops)
- _desktop_names.push_back("Unnamed");
-}
-
-
-const otk::Rect& Screen::area(unsigned int desktop) const {
- assert(desktop < _num_desktops || desktop == 0xffffffff);
- if (desktop < _num_desktops)
- return _area[desktop];
- else
- return _area[_num_desktops];
-}
-
-void Screen::installColormap(bool install) const
-{
- if (install)
- XInstallColormap(**otk::display, _info->colormap());
- else
- XUninstallColormap(**otk::display, _info->colormap());
-}
-
-void Screen::showDesktop(bool show)
-{
- if (show == _showing_desktop) return; // no change
-
- // save the window focus, and restore it when leaving the show-desktop mode
- static Window saved_focus = 0;
- if (show) {
- Client *c = openbox->focusedClient();
- if (c) saved_focus = c->window();
- }
-
- _showing_desktop = show;
-
- std::list<Client*>::iterator it, end = clients.end();
- for (it = clients.begin(); it != end; ++it) {
- if ((*it)->type() == Client::Type_Desktop) {
- if (show)
- (*it)->focus();
- } else
- (*it)->showhide();
- }
-
- if (!show) {
- Client *f = openbox->focusedClient();
- if (!f || f->type() == Client::Type_Desktop) {
- Client *c = openbox->findClient(saved_focus);
- if (c) c->focus();
- }
- }
-
- otk::Property::set(_info->rootWindow(),
- otk::Property::atoms.net_showing_desktop,
- otk::Property::atoms.cardinal,
- show ? 1 : 0);
-}
-
-void Screen::propertyHandler(const XPropertyEvent &e)
-{
- otk::EventHandler::propertyHandler(e);
-
- // compress changes to a single property into a single change
- XEvent ce;
- while (XCheckTypedWindowEvent(**otk::display, _info->rootWindow(),
- e.type, &ce)) {
- // XXX: it would be nice to compress ALL changes to a property, not just
- // changes in a row without other props between.
- if (ce.xproperty.atom != e.atom) {
- XPutBackEvent(**otk::display, &ce);
- break;
- }
- }
-
- if (e.atom == otk::Property::atoms.net_desktop_names)
- updateDesktopNames();
- else if (e.atom == otk::Property::atoms.net_desktop_layout)
- updateDesktopLayout();
-}
-
-
-void Screen::clientMessageHandler(const XClientMessageEvent &e)
-{
- otk::EventHandler::clientMessageHandler(e);
-
- if (e.format != 32) return;
-
- if (e.message_type == otk::Property::atoms.net_current_desktop) {
- changeDesktop(e.data.l[0]);
- } else if (e.message_type == otk::Property::atoms.net_number_of_desktops) {
- changeNumDesktops(e.data.l[0]);
- } else if (e.message_type == otk::Property::atoms.net_showing_desktop) {
- showDesktop(e.data.l[0] != 0);
- }
-}
-
-
-void Screen::mapRequestHandler(const XMapRequestEvent &e)
-{
- otk::EventHandler::mapRequestHandler(e);
-
-#ifdef DEBUG
- printf("MapRequest for 0x%lx\n", e.window);
-#endif // DEBUG
-
- Client *c = openbox->findClient(e.window);
- if (c) {
-#ifdef DEBUG
- printf("DEBUG: MAP REQUEST CAUGHT IN SCREEN. IGNORED.\n");
-#endif
- } else {
- if (_showing_desktop)
- showDesktop(false); // leave showing-the-desktop mode
- manageWindow(e.window);
- }
-}
-
-}
+++ /dev/null
-// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __screen_hh
-#define __screen_hh
-
-/*! @file screen.hh
- @brief Screen manages a single screen
-*/
-
-extern "C" {
-#include <X11/Xlib.h>
-}
-
-#include "otk/strut.hh"
-#include "otk/rect.hh"
-#include "otk/screeninfo.hh"
-#include "otk/eventhandler.hh"
-#include "otk/property.hh"
-#include "otk/ustring.hh"
-
-#include <string>
-#include <list>
-
-namespace ob {
-
-class Client;
-
-struct DesktopLayout {
- enum Corner { TopLeft, TopRight, BottomRight, BottomLeft };
- enum Direction { Horizontal, Vertical };
-
- Direction orientation;
- Corner start_corner;
- unsigned int rows;
- unsigned int columns;
-};
-
-//! Manages a single screen
-/*!
-*/
-class Screen : public otk::EventHandler {
-public:
- //! Holds a list of otk::Strut objects
- typedef std::vector<otk::Strut> StrutList;
- //! Holds a list of otk::Rect objects
- typedef std::vector<otk::Rect> RectList;
-
- static const unsigned long event_mask = ColormapChangeMask |
- EnterWindowMask |
- LeaveWindowMask |
- PropertyChangeMask |
- SubstructureNotifyMask |
- SubstructureRedirectMask |
- ButtonPressMask |
- ButtonReleaseMask;
-
- //! All managed clients on the screen (in order of being mapped)
- std::list<Client*> clients;
-
-private:
- //! Was %Openbox able to manage the screen?
- bool _managed;
-
- //! The number of the screen on the X server
- int _number;
-
- //! Information about this screen
- const otk::ScreenInfo *_info;
-
- //! Area usable for placement etc (total - struts), one per desktop,
- //! plus one extra for windows on all desktops
- RectList _area;
-
- //! Combined strut from all of the clients' struts, one per desktop,
- //! plus one extra for windows on all desktops
- StrutList _struts;
-
- //! An offscreen window which gets focus when nothing else has it
- Window _focuswindow;
-
- //! An offscreen window which shows that a NETWM compliant window manager is
- //! running
- Window _supportwindow;
-
- //! A list of all managed clients on the screen, in their stacking order
- std::list<Client*> _stacking;
-
- //! The desktop currently being displayed
- unsigned int _desktop;
-
- //! The number of desktops
- unsigned int _num_desktops;
-
- //! The names of all desktops
- otk::Property::StringVect _desktop_names;
-
- //! The layout of the desktops as specified by an EWMH compliant pager
- DesktopLayout _layout;
-
- //! True when the window manager is in 'showing desktop' mode
- bool _showing_desktop;
-
- //! Calculate the Screen::_area member
- void calcArea();
- //! Set the list of supported NETWM atoms on the root window
- void changeSupportedAtoms();
- //! Set the client list on the root window
- /*!
- Sets the _NET_CLIENT_LIST root window property.<br>
- Also calls Screen::updateStackingList.
- */
- void changeClientList();
- //! Set the client stacking list on the root window
- /*!
- Set the _NET_CLIENT_LIST_STACKING root window property.
- */
- void changeStackingList();
- //! Set the work area hint on the root window
- /*!
- Set the _NET_WORKAREA root window property.
- */
- void changeWorkArea();
-
- //! Get desktop names from the root window property
- void updateDesktopNames();
-
- //! Gets the layout of the desktops from the root window property
- void updateDesktopLayout();
-
- //! Changes to the specified desktop, displaying windows on it and hiding
- //! windows on the others.
- /*!
- @param desktop The number of the desktop to switch to (starts from 0).
- If the desktop is out of valid range, it is ignored.
- */
- void changeDesktop(unsigned int desktop);
-
- //! Changes the number of desktops.
- /*!
- @param num The number of desktops that should exist. This value must be
- greater than 0 or it will be ignored.
- */
- void changeNumDesktops(unsigned int num);
-
-public:
- //! Constructs a new Screen object
- Screen(int screen);
- //! Destroys the Screen object
- virtual ~Screen();
-
- inline int number() const { return _number; }
-
- //! Returns if the screen was successfully managed
- /*!
- If this is false, then the screen should be deleted and should NOT be
- used.
- */
- inline bool managed() const { return _managed; }
-
- //! An offscreen window which gets focus when nothing else has it
- inline Window focuswindow() const { return _focuswindow; }
- //! Returns the desktop being displayed
- inline unsigned int desktop() const { return _desktop; }
- //! Returns the number of desktops
- inline unsigned int numDesktops() const { return _num_desktops; }
- //! When true, the desktop is being shown and all clients are hidden
- inline bool showingDesktop() const { return _showing_desktop; }
-
- //! Returns the area of the screen not reserved by applications' Struts
- /*!
- @param desktop The desktop number of the area to retrieve for. A value of
- 0xffffffff will return an area that combines all struts
- on all desktops.
- */
- const otk::Rect& area(unsigned int desktop) const;
-
- //! Gives the layout of how the desktops are being displayed, the number of
- //! rows and columns etc.
- const DesktopLayout& desktopLayout() const { return _layout; }
-
- //! Shows and focuses the desktop and hides all the client windows, or
- //! returns to the normal state, showing client windows.
- void showDesktop(bool show);
-
- //! Update's the screen's combined strut of all the clients.
- /*!
- Clients should call this whenever they change their strut.
- */
- void updateStruts();
-
- //! Manage any pre-existing windows on the screen
- void manageExisting();
- //! Manage a client window
- /*!
- This gives the window a frame, reparents it, selects events on it, etc.
- */
- void manageWindow(Window window);
- //! Unmanage a client
- /*!
- This removes the window's frame, reparents it to root, unselects events on
- it, etc.
- @param client The client to unmanage
- */
- void unmanageWindow(Client *client);
-
- //! Raises a client window above all others in its stacking layer
- /*!
- raiseWindow has a couple of constraints that lowerWindow does not.<br>
- 1) raiseWindow can be called after changing a Client's stack layer, and
- the list will be reorganized properly.<br>
- 2) raiseWindow guarantees that XRestackWindows() will <i>always</i> be
- called for the specified client.
- */
- void raiseWindow(Client *client);
-
- //! Lowers a client window below all others in its stacking layer
- void lowerWindow(Client *client);
-
- const otk::Property::StringVect& desktopNames() const
- { return _desktop_names; }
-
- void installColormap(bool install) const;
-
- virtual void propertyHandler(const XPropertyEvent &e);
- virtual void clientMessageHandler(const XClientMessageEvent &e);
- virtual void mapRequestHandler(const XMapRequestEvent &e);
-};
-
-}
-
-#endif// __screen_hh