From db451d95bf97b8a8e995f031ac98da50606fd3a0 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 31 Oct 2002 06:54:56 +0000 Subject: rename, remove bullshit. ya --- src/BaseDisplay.cc | 522 ------ src/BaseDisplay.hh | 182 --- src/Color.cc | 244 --- src/Color.hh | 128 -- src/Configuration.cc | 253 --- src/Configuration.hh | 98 -- src/Font.cc | 383 ----- src/Font.hh | 124 -- src/GCCache.cc | 209 --- src/GCCache.hh | 141 -- src/Image.cc | 1703 -------------------- src/Image.hh | 168 -- src/ImageControl.cc | 599 ------- src/Netizen.cc | 117 -- src/Netizen.hh | 63 - src/Screen.cc | 2780 -------------------------------- src/Screen.hh | 432 ----- src/Slit.cc | 915 ----------- src/Slit.hh | 205 --- src/Texture.cc | 204 --- src/Texture.hh | 114 -- src/Timer.cc | 111 -- src/Timer.hh | 131 -- src/Toolbar.cc | 1236 -------------- src/Toolbar.hh | 197 --- src/Util.cc | 254 --- src/Util.hh | 120 -- src/Window.cc | 4357 -------------------------------------------------- src/Window.hh | 436 ----- src/Workspace.cc | 841 ---------- src/Workspace.hh | 123 -- src/XAtom.cc | 526 ------ src/XAtom.hh | 230 --- src/basedisplay.cc | 521 ++++++ src/basedisplay.hh | 182 +++ src/blackbox.cc | 27 +- src/blackbox.hh | 9 +- src/color.cc | 244 +++ src/color.hh | 128 ++ src/configuration.cc | 253 +++ src/configuration.hh | 98 ++ src/font.cc | 374 +++++ src/font.hh | 124 ++ src/gccache.cc | 209 +++ src/gccache.hh | 141 ++ src/i18n.cc | 119 -- src/i18n.hh | 63 - src/image.cc | 1702 ++++++++++++++++++++ src/image.hh | 168 ++ src/imagecontrol.cc | 598 +++++++ src/main.cc | 1 - src/screen.cc | 2777 ++++++++++++++++++++++++++++++++ src/screen.hh | 432 +++++ src/texture.cc | 204 +++ src/texture.hh | 114 ++ src/timer.cc | 111 ++ src/timer.hh | 131 ++ src/util.cc | 254 +++ src/util.hh | 120 ++ src/window.cc | 4356 +++++++++++++++++++++++++++++++++++++++++++++++++ src/window.hh | 436 +++++ src/workspace.cc | 840 ++++++++++ src/workspace.hh | 123 ++ src/xatom.cc | 526 ++++++ src/xatom.hh | 230 +++ 65 files changed, 15413 insertions(+), 18348 deletions(-) delete mode 100644 src/BaseDisplay.cc delete mode 100644 src/BaseDisplay.hh delete mode 100644 src/Color.cc delete mode 100644 src/Color.hh delete mode 100644 src/Configuration.cc delete mode 100644 src/Configuration.hh delete mode 100644 src/Font.cc delete mode 100644 src/Font.hh delete mode 100644 src/GCCache.cc delete mode 100644 src/GCCache.hh delete mode 100644 src/Image.cc delete mode 100644 src/Image.hh delete mode 100644 src/ImageControl.cc delete mode 100644 src/Netizen.cc delete mode 100644 src/Netizen.hh delete mode 100644 src/Screen.cc delete mode 100644 src/Screen.hh delete mode 100644 src/Slit.cc delete mode 100644 src/Slit.hh delete mode 100644 src/Texture.cc delete mode 100644 src/Texture.hh delete mode 100644 src/Timer.cc delete mode 100644 src/Timer.hh delete mode 100644 src/Toolbar.cc delete mode 100644 src/Toolbar.hh delete mode 100644 src/Util.cc delete mode 100644 src/Util.hh delete mode 100644 src/Window.cc delete mode 100644 src/Window.hh delete mode 100644 src/Workspace.cc delete mode 100644 src/Workspace.hh delete mode 100644 src/XAtom.cc delete mode 100644 src/XAtom.hh create mode 100644 src/basedisplay.cc create mode 100644 src/basedisplay.hh create mode 100644 src/color.cc create mode 100644 src/color.hh create mode 100644 src/configuration.cc create mode 100644 src/configuration.hh create mode 100644 src/font.cc create mode 100644 src/font.hh create mode 100644 src/gccache.cc create mode 100644 src/gccache.hh delete mode 100644 src/i18n.cc delete mode 100644 src/i18n.hh create mode 100644 src/image.cc create mode 100644 src/image.hh create mode 100644 src/imagecontrol.cc create mode 100644 src/screen.cc create mode 100644 src/screen.hh create mode 100644 src/texture.cc create mode 100644 src/texture.hh create mode 100644 src/timer.cc create mode 100644 src/timer.hh create mode 100644 src/util.cc create mode 100644 src/util.hh create mode 100644 src/window.cc create mode 100644 src/window.hh create mode 100644 src/workspace.cc create mode 100644 src/workspace.hh create mode 100644 src/xatom.cc create mode 100644 src/xatom.hh diff --git a/src/BaseDisplay.cc b/src/BaseDisplay.cc deleted file mode 100644 index 51d79399..00000000 --- a/src/BaseDisplay.cc +++ /dev/null @@ -1,522 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// BaseDisplay.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -#include -#include -#include - -#ifdef SHAPE -# include -#endif // SHAPE - -#ifdef XINERAMA -# include -#endif // XINERAMA - -#ifdef HAVE_FCNTL_H -# include -#endif // HAVE_FCNTL_H - -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H - -#ifdef HAVE_UNISTD_H -# include -# include -#endif // HAVE_UNISTD_H - -#ifdef HAVE_SYS_SELECT_H -# include -#endif // HAVE_SYS_SELECT_H - -#ifdef HAVE_SIGNAL_H -# include -#endif // HAVE_SIGNAL_H - -#ifndef SA_NODEFER -# ifdef SA_INTERRUPT -# define SA_NODEFER SA_INTERRUPT -# else // !SA_INTERRUPT -# define SA_NODEFER (0) -# endif // SA_INTERRUPT -#endif // SA_NODEFER - -#ifdef HAVE_SYS_WAIT_H -# include -# include -#endif // HAVE_SYS_WAIT_H -} - -#include -using std::string; - -#include "i18n.hh" -#include "BaseDisplay.hh" -#include "GCCache.hh" -#include "Timer.hh" -#include "Util.hh" - - -// X error handler to handle any and all X errors while the application is -// running -static bool internal_error = False; - -BaseDisplay *base_display; - -static int handleXErrors(Display *d, XErrorEvent *e) { -#ifdef DEBUG - char errtxt[128]; - - XGetErrorText(d, e->error_code, errtxt, 128); - fprintf(stderr, - i18n(BaseDisplaySet, BaseDisplayXError, - "%s: X error: %s(%d) opcodes %d/%d\n resource 0x%lx\n"), - base_display->getApplicationName(), errtxt, e->error_code, - e->request_code, e->minor_code, e->resourceid); -#else - // shutup gcc - (void) d; - (void) e; -#endif // DEBUG - - if (internal_error) abort(); - - return(False); -} - - -// signal handler to allow for proper and gentle shutdown - -#ifndef HAVE_SIGACTION -static RETSIGTYPE signalhandler(int sig) { -#else // HAVE_SIGACTION -static void signalhandler(int sig) { -#endif // HAVE_SIGACTION - - static int re_enter = 0; - - switch (sig) { - case SIGCHLD: - int status; - waitpid(-1, &status, WNOHANG | WUNTRACED); - -#ifndef HAVE_SIGACTION - // assume broken, braindead sysv signal semantics - signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler); -#endif // HAVE_SIGACTION - - break; - - default: - if (base_display->handleSignal(sig)) { - -#ifndef HAVE_SIGACTION - // assume broken, braindead sysv signal semantics - signal(sig, (RETSIGTYPE (*)(int)) signalhandler); -#endif // HAVE_SIGACTION - - return; - } - - fprintf(stderr, i18n(BaseDisplaySet, BaseDisplaySignalCaught, - "%s: signal %d caught\n"), - base_display->getApplicationName(), sig); - - if (! base_display->isStartup() && ! re_enter) { - internal_error = True; - - re_enter = 1; - fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayShuttingDown, - "shutting down\n")); - base_display->shutdown(); - } - - if (sig != SIGTERM && sig != SIGINT) { - fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayAborting, - "aborting... dumping core\n")); - abort(); - } - - exit(0); - - break; - } -} - - -BaseDisplay::BaseDisplay(const char *app_name, const char *dpy_name) { - application_name = app_name; - - run_state = STARTUP; - - ::base_display = this; - -#ifdef HAVE_SIGACTION - struct sigaction action; - - action.sa_handler = signalhandler; - action.sa_mask = sigset_t(); - action.sa_flags = SA_NOCLDSTOP | SA_NODEFER; - - sigaction(SIGPIPE, &action, NULL); - sigaction(SIGSEGV, &action, NULL); - sigaction(SIGFPE, &action, NULL); - sigaction(SIGTERM, &action, NULL); - sigaction(SIGINT, &action, NULL); - sigaction(SIGCHLD, &action, NULL); - sigaction(SIGHUP, &action, NULL); - sigaction(SIGUSR1, &action, NULL); - sigaction(SIGUSR2, &action, NULL); -#else // !HAVE_SIGACTION - signal(SIGPIPE, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGSEGV, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGFPE, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGTERM, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGINT, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGUSR1, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGUSR2, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGHUP, (RETSIGTYPE (*)(int)) signalhandler); - signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler); -#endif // HAVE_SIGACTION - - if (! (display = XOpenDisplay(dpy_name))) { - fprintf(stderr, - i18n(BaseDisplaySet, BaseDisplayXConnectFail, - "BaseDisplay::BaseDisplay: connection to X server failed.\n")); - ::exit(2); - } else if (fcntl(ConnectionNumber(display), F_SETFD, 1) == -1) { - fprintf(stderr, - i18n(BaseDisplaySet, BaseDisplayCloseOnExecFail, - "BaseDisplay::BaseDisplay: couldn't mark display connection " - "as close-on-exec\n")); - ::exit(2); - } - - display_name = XDisplayName(dpy_name); - -#ifdef SHAPE - shape.extensions = XShapeQueryExtension(display, &shape.event_basep, - &shape.error_basep); -#else // !SHAPE - shape.extensions = False; -#endif // SHAPE - -#ifdef XINERAMA - if (XineramaQueryExtension(display, &xinerama.event_basep, - &xinerama.error_basep) && - XineramaQueryVersion(display, &xinerama.major, &xinerama.minor)) { -#ifdef DEBUG - fprintf(stderr, - "BaseDisplay::BaseDisplay: Found Xinerama version %d.%d\n", - xinerama.major, xinerama.minor); -#endif // DEBUG - xinerama.extensions = True; - } else { - xinerama.extensions = False; - } -#endif // XINERAMA - - XSetErrorHandler((XErrorHandler) handleXErrors); - - screenInfoList.reserve(ScreenCount(display)); - for (int i = 0; i < ScreenCount(display); ++i) - screenInfoList.push_back(ScreenInfo(this, i)); - - NumLockMask = ScrollLockMask = 0; - - const XModifierKeymap* const modmap = XGetModifierMapping(display); - 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]) - NumLockMask = mask_table[cnt / modmap->max_keypermod]; - if (scroll_lock == modmap->modifiermap[cnt]) - ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; - } - } - - MaskList[0] = 0; - MaskList[1] = LockMask; - MaskList[2] = NumLockMask; - MaskList[3] = LockMask | NumLockMask; - MaskList[4] = ScrollLockMask; - MaskList[5] = ScrollLockMask | LockMask; - MaskList[6] = ScrollLockMask | NumLockMask; - MaskList[7] = ScrollLockMask | LockMask | NumLockMask; - MaskListLength = sizeof(MaskList) / sizeof(MaskList[0]); - - if (modmap) XFreeModifiermap(const_cast(modmap)); - - gccache = (BGCCache *) 0; -} - - -BaseDisplay::~BaseDisplay(void) { - delete gccache; - - XCloseDisplay(display); -} - - -void BaseDisplay::eventLoop(void) { - run(); - - const int xfd = ConnectionNumber(display); - - while (run_state == RUNNING && ! internal_error) { - if (XPending(display)) { - XEvent e; - XNextEvent(display, &e); - process_event(&e); - } else { - fd_set rfds; - timeval now, tm, *timeout = (timeval *) 0; - - FD_ZERO(&rfds); - FD_SET(xfd, &rfds); - - if (! timerList.empty()) { - const BTimer* const timer = timerList.top(); - - gettimeofday(&now, 0); - tm = timer->timeRemaining(now); - - timeout = &tm; - } - - select(xfd + 1, &rfds, 0, 0, timeout); - - // check for timer timeout - gettimeofday(&now, 0); - - // there is a small chance for deadlock here: - // *IF* the timer list keeps getting refreshed *AND* the time between - // timer->start() and timer->shouldFire() is within the timer's period - // then the timer will keep firing. This should be VERY near impossible. - while (! timerList.empty()) { - BTimer *timer = timerList.top(); - if (! timer->shouldFire(now)) - break; - - timerList.pop(); - - timer->fireTimeout(); - timer->halt(); - if (timer->isRecurring()) - timer->start(); - } - } - } -} - - -void BaseDisplay::addTimer(BTimer *timer) { - if (! timer) return; - - timerList.push(timer); -} - - -void BaseDisplay::removeTimer(BTimer *timer) { - timerList.release(timer); -} - - -/* - * 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 BaseDisplay::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) ? MaskListLength / 2: - MaskListLength; - for (size_t cnt = 0; cnt < length; ++cnt) - XGrabButton(display, button, modifiers | MaskList[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 BaseDisplay::ungrabButton(unsigned int button, unsigned int modifiers, - Window grab_window) const { - for (size_t cnt = 0; cnt < MaskListLength; ++cnt) - XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window); -} - - -const ScreenInfo* BaseDisplay::getScreenInfo(unsigned int s) const { - if (s < screenInfoList.size()) - return &screenInfoList[s]; - return (const ScreenInfo*) 0; -} - - -BGCCache* BaseDisplay::gcCache(void) const { - if (! gccache) - gccache = new BGCCache(this, screenInfoList.size()); - - return gccache; -} - - -ScreenInfo::ScreenInfo(BaseDisplay *d, unsigned int num) { - basedisplay = d; - screen_number = num; - - root_window = RootWindow(basedisplay->getXDisplay(), screen_number); - - rect.setSize(WidthOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), - screen_number)), - HeightOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), - screen_number))); - /* - 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. - */ - - depth = DefaultDepth(basedisplay->getXDisplay(), screen_number); - visual = DefaultVisual(basedisplay->getXDisplay(), screen_number); - colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number); - - 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_number; - vinfo_template.c_class = TrueColor; - - vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(), - 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(basedisplay->getXDisplay(), root_window, - visual, AllocNone); - } - - XFree(vinfo_return); - } - - // get the default display string and strip the screen number - string default_string = DisplayString(basedisplay->getXDisplay()); - 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(screen_number)); - -#ifdef 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(d->getXDisplay())) { - /* - 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(d->getXDisplay(), &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; - } - } - } - } -#endif // XINERAMA -} diff --git a/src/BaseDisplay.hh b/src/BaseDisplay.hh deleted file mode 100644 index e4ef2387..00000000 --- a/src/BaseDisplay.hh +++ /dev/null @@ -1,182 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// BaseDisplay.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __BaseDisplay_hh -#define __BaseDisplay_hh - -extern "C" { -#include -#include -} - -#include -#include - -// forward declaration -class BaseDisplay; -class BGCCache; - -#include "Timer.hh" -#include "Util.hh" - -class ScreenInfo { -private: - BaseDisplay *basedisplay; - Visual *visual; - Window root_window; - Colormap colormap; - - int depth; - unsigned int screen_number; - std::string display_string; - Rect rect; -#ifdef XINERAMA - RectList xinerama_areas; - bool xinerama_active; -#endif - -public: - ScreenInfo(BaseDisplay *d, unsigned int num); - - inline BaseDisplay *getBaseDisplay(void) const { return basedisplay; } - inline Visual *getVisual(void) const { return visual; } - inline Window getRootWindow(void) const { return root_window; } - inline Colormap getColormap(void) const { return colormap; } - inline int getDepth(void) const { return depth; } - inline unsigned int getScreenNumber(void) const - { return screen_number; } - inline const Rect& getRect(void) const { return rect; } - inline unsigned int getWidth(void) const { return rect.width(); } - inline unsigned int getHeight(void) const { return rect.height(); } - inline const std::string& displayString(void) const - { return display_string; } -#ifdef XINERAMA - inline const RectList &getXineramaAreas(void) const { return xinerama_areas; } - inline bool isXineramaActive(void) const { return xinerama_active; } -#endif -}; - - -class BaseDisplay: public TimerQueueManager { -private: - struct BShape { - bool extensions; - int event_basep, error_basep; - }; - BShape shape; - -#ifdef XINERAMA - struct BXinerama { - bool extensions; - int event_basep, error_basep; - int major, minor; // version - }; - BXinerama xinerama; -#endif // XINERAMA - - unsigned int MaskList[8]; - size_t MaskListLength; - - enum RunState { STARTUP, RUNNING, SHUTDOWN }; - RunState run_state; - - Display *display; - mutable BGCCache *gccache; - - typedef std::vector ScreenInfoList; - ScreenInfoList screenInfoList; - TimerQueue timerList; - - const char *display_name, *application_name; - - // no copying! - BaseDisplay(const BaseDisplay &); - BaseDisplay& operator=(const BaseDisplay&); - -protected: - // pure virtual function... you must override this - virtual void process_event(XEvent *e) = 0; - - // the masks of the modifiers which are ignored in button events. - int NumLockMask, ScrollLockMask; - - -public: - BaseDisplay(const char *app_name, const char *dpy_name = 0); - virtual ~BaseDisplay(void); - - const ScreenInfo* getScreenInfo(const unsigned int s) const; - - BGCCache *gcCache(void) const; - - inline bool hasShapeExtensions(void) const - { return shape.extensions; } -#ifdef XINERAMA - inline bool hasXineramaExtensions(void) const - { return xinerama.extensions; } -#endif // XINERAMA - inline bool doShutdown(void) const - { return run_state == SHUTDOWN; } - inline bool isStartup(void) const - { return run_state == STARTUP; } - - inline Display *getXDisplay(void) const { return display; } - - inline const char *getXDisplayName(void) const - { return display_name; } - inline const char *getApplicationName(void) const - { return application_name; } - - inline unsigned int getNumberOfScreens(void) const - { return screenInfoList.size(); } - inline int getShapeEventBase(void) const - { return shape.event_basep; } -#ifdef XINERAMA - inline int getXineramaMajorVersion(void) const - { return xinerama.major; } -#endif // XINERAMA - - inline void shutdown(void) { run_state = SHUTDOWN; } - inline void run(void) { run_state = RUNNING; } - - 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 eventLoop(void); - - // from TimerQueueManager interface - virtual void addTimer(BTimer *timer); - virtual void removeTimer(BTimer *timer); - - // another pure virtual... this is used to handle signals that BaseDisplay - // doesn't understand itself - virtual bool handleSignal(int sig) = 0; -}; - - -#endif // __BaseDisplay_hh diff --git a/src/Color.cc b/src/Color.cc deleted file mode 100644 index 85f3ec19..00000000 --- a/src/Color.cc +++ /dev/null @@ -1,244 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Color.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -} - -#include - -#include "Color.hh" -#include "BaseDisplay.hh" - - -BColor::ColorCache BColor::colorcache; -bool BColor::cleancache = false; - -BColor::BColor(const BaseDisplay * const _display, unsigned int _screen) - : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen) -{} - -BColor::BColor(int _r, int _g, int _b, - const BaseDisplay * const _display, unsigned int _screen) - : allocated(false), r(_r), g(_g), b(_b), p(0), dpy(_display), scrn(_screen) -{} - - -BColor::BColor(const std::string &_name, - const BaseDisplay * const _display, unsigned int _screen) - : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen), - colorname(_name) { - parseColorName(); -} - - -BColor::~BColor(void) { - deallocate(); -} - - -void BColor::setDisplay(const BaseDisplay * const _display, - unsigned int _screen) { - if (_display == display() && _screen == screen()) { - // nothing to do - return; - } - - deallocate(); - - dpy = _display; - scrn = _screen; - - if (! colorname.empty()) { - parseColorName(); - } -} - - -unsigned long BColor::pixel(void) const { - if (! allocated) { - // mutable - BColor *that = (BColor *) this; - that->allocate(); - } - - return p; -} - - -void BColor::parseColorName(void) { - assert(dpy != 0); - - if (colorname.empty()) { - fprintf(stderr, "BColor: empty colorname, cannot parse (using black)\n"); - setRGB(0, 0, 0); - } - - if (scrn == ~(0u)) - scrn = DefaultScreen(display()->getXDisplay()); - Colormap colormap = display()->getScreenInfo(scrn)->getColormap(); - - // get rgb values from colorname - XColor xcol; - xcol.red = 0; - xcol.green = 0; - xcol.blue = 0; - xcol.pixel = 0; - - if (! XParseColor(display()->getXDisplay(), colormap, - colorname.c_str(), &xcol)) { - fprintf(stderr, "BColor::allocate: color parse error: \"%s\"\n", - colorname.c_str()); - setRGB(0, 0, 0); - return; - } - - setRGB(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8); -} - - -void BColor::allocate(void) { - assert(dpy != 0); - - if (scrn == ~(0u)) scrn = DefaultScreen(display()->getXDisplay()); - Colormap colormap = display()->getScreenInfo(scrn)->getColormap(); - - if (! isValid()) { - if (colorname.empty()) { - fprintf(stderr, "BColor: cannot allocate invalid color (using black)\n"); - setRGB(0, 0, 0); - } else { - parseColorName(); - } - } - - // see if we have allocated this color before - RGB rgb(display(), scrn, r, g, b); - ColorCache::iterator it = colorcache.find(rgb); - if (it != colorcache.end()) { - // found - allocated = true; - p = (*it).second.p; - (*it).second.count++; - return; - } - - // allocate color from rgb values - XColor xcol; - xcol.red = r | r << 8; - xcol.green = g | g << 8; - xcol.blue = b | b << 8; - xcol.pixel = 0; - - if (! XAllocColor(display()->getXDisplay(), colormap, &xcol)) { - fprintf(stderr, "BColor::allocate: color alloc error: rgb:%x/%x/%x\n", - r, g, b); - xcol.pixel = 0; - } - - p = xcol.pixel; - allocated = true; - - colorcache.insert(ColorCacheItem(rgb, PixelRef(p))); - - if (cleancache) - doCacheCleanup(); -} - - -void BColor::deallocate(void) { - if (! allocated) - return; - - assert(dpy != 0); - - ColorCache::iterator it = colorcache.find(RGB(display(), scrn, r, g, b)); - if (it != colorcache.end()) { - if ((*it).second.count >= 1) - (*it).second.count--; - } - - if (cleancache) - doCacheCleanup(); - - allocated = false; -} - - -BColor &BColor::operator=(const BColor &c) { - deallocate(); - - setRGB(c.r, c.g, c.b); - colorname = c.colorname; - dpy = c.dpy; - scrn = c.scrn; - return *this; -} - - -void BColor::cleanupColorCache(void) { - cleancache = true; -} - - -void BColor::doCacheCleanup(void) { - // ### TODO - support multiple displays! - ColorCache::iterator it = colorcache.begin(); - if (it == colorcache.end()) { - // nothing to do - return; - } - - const BaseDisplay* const display = (*it).first.display; - unsigned long *pixels = new unsigned long[ colorcache.size() ]; - unsigned int i, count; - - for (i = 0; i < display->getNumberOfScreens(); i++) { - count = 0; - it = colorcache.begin(); - - while (it != colorcache.end()) { - if ((*it).second.count != 0 || (*it).first.screen != i) { - ++it; - continue; - } - - pixels[ count++ ] = (*it).second.p; - ColorCache::iterator it2 = it; - ++it; - colorcache.erase(it2); - } - - if (count > 0) - XFreeColors(display->getXDisplay(), - display->getScreenInfo(i)->getColormap(), - pixels, count, 0); - } - - delete [] pixels; - cleancache = false; -} diff --git a/src/Color.hh b/src/Color.hh deleted file mode 100644 index 9eb8ef2e..00000000 --- a/src/Color.hh +++ /dev/null @@ -1,128 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Color.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef COLOR_HH -#define COLOR_HH - -extern "C" { -#include -} - -#include -#include - -class BaseDisplay; - -class BColor { -public: - BColor(const BaseDisplay * const _display = 0, unsigned int _screen = ~(0u)); - BColor(int _r, int _g, int _b, - const BaseDisplay * const _display, unsigned int _screen = ~(0u)); - BColor(const std::string &_name, - const BaseDisplay * const _display, unsigned int _screen = ~(0u)); - ~BColor(void); - - inline const std::string &name(void) const { return colorname; } - - inline int red(void) const { return r; } - inline int green(void) const { return g; } - inline int blue(void) const { return b; } - void setRGB(int _r, int _g, int _b) { - deallocate(); - r = _r; - g = _g; - b = _b; - } - - inline const BaseDisplay *display(void) const { return dpy; } - inline unsigned int screen(void) const { return scrn; } - void setDisplay(const BaseDisplay * const _display, - unsigned int _screen = ~(0u)); - - inline bool isAllocated(void) const { return allocated; } - - inline bool isValid(void) const { return r != -1 && g != -1 && b != -1; } - - unsigned long pixel(void) const; - - // operators - BColor &operator=(const BColor &c); - inline bool operator==(const BColor &c) const - { return (r == c.r && b == c.b && b == c.b); } - inline bool operator!=(const BColor &c) const - { return (! operator==(c)); } - - static void cleanupColorCache(void); - -private: - void parseColorName(void); - void allocate(void); - void deallocate(void); - - bool allocated; - int r, g, b; - unsigned long p; - const BaseDisplay *dpy; - unsigned int scrn; - std::string colorname; - - // global color allocator/deallocator - struct RGB { - const BaseDisplay* const display; - const unsigned int screen; - const int r, g, b; - - RGB(void) : display(0), screen(~(0u)), r(-1), g(-1), b(-1) { } - RGB(const BaseDisplay * const a, const unsigned int b, - const int x, const int y, const int z) - : display(a), screen(b), r(x), g(y), b(z) {} - RGB(const RGB &x) - : display(x.display), screen(x.screen), r(x.r), g(x.g), b(x.b) {} - - inline bool operator==(const RGB &x) const { - return display == x.display && - screen == x.screen && - r == x.r && g == x.g && b == x.b; - } - - inline bool operator<(const RGB &x) const { - unsigned long p1, p2; - p1 = (screen << 24 | r << 16 | g << 8 | b) & 0x00ffffff; - p2 = (x.screen << 24 | x.r << 16 | x.g << 8 | x.b) & 0x00ffffff; - return p1 < p2; - } - }; - struct PixelRef { - const unsigned long p; - unsigned int count; - inline PixelRef(void) : p(0), count(0) { } - inline PixelRef(const unsigned long x) : p(x), count(1) { } - }; - typedef std::map ColorCache; - typedef ColorCache::value_type ColorCacheItem; - static ColorCache colorcache; - static bool cleancache; - static void doCacheCleanup(void); -}; - -#endif // COLOR_HH diff --git a/src/Configuration.cc b/src/Configuration.cc deleted file mode 100644 index 52e1b272..00000000 --- a/src/Configuration.cc +++ /dev/null @@ -1,253 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Configuration.hh for Blackbox - an X11 Window manager -// Copyright (c) 2002 - 2002 Ben Jansens (ben@orodu.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H -} - -#include "Configuration.hh" -#include "Util.hh" - -#include - -using std::string; - -bool Configuration::_initialized = False; - -Configuration::Configuration(const string &file, bool autosave) { - setFile(file); - _modified = False; - _database = NULL; - _autosave = autosave; - if (! _initialized) { - XrmInitialize(); - _initialized = True; - } -} - -Configuration::Configuration(bool autosave) { - _modified = False; - _database = NULL; - _autosave = autosave; - if (! _initialized) { - XrmInitialize(); - _initialized = True; - } -} - -Configuration::~Configuration() { - if (_database != NULL) - XrmDestroyDatabase(_database); -} - -void Configuration::setFile(const string &file) { - _file = file; -} - -void Configuration::setAutoSave(bool autosave) { - _autosave = autosave; -} - -void Configuration::save() { - assert(_database != NULL); - XrmPutFileDatabase(_database, _file.c_str()); - _modified = False; -} - -bool Configuration::load() { - if (_database != NULL) - XrmDestroyDatabase(_database); - _modified = False; - if (NULL == (_database = XrmGetFileDatabase(_file.c_str()))) - return False; - return True; -} - -bool Configuration::merge(const string &file, bool overwrite) { - if (XrmCombineFileDatabase(file.c_str(), &_database, overwrite) == 0) - return False; - _modified = True; - if (_autosave) - save(); - return True; -} - -void Configuration::create() { - if (_database != NULL) - XrmDestroyDatabase(_database); - _modified = False; - assert(NULL != (_database = XrmGetStringDatabase(""))); -} - -void Configuration::setValue(const string &rname, bool value) { - assert(_database != NULL); - - const char *val = (value ? "True" : "False"); - string rc_string = rname + ": " + val; - XrmPutLineResource(&_database, rc_string.c_str()); - - _modified = True; - if (_autosave) - save(); -} - -void Configuration::setValue(const string &rname, unsigned long value) { - assert(_database != NULL); - - string rc_string = rname + ": " + itostring(value); - XrmPutLineResource(&_database, rc_string.c_str()); - - _modified = True; - if (_autosave) - save(); -} - -void Configuration::setValue(const string &rname, long value) { - assert(_database != NULL); - - string rc_string = rname + ": " + itostring(value); - XrmPutLineResource(&_database, rc_string.c_str()); - - _modified = True; - if (_autosave) - save(); -} - -void Configuration::setValue(const string &rname, const char *value) { - assert(_database != NULL); - assert(value != NULL); - - string rc_string = rname + ": " + value; - XrmPutLineResource(&_database, rc_string.c_str()); - - _modified = True; - if (_autosave) - save(); -} - -void Configuration::setValue(const string &rname, const string &value) { - assert(_database != NULL); - - string rc_string = rname + ": " + value; - XrmPutLineResource(&_database, rc_string.c_str()); - - _modified = True; - if (_autosave) - save(); -} - -bool Configuration::getValue(const string &rname, bool &value) const { - assert(_database != NULL); - - string rclass = createClassName(rname); - - char *rettype; - XrmValue retvalue; - if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), - &rettype, &retvalue) || retvalue.addr == NULL) - return False; - string val = retvalue.addr; - if (val == "True" || val == "True") - value = True; - else - value = False; - return True; -} - -bool Configuration::getValue(const string &rname, long &value) const { - assert(_database != NULL); - - string rclass = createClassName(rname); - - char *rettype; - XrmValue retvalue; - if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), - &rettype, &retvalue) || retvalue.addr == NULL) - return False; - char *end; - value = strtol(retvalue.addr, &end, 10); - if (end == retvalue.addr) - return False; - return True; -} - -bool Configuration::getValue(const string &rname, unsigned long &value) const { - assert(_database != NULL); - - string rclass = createClassName(rname); - - char *rettype; - XrmValue retvalue; - if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), - &rettype, &retvalue) || retvalue.addr == NULL) - return False; - char *end; - value = strtoul(retvalue.addr, &end, 10); - if (end == retvalue.addr) - return False; - return True; -} - -bool Configuration::getValue(const string &rname, - string &value) const { - assert(_database != NULL); - - string rclass = createClassName(rname); - - char *rettype; - XrmValue retvalue; - if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), - &rettype, &retvalue) || retvalue.addr == NULL) - return False; - value = retvalue.addr; - return True; -} - - -string Configuration::createClassName(const string &rname) const { - string rclass(rname); - - string::iterator it = rclass.begin(), end = rclass.end(); - while (True) { - *it = toUpper(*it); - ++it; - if (it == end) break; - it = std::find(it, rclass.end(), '.'); - if (it == end) break; - ++it; - if (it == end) break; - } - return rclass; -} - - -char Configuration::toUpper(char c) const { - if (c >= 'a' && c <= 'z') - return c - 'a' + 'A'; - return c; -} diff --git a/src/Configuration.hh b/src/Configuration.hh deleted file mode 100644 index 8f4a3157..00000000 --- a/src/Configuration.hh +++ /dev/null @@ -1,98 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Configuration.hh for Blackbox - an X11 Window manager -// Copyright (c) 2002 - 2002 Ben Jansens (ben@orodu.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Configuration_hh -#define __Configuration_hh - -#include -#include -#include - -/* - * The Configuration class is a generic wrapper for configuration settings. - * - * This class is used for the global rc/config file, and for styles. - * - * This implementation of the Configuration class wraps an X resource database - * file. - */ -class Configuration { -public: - explicit Configuration(const std::string &file, bool autosave = True); - Configuration(bool autosave = True); - virtual ~Configuration(); - - inline const std::string &file() const { - return static_cast(_file); - } - void setFile(const std::string &file); - - // defaults to true! - inline bool autoSave() const { - return _autosave; - } - void setAutoSave(bool); - - inline bool isModified() const { - return _modified; - } - - void save(); - bool load(); - bool merge(const std::string &file, bool overwrite = False); - void create(); - - void setValue(const std::string &rname, bool value); - inline void setValue(const std::string &rname, int value) { - setValue(rname, (long) value); - } - inline void setValue(const std::string &rname, unsigned int value) { - setValue(rname, (unsigned long) value); - } - void setValue(const std::string &rname, long value); - void setValue(const std::string &rname, unsigned long value); - void setValue(const std::string &rname, const std::string &value); - void setValue(const std::string &rname, const char *value); - - bool getValue(const std::string &rname, bool &value) const; - inline bool getValue(const std::string &rname, int &value) const { - return getValue(rname, (long) value); - } - inline bool getValue(const std::string &rname, unsigned int &value) const { - return getValue(rname, (unsigned long) value); - } - bool getValue(const std::string &rname, long &value) const; - bool getValue(const std::string &rname, unsigned long &value) const; - bool getValue(const std::string &rname, std::string &value) const; - -private: - std::string createClassName(const std::string &rname) const; - char toUpper(char) const; - - static bool _initialized; - std::string _file; - bool _modified; - bool _autosave; - XrmDatabase _database; -}; - -#endif // __Configuration_hh diff --git a/src/Font.cc b/src/Font.cc deleted file mode 100644 index 4699350c..00000000 --- a/src/Font.cc +++ /dev/null @@ -1,383 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Font.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H -} - -#include -#include - -using std::string; -using std::cerr; -using std::endl; - -#include "i18n.hh" -#include "Font.hh" -#include "Util.hh" -#include "GCCache.hh" -#include "Color.hh" - -string BFont::_fallback_font = "fixed"; - -#ifdef XFT -BFont::BFont(Display *d, BScreen *screen, const string &family, int size, - bool bold, bool italic, bool shadow, unsigned char offset, - int tint, bool antialias) : - _display(d), - _screen(screen), - _family(family), - _simplename(False), - _size(size), - _bold(bold), - _italic(italic), - _antialias(antialias), - _shadow(shadow), - _offset(offset), - _tint(tint), - _xftfont(0), - _font(0), - _fontset(0), - _fontset_extents(0) { - _valid = False; - - _xftfont = XftFontOpen(_display, _screen->getScreenNumber(), - XFT_FAMILY, XftTypeString, _family.c_str(), - XFT_SIZE, XftTypeInteger, _size, - XFT_WEIGHT, XftTypeInteger, (_bold ? - XFT_WEIGHT_BOLD : - XFT_WEIGHT_MEDIUM), - XFT_SLANT, XftTypeInteger, (_italic ? - XFT_SLANT_ITALIC : - XFT_SLANT_ROMAN), - XFT_ANTIALIAS, XftTypeBool, _antialias, - 0); - if (! _xftfont) - return; // failure - - _font = XLoadQueryFont(_display, buildXlfd().c_str()); - if (! _font) - return; // failure - - _valid = True; -} -#endif - - -BFont::BFont(Display *d, BScreen *screen, const string &xlfd) : - _display(d), - _screen(screen), -#ifdef XFT - _antialias(False), - _shadow(False), - _xftfont(0), -#endif // XFT - _font(0), - _fontset(0), - _fontset_extents(0) { - string int_xlfd; - if (xlfd.empty()) - int_xlfd = _fallback_font; - else - int_xlfd = xlfd; - - if ((_valid = createXFont(int_xlfd))) - return; // success - - if (int_xlfd != _fallback_font) { - // try the fallback - cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl << - "Falling back to default '" << _fallback_font << "'" << endl; - - if ((_valid = createXFont(_fallback_font))) - return; // success - } - - cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl << - "Giving up!" << endl; - return; // failure -} - - -bool BFont::createXFont(const std::string &xlfd) { - /* - Even though this is only used for font sets (multibyte), it is still parsed - out so that the bold/italic/etc information is still available from the - class when using non-multibyte. - - This is where _simplename, _bold, _italic, and _size are initialized, since - they are not initialized in the constructor. This needs to occur before - calling any Xlfd-building functions. - */ - if (! parseXlfd(xlfd)) - return False; - - if (i18n.multibyte()) { - char **missing, *def = "-"; - int nmissing; - - _fontset = XCreateFontSet(_display, buildMultibyteXlfd().c_str(), - &missing, &nmissing, &def); - if (nmissing) XFreeStringList(missing); - if (_fontset) - _fontset_extents = XExtentsOfFontSet(_fontset); - else - return False; - - assert(_fontset_extents); - } - - _font = XLoadQueryFont(_display, xlfd.c_str()); - if (! _font) - return False; - return True; -} - - -BFont::~BFont(void) { -#ifdef XFT - if (_xftfont) - XftFontClose(_display, _xftfont); -#endif // XFT - - if (i18n.multibyte() && _fontset) - XFreeFontSet(_display, _fontset); - if (_font) - XFreeFont(_display, _font); -} - - -/* - * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD. - */ -string BFont::buildXlfd(void) const { - if (_simplename) - return _family; - - string weight = _bold ? "bold" : "medium"; - string slant = _italic ? "i" : "r"; - string sizestr= _size ? itostring(_size * 10) : "*"; - - return "-*-" + _family + "-" + weight + "-" + slant + "-*-*-*-" + sizestr + - "-*-*-*-*-*-*"; -} - - -/* - * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD. - */ -string BFont::buildMultibyteXlfd(void) const { - string weight = _bold ? "bold" : "medium"; - string slant = _italic ? "i" : "r"; - string sizestr= _size ? itostring(_size) : "*"; - - return _family + ',' - + "-*-*-" + weight + "-" + slant + "-*-*-*-" + sizestr + - "-*-*-*-*-*-*" + ',' - + "-*-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*" + ',' + - + "*"; -} - - -/* - * Takes a full X font name and parses it out so we know if we're bold, our - * size, etc. - */ -bool BFont::parseXlfd(const string &xlfd) { - if (xlfd.empty() || xlfd[0] != '-') { - _family = xlfd; - _simplename = True; - _bold = False; - _italic = False; - _size = 0; - } else { - _simplename = False; - string weight, - slant, - sizestr; - int i = 0; - - string::const_iterator it = xlfd.begin(), end = xlfd.end(); - while(1) { - string::const_iterator tmp = it; // current string.begin() - it = std::find(tmp, end, '-'); // look for comma between tmp and end - if (i == 2) _family = string(tmp, it); // s[tmp:it] - if (i == 3) weight = string(tmp, it); - if (i == 4) slant = string(tmp, it); - if (i == 7 && string(tmp, it) != "*") sizestr = string(tmp, it); - if (sizestr.empty() && - i == 8 && string(tmp, it) != "*") sizestr = string(tmp, it); - if (it == end || i >= 8) - break; - ++it; - ++i; - } - if (i < 3) // no name even! can't parse that - return False; - _bold = weight == "bold" || weight == "demibold"; - _italic = slant == "i" || slant == "o"; - _size = atoi(sizestr.c_str()) / 10; - } - - // min/max size restrictions for sanity, but 0 is the font's "default size" - if (_size && _size < 3) - _size = 3; - else if (_size > 97) - _size = 97; - - return True; -} - - -void BFont::drawString(Drawable d, int x, int y, const BColor &color, - const string &string) const { - assert(_valid); - -#ifdef XFT - if (_xftfont) { - XftDraw *draw = XftDrawCreate(_display, d, _screen->getVisual(), - _screen->getColormap()); - assert(draw); - - - if (_shadow) { - XftColor c; - if (_tint >= 0) { - c.color.red = 0; - c.color.green = 0; - c.color.blue = 0; - c.color.alpha = 0xffff * _tint/100; // transparent shadow - c.pixel = BlackPixel(_display, _screen->getScreenNumber()); - } else { - c.color.red = 0xffff * -_tint/100; - c.color.green = 0xffff * -_tint/100; - c.color.blue = 0xffff * -_tint/100; - c.color.alpha = 0xffff * -_tint/100; - c.pixel = WhitePixel(_display, _screen->getScreenNumber()); - } -#ifdef XFT_UTF8 - XftDrawStringUtf8( -#else - XftDrawString8( -#endif - draw, &c, _xftfont, x + _offset, - _xftfont->ascent + y + _offset, (XftChar8 *) string.c_str(), - string.size()); - } - - 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 BColor yet - -#ifdef XFT_UTF8 - XftDrawStringUtf8( -#else - XftDrawString8( -#endif - draw, &c, _xftfont, x, _xftfont->ascent + y, - (XftChar8 *) string.c_str(), string.size()); - - XftDrawDestroy(draw); - return; - } -#endif // XFT - - BPen pen(color, _font); - - if (i18n.multibyte()) - XmbDrawString(_display, d, _fontset, pen.gc(), - x, y - _fontset_extents->max_ink_extent.y, - string.c_str(), string.size()); - else - XDrawString(_display, d, pen.gc(), - x, _font->ascent + y, - string.c_str(), string.size()); -} - - -unsigned int BFont::measureString(const string &string) const { - assert(_valid); - -#ifdef XFT - if (_xftfont) { - XGlyphInfo info; - -#ifdef XFT_UTF8 - XftTextExtentsUtf8( -#else - XftTextExtents8( -#endif - _display, _xftfont, (XftChar8 *) string.c_str(), - string.size(), &info); - - return info.xOff + (_shadow ? _offset : 0); - } -#endif // XFT - - if (i18n.multibyte()) { - XRectangle ink, logical; - XmbTextExtents(_fontset, string.c_str(), string.size(), &ink, &logical); - return logical.width; - } else { - return XTextWidth(_font, string.c_str(), string.size()); - } -} - - -unsigned int BFont::height(void) const { - assert(_valid); - -#ifdef XFT - if (_xftfont) - return _xftfont->height + (_shadow ? _offset : 0); -#endif // XFT - - if (i18n.multibyte()) - return _fontset_extents->max_ink_extent.height; - else - return _font->ascent + _font->descent; -} - - -unsigned int BFont::maxCharWidth(void) const { - assert(_valid); - -#ifdef XFT - if (_xftfont) - return _xftfont->max_advance_width; -#endif // XFT - - if (i18n.multibyte()) - return _fontset_extents->max_logical_extent.width; - else - return _font->max_bounds.rbearing - _font->min_bounds.lbearing; -} diff --git a/src/Font.hh b/src/Font.hh deleted file mode 100644 index 6f6431ef..00000000 --- a/src/Font.hh +++ /dev/null @@ -1,124 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Font.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Font_hh -#define __Font_hh - -extern "C" { -#include - -#ifdef XFT -# include -#endif -} - -#include - -#include - -class BGCCache; -class BGCCacheItem; -class BColor; - -#include "Screen.hh" - -class BFont { - /* - * static members - */ -private: - static std::string _fallback_font; - -public: - // the fallback is only used for X fonts, not for Xft fonts, since it is - // assumed that X fonts will be the fallback from Xft. - inline static std::string fallbackFont(void) { return _fallback_font; } - inline static void setFallbackFont(const std::string &f) - { _fallback_font = f; } - - /* - * instance members - */ -private: - Display *_display; - BScreen *_screen; - - std::string _family; - bool _simplename; // true if not spec'd as a -*-* string - int _size; - bool _bold; - bool _italic; - -#ifdef XFT - bool _antialias; - bool _shadow; - unsigned char _offset; - int _tint; - - XftFont *_xftfont; - - bool createXftFont(void); -#endif - - // standard - XFontStruct *_font; - // multibyte - XFontSet _fontset; - XFontSetExtents *_fontset_extents; - - std::string buildXlfd(void) const; - std::string buildMultibyteXlfd(void) const; - - bool createXFont(const std::string &xlfd); - bool parseXlfd(const std::string &xlfd); - - bool _valid; - -public: -#ifdef XFT - // loads an Xft font - BFont(Display *d, BScreen *screen, const std::string &family, int size, - bool bold, bool italic, bool shadow, unsigned char offset, - int tint, bool antialias = True); -#endif - // loads a standard X font - BFont(Display *d, BScreen *screen, const std::string &xlfd); - virtual ~BFont(void); - - inline bool valid(void) const { return _valid; } - - inline std::string family(void) const { assert(_valid); return _family; } - inline int size(void) const { assert(_valid); return _size; } - inline bool bold(void) const { assert(_valid); return _bold; } - inline bool italic(void) const { assert(_valid); return _italic; } - - unsigned int height(void) const; - unsigned int maxCharWidth(void) const; - - unsigned int measureString(const std::string &string) const; - - void drawString(Drawable d, int x, int y, const BColor &color, - const std::string &string) const; -}; - -#endif // __Font_hh diff --git a/src/GCCache.cc b/src/GCCache.cc deleted file mode 100644 index 829d130f..00000000 --- a/src/GCCache.cc +++ /dev/null @@ -1,209 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// GCCache.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -} - -#include "GCCache.hh" -#include "BaseDisplay.hh" -#include "Color.hh" -#include "Util.hh" - - -BGCCacheContext::~BGCCacheContext(void) { - if (gc) - XFreeGC(display->getXDisplay(), gc); -} - - -void BGCCacheContext::set(const BColor &_color, - const XFontStruct * const _font, - const int _function, const int _subwindow, - int _linewidth) { - XGCValues gcv; - pixel = gcv.foreground = _color.pixel(); - function = gcv.function = _function; - subwindow = gcv.subwindow_mode = _subwindow; - linewidth = gcv.line_width = _linewidth; - gcv.cap_style = CapProjecting; - - unsigned long mask = GCForeground | GCFunction | GCSubwindowMode | - GCLineWidth | GCCapStyle; - - if (_font) { - fontid = gcv.font = _font->fid; - mask |= GCFont; - } else { - fontid = 0; - } - - XChangeGC(display->getXDisplay(), gc, mask, &gcv); -} - - -void BGCCacheContext::set(const XFontStruct * const _font) { - if (! _font) { - fontid = 0; - return; - } - - XGCValues gcv; - fontid = gcv.font = _font->fid; - XChangeGC(display->getXDisplay(), gc, GCFont, &gcv); -} - - -BGCCache::BGCCache(const BaseDisplay * const _display, - unsigned int screen_count) - : display(_display), context_count(128u), - cache_size(16u), cache_buckets(8u * screen_count), - cache_total_size(cache_size * cache_buckets) { - - contexts = new BGCCacheContext*[context_count]; - unsigned int i; - for (i = 0; i < context_count; i++) { - contexts[i] = new BGCCacheContext(display); - } - - cache = new BGCCacheItem*[cache_total_size]; - for (i = 0; i < cache_total_size; ++i) { - cache[i] = new BGCCacheItem; - } -} - - -BGCCache::~BGCCache(void) { - std::for_each(contexts, contexts + context_count, PointerAssassin()); - std::for_each(cache, cache + cache_total_size, PointerAssassin()); - delete [] cache; - delete [] contexts; -} - - -BGCCacheContext *BGCCache::nextContext(unsigned int scr) { - Window hd = display->getScreenInfo(scr)->getRootWindow(); - - BGCCacheContext *c; - - for (unsigned int i = 0; i < context_count; ++i) { - c = contexts[i]; - - if (! c->gc) { - c->gc = XCreateGC(display->getXDisplay(), hd, 0, 0); - c->used = false; - c->screen = scr; - } - if (! c->used && c->screen == scr) - return c; - } - - fprintf(stderr, "BGCCache: context fault!\n"); - abort(); - return (BGCCacheContext*) 0; // not reached -} - - -void BGCCache::release(BGCCacheContext *ctx) { - ctx->used = false; -} - - -BGCCacheItem *BGCCache::find(const BColor &_color, - const XFontStruct * const _font, - int _function, int _subwindow, int _linewidth) { - const unsigned long pixel = _color.pixel(); - const unsigned int screen = _color.screen(); - const int key = _color.red() ^ _color.green() ^ _color.blue(); - int k = (key % cache_size) * cache_buckets; - unsigned int i = 0; // loop variable - BGCCacheItem *c = cache[ k ], *prev = 0; - - /* - this will either loop cache_buckets times then return/abort or - it will stop matching - */ - while (c->ctx && - (c->ctx->pixel != pixel || c->ctx->function != _function || - c->ctx->subwindow != _subwindow || c->ctx->screen != screen || - c->ctx->linewidth != _linewidth)) { - if (i < (cache_buckets - 1)) { - prev = c; - c = cache[ ++k ]; - ++i; - continue; - } - if (c->count == 0 && c->ctx->screen == screen) { - // use this cache item - c->ctx->set(_color, _font, _function, _subwindow, _linewidth); - c->ctx->used = true; - c->count = 1; - c->hits = 1; - return c; - } - // cache fault! - fprintf(stderr, "BGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen); - abort(); - } - - if (c->ctx) { - // reuse existing context - if (_font && _font->fid && _font->fid != c->ctx->fontid) - c->ctx->set(_font); - c->count++; - c->hits++; - if (prev && c->hits > prev->hits) { - cache[ k ] = prev; - cache[ k - 1 ] = c; - } - } else { - c->ctx = nextContext(screen); - c->ctx->set(_color, _font, _function, _subwindow, _linewidth); - c->ctx->used = true; - c->count = 1; - c->hits = 1; - } - - return c; -} - - -void BGCCache::release(BGCCacheItem *_item) { - _item->count--; -} - - -void BGCCache::purge(void) { - for (unsigned int i = 0; i < cache_total_size; ++i) { - BGCCacheItem *d = cache[ i ]; - - if (d->ctx && d->count == 0) { - release(d->ctx); - d->ctx = 0; - } - } -} diff --git a/src/GCCache.hh b/src/GCCache.hh deleted file mode 100644 index 614eac1d..00000000 --- a/src/GCCache.hh +++ /dev/null @@ -1,141 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// GCCache.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef GCCACHE_HH -#define GCCACHE_HH - -extern "C" { -#include -} - -#include "BaseDisplay.hh" -#include "Color.hh" - -class BGCCacheItem; - -class BGCCacheContext { -public: - void set(const BColor &_color, const XFontStruct * const _font, - const int _function, const int _subwindow, const int _linewidth); - void set(const XFontStruct * const _font); - - ~BGCCacheContext(void); - -private: - BGCCacheContext(const BaseDisplay * const _display) - : display(_display), gc(0), pixel(0ul), fontid(0ul), - function(0), subwindow(0), used(false), screen(~(0u)), linewidth(0) {} - - const BaseDisplay *display; - GC gc; - unsigned long pixel; - unsigned long fontid; - int function; - int subwindow; - bool used; - unsigned int screen; - int linewidth; - - BGCCacheContext(const BGCCacheContext &_nocopy); - BGCCacheContext &operator=(const BGCCacheContext &_nocopy); - - friend class BGCCache; - friend class BGCCacheItem; -}; - -class BGCCacheItem { -public: - inline const GC &gc(void) const { return ctx->gc; } - -private: - BGCCacheItem(void) : ctx(0), count(0), hits(0), fault(false) { } - - BGCCacheContext *ctx; - unsigned int count; - unsigned int hits; - bool fault; - - BGCCacheItem(const BGCCacheItem &_nocopy); - BGCCacheItem &operator=(const BGCCacheItem &_nocopy); - - friend class BGCCache; -}; - -class BGCCache { -public: - BGCCache(const BaseDisplay * const _display, unsigned int screen_count); - ~BGCCache(void); - - // cleans up the cache - void purge(void); - - BGCCacheItem *find(const BColor &_color, const XFontStruct * const _font = 0, - int _function = GXcopy, int _subwindow = ClipByChildren, - int _linewidth = 0); - void release(BGCCacheItem *_item); - -private: - BGCCacheContext *nextContext(unsigned int _screen); - void release(BGCCacheContext *ctx); - - // this is closely modelled after the Qt GC cache, but with some of the - // complexity stripped out - const BaseDisplay *display; - - const unsigned int context_count; - const unsigned int cache_size; - const unsigned int cache_buckets; - const unsigned int cache_total_size; - BGCCacheContext **contexts; - BGCCacheItem **cache; -}; - -class BPen { -public: - inline BPen(const BColor &_color, const XFontStruct * const _font = 0, - int _linewidth = 0, int _function = GXcopy, - int _subwindow = ClipByChildren) - : color(_color), font(_font), linewidth(_linewidth), function(_function), - subwindow(_subwindow), cache(_color.display()->gcCache()), item(0) { } - - inline ~BPen(void) { if (item) cache->release(item); } - - inline const GC &gc(void) const { - if (! item) item = cache->find(color, font, function, subwindow, - linewidth); - return item->gc(); - } - -private: - const BColor &color; - const XFontStruct *font; - int linewidth; - int function; - int subwindow; - - mutable BGCCache *cache; - mutable BGCCacheItem *item; -}; - - -#endif // GCCACHE_HH diff --git a/src/Image.cc b/src/Image.cc deleted file mode 100644 index 2094c003..00000000 --- a/src/Image.cc +++ /dev/null @@ -1,1703 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Image.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#include -using std::max; -using std::min; - -#include "blackbox.hh" -#include "i18n.hh" -#include "BaseDisplay.hh" -#include "GCCache.hh" -#include "Image.hh" -#include "Texture.hh" - - -BImage::BImage(BImageControl *c, int w, int h) { - control = c; - - width = (w > 0) ? w : 1; - height = (h > 0) ? h : 1; - - red = new unsigned char[width * height]; - green = new unsigned char[width * height]; - blue = new unsigned char[width * height]; - - xtable = ytable = (unsigned int *) 0; - - cpc = control->getColorsPerChannel(); - cpccpc = cpc * cpc; - - control->getColorTables(&red_table, &green_table, &blue_table, - &red_offset, &green_offset, &blue_offset, - &red_bits, &green_bits, &blue_bits); - - if (control->getVisual()->c_class != TrueColor) - control->getXColorTable(&colors, &ncolors); -} - - -BImage::~BImage(void) { - delete [] red; - delete [] green; - delete [] blue; -} - - -Pixmap BImage::render(const BTexture &texture) { - if (texture.texture() & BTexture::Parent_Relative) - return ParentRelative; - else if (texture.texture() & BTexture::Solid) - return render_solid(texture); - else if (texture.texture() & BTexture::Gradient) - return render_gradient(texture); - return None; -} - - -Pixmap BImage::render_solid(const BTexture &texture) { - Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(), - control->getDrawable(), width, - height, control->getDepth()); - if (pixmap == None) { - fprintf(stderr, i18n(ImageSet, ImageErrorCreatingSolidPixmap, - "BImage::render_solid: error creating pixmap\n")); - return None; - } - - Display *display = control->getBaseDisplay()->getXDisplay(); - - BPen pen(texture.color()); - BPen penlight(texture.lightColor()); - BPen penshadow(texture.shadowColor()); - - XFillRectangle(display, pixmap, pen.gc(), 0, 0, width, height); - - if (texture.texture() & BTexture::Interlaced) { - BPen peninterlace(texture.colorTo()); - for (unsigned int i = 0; i < height; i += 2) - XDrawLine(display, pixmap, peninterlace.gc(), 0, i, width, i); - } - - int left = 0, top = 0, right = width - 1, bottom = height - 1; - - if (texture.texture() & BTexture::Border) { - BPen penborder(texture.borderColor()); - XDrawRectangle(display, pixmap, penborder.gc(), - left, top, right, bottom); - } - - if (texture.texture() & BTexture::Bevel1) { - if (texture.texture() & BTexture::Raised) { - XDrawLine(display, pixmap, penshadow.gc(), - left, bottom, right, bottom); - XDrawLine(display, pixmap, penshadow.gc(), - right, bottom, right, top); - - XDrawLine(display, pixmap, penlight.gc(), - left, top, right, top); - XDrawLine(display, pixmap, penlight.gc(), - left, bottom, left, top); - } else if (texture.texture() & BTexture::Sunken) { - XDrawLine(display, pixmap, penlight.gc(), - left, bottom, right, bottom); - XDrawLine(display, pixmap, penlight.gc(), - right, bottom, right, top); - - XDrawLine(display, pixmap, penshadow.gc(), - left, top, right, top); - XDrawLine(display, pixmap, penshadow.gc(), - left, bottom, left, top); - } - } else if (texture.texture() & BTexture::Bevel2) { - if (texture.texture() & BTexture::Raised) { - XDrawLine(display, pixmap, penshadow.gc(), - left + 1, bottom - 2, right - 2, bottom - 2); - XDrawLine(display, pixmap, penshadow.gc(), - right - 2, bottom - 2, right - 2, top + 1); - - XDrawLine(display, pixmap, penlight.gc(), - left + 1, top + 1, right - 2, top + 1); - XDrawLine(display, pixmap, penlight.gc(), - left + 1, bottom - 2, left + 1, top + 1); - } else if (texture.texture() & BTexture::Sunken) { - XDrawLine(display, pixmap, penlight.gc(), - left + 1, bottom - 2, right - 2, bottom - 2); - XDrawLine(display, pixmap, penlight.gc(), - right - 2, bottom - 2, right - 2, top + 1); - - XDrawLine(display, pixmap, penshadow.gc(), - left + 1, top + 1, right - 2, top + 1); - XDrawLine(display, pixmap, penshadow.gc(), - left + 1, bottom - 2, left + 1, top + 1); - } - } - - return pixmap; -} - - -Pixmap BImage::render_gradient(const BTexture &texture) { - bool inverted = False; - - interlaced = texture.texture() & BTexture::Interlaced; - - if (texture.texture() & BTexture::Sunken) { - from = texture.colorTo(); - to = texture.color(); - - if (! (texture.texture() & BTexture::Invert)) inverted = True; - } else { - from = texture.color(); - to = texture.colorTo(); - - if (texture.texture() & BTexture::Invert) inverted = True; - } - - control->getGradientBuffers(width, height, &xtable, &ytable); - - if (texture.texture() & BTexture::Diagonal) dgradient(); - else if (texture.texture() & BTexture::Elliptic) egradient(); - else if (texture.texture() & BTexture::Horizontal) hgradient(); - else if (texture.texture() & BTexture::Pyramid) pgradient(); - else if (texture.texture() & BTexture::Rectangle) rgradient(); - else if (texture.texture() & BTexture::Vertical) vgradient(); - else if (texture.texture() & BTexture::CrossDiagonal) cdgradient(); - else if (texture.texture() & BTexture::PipeCross) pcgradient(); - - if (texture.texture() & BTexture::Bevel1) bevel1(); - else if (texture.texture() & BTexture::Bevel2) bevel2(); - - if (texture.texture() & BTexture::Border) border(texture); - - if (inverted) invert(); - - return renderPixmap(); - -} - - -static const unsigned char dither4[4][4] = { - {0, 4, 1, 5}, - {6, 2, 7, 3}, - {1, 5, 0, 4}, - {7, 3, 6, 2} -}; - - -/* - * Helper function for TrueColorDither and renderXImage - * - * This handles the proper setting of the image data based on the image depth - * and the machine's byte ordering - */ -static inline -void assignPixelData(unsigned int bit_depth, unsigned char **data, - unsigned long pixel) { - unsigned char *pixel_data = *data; - switch (bit_depth) { - case 8: // 8bpp - *pixel_data++ = pixel; - break; - - case 16: // 16bpp LSB - *pixel_data++ = pixel; - *pixel_data++ = pixel >> 8; - break; - - case 17: // 16bpp MSB - *pixel_data++ = pixel >> 8; - *pixel_data++ = pixel; - break; - - case 24: // 24bpp LSB - *pixel_data++ = pixel; - *pixel_data++ = pixel >> 8; - *pixel_data++ = pixel >> 16; - break; - - case 25: // 24bpp MSB - *pixel_data++ = pixel >> 16; - *pixel_data++ = pixel >> 8; - *pixel_data++ = pixel; - break; - - case 32: // 32bpp LSB - *pixel_data++ = pixel; - *pixel_data++ = pixel >> 8; - *pixel_data++ = pixel >> 16; - *pixel_data++ = pixel >> 24; - break; - - case 33: // 32bpp MSB - *pixel_data++ = pixel >> 24; - *pixel_data++ = pixel >> 16; - *pixel_data++ = pixel >> 8; - *pixel_data++ = pixel; - break; - } - *data = pixel_data; // assign back so we don't lose our place -} - - -// algorithm: ordered dithering... many many thanks to rasterman -// (raster@rasterman.com) for telling me about this... portions of this -// code is based off of his code in Imlib -void BImage::TrueColorDither(unsigned int bit_depth, int bytes_per_line, - unsigned char *pixel_data) { - unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset; - unsigned char *ppixel_data = pixel_data; - unsigned long pixel; - - for (y = 0, offset = 0; y < height; y++) { - dithy = y & 0x3; - - for (x = 0; x < width; x++, offset++) { - dithx = x & 0x3; - r = red[offset]; - g = green[offset]; - b = blue[offset]; - - er = r & (red_bits - 1); - eg = g & (green_bits - 1); - eb = b & (blue_bits - 1); - - r = red_table[r]; - g = green_table[g]; - b = blue_table[b]; - - if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++; - if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++; - if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++; - - pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); - assignPixelData(bit_depth, &pixel_data, pixel); - } - - pixel_data = (ppixel_data += bytes_per_line); - } -} - -#ifdef ORDEREDPSEUDO -const static unsigned char dither8[8][8] = { - { 0, 32, 8, 40, 2, 34, 10, 42}, - { 48, 16, 56, 24, 50, 18, 58, 26}, - { 12, 44, 4, 36, 14, 46, 6, 38}, - { 60, 28, 52, 20, 62, 30, 54, 22}, - { 3, 35, 11, 43, 1, 33, 9, 41}, - { 51, 19, 59, 27, 49, 17, 57, 25}, - { 15, 47, 7, 39, 13, 45, 5, 37}, - { 63, 31, 55, 23, 61, 29, 53, 21} -}; - -void BImage::OrderedPseudoColorDither(int bytes_per_line, - unsigned char *pixel_data) { - unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset; - unsigned long pixel; - unsigned char *ppixel_data = pixel_data; - - for (y = 0, offset = 0; y < height; y++) { - dithy = y & 7; - - for (x = 0; x < width; x++, offset++) { - dithx = x & 7; - - r = red[offset]; - g = green[offset]; - b = blue[offset]; - - er = r & (red_bits - 1); - eg = g & (green_bits - 1); - eb = b & (blue_bits - 1); - - r = red_table[r]; - g = green_table[g]; - b = blue_table[b]; - - if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++; - if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++; - if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++; - - pixel = (r * cpccpc) + (g * cpc) + b; - *(pixel_data++) = colors[pixel].pixel; - } - - pixel_data = (ppixel_data += bytes_per_line); - } -} -#endif - -void BImage::PseudoColorDither(int bytes_per_line, unsigned char *pixel_data) { - short *terr, - *rerr = new short[width + 2], - *gerr = new short[width + 2], - *berr = new short[width + 2], - *nrerr = new short[width + 2], - *ngerr = new short[width + 2], - *nberr = new short[width + 2]; - - int rr, gg, bb, rer, ger, ber; - int dd = 255 / control->getColorsPerChannel(); - unsigned int x, y, r, g, b, offset; - unsigned long pixel; - unsigned char *ppixel_data = pixel_data; - - for (x = 0; x < width; x++) { - *(rerr + x) = *(red + x); - *(gerr + x) = *(green + x); - *(berr + x) = *(blue + x); - } - - *(rerr + x) = *(gerr + x) = *(berr + x) = 0; - - for (y = 0, offset = 0; y < height; y++) { - if (y < (height - 1)) { - int i = offset + width; - for (x = 0; x < width; x++, i++) { - *(nrerr + x) = *(red + i); - *(ngerr + x) = *(green + i); - *(nberr + x) = *(blue + i); - } - - *(nrerr + x) = *(red + (--i)); - *(ngerr + x) = *(green + i); - *(nberr + x) = *(blue + i); - } - - for (x = 0; x < width; x++) { - rr = rerr[x]; - gg = gerr[x]; - bb = berr[x]; - - if (rr > 255) rr = 255; else if (rr < 0) rr = 0; - if (gg > 255) gg = 255; else if (gg < 0) gg = 0; - if (bb > 255) bb = 255; else if (bb < 0) bb = 0; - - r = red_table[rr]; - g = green_table[gg]; - b = blue_table[bb]; - - rer = rerr[x] - r*dd; - ger = gerr[x] - g*dd; - ber = berr[x] - b*dd; - - pixel = (r * cpccpc) + (g * cpc) + b; - *pixel_data++ = colors[pixel].pixel; - - r = rer >> 1; - g = ger >> 1; - b = ber >> 1; - rerr[x+1] += r; - gerr[x+1] += g; - berr[x+1] += b; - nrerr[x] += r; - ngerr[x] += g; - nberr[x] += b; - } - - offset += width; - - pixel_data = (ppixel_data += bytes_per_line); - - terr = rerr; - rerr = nrerr; - nrerr = terr; - - terr = gerr; - gerr = ngerr; - ngerr = terr; - - terr = berr; - berr = nberr; - nberr = terr; - } - - delete [] rerr; - delete [] gerr; - delete [] berr; - delete [] nrerr; - delete [] ngerr; - delete [] nberr; -} - -XImage *BImage::renderXImage(void) { - XImage *image = - XCreateImage(control->getBaseDisplay()->getXDisplay(), - control->getVisual(), control->getDepth(), ZPixmap, 0, 0, - width, height, 32, 0); - - if (! image) { - fprintf(stderr, i18n(ImageSet, ImageErrorCreatingXImage, - "BImage::renderXImage: error creating XImage\n")); - return (XImage *) 0; - } - - // insurance policy - image->data = (char *) 0; - - unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)]; - - unsigned int o = image->bits_per_pixel + - ((image->byte_order == MSBFirst) ? 1 : 0); - - bool unsupported = False; - - if (control->doDither() && width > 1 && height > 1) { - switch (control->getVisual()->c_class) { - case TrueColor: - TrueColorDither(o, image->bytes_per_line, d); - break; - - case StaticColor: - case PseudoColor: { -#ifdef ORDEREDPSEUDO - OrderedPseudoColorDither(image->bytes_per_line, d); -#else - PseudoColorDither(image->bytes_per_line, d); -#endif - break; - } - - default: - unsupported = True; - } - } else { - unsigned int x, y, r, g, b, offset; - unsigned char *pixel_data = d, *ppixel_data = d; - unsigned long pixel; - - switch (control->getVisual()->c_class) { - case StaticColor: - case PseudoColor: - for (y = 0, offset = 0; y < height; ++y) { - for (x = 0; x < width; ++x, ++offset) { - r = red_table[red[offset]]; - g = green_table[green[offset]]; - b = blue_table[blue[offset]]; - - pixel = (r * cpccpc) + (g * cpc) + b; - *pixel_data++ = colors[pixel].pixel; - } - - pixel_data = (ppixel_data += image->bytes_per_line); - } - - break; - - case TrueColor: - for (y = 0, offset = 0; y < height; y++) { - for (x = 0; x < width; x++, offset++) { - r = red_table[red[offset]]; - g = green_table[green[offset]]; - b = blue_table[blue[offset]]; - - pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); - assignPixelData(o, &pixel_data, pixel); - } - - pixel_data = (ppixel_data += image->bytes_per_line); - } - - break; - - case StaticGray: - case GrayScale: - for (y = 0, offset = 0; y < height; y++) { - for (x = 0; x < width; x++, offset++) { - r = *(red_table + *(red + offset)); - g = *(green_table + *(green + offset)); - b = *(blue_table + *(blue + offset)); - - g = ((r * 30) + (g * 59) + (b * 11)) / 100; - *pixel_data++ = colors[g].pixel; - } - - pixel_data = (ppixel_data += image->bytes_per_line); - } - - break; - - default: - unsupported = True; - } - } - - if (unsupported) { - fprintf(stderr, i18n(ImageSet, ImageUnsupVisual, - "BImage::renderXImage: unsupported visual\n")); - delete [] d; - XDestroyImage(image); - return (XImage *) 0; - } - - image->data = (char *) d; - - return image; -} - - -Pixmap BImage::renderPixmap(void) { - Pixmap pixmap = - XCreatePixmap(control->getBaseDisplay()->getXDisplay(), - control->getDrawable(), width, height, control->getDepth()); - - if (pixmap == None) { - fprintf(stderr, i18n(ImageSet, ImageErrorCreatingPixmap, - "BImage::renderPixmap: error creating pixmap\n")); - return None; - } - - XImage *image = renderXImage(); - - if (! image) { - XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); - return None; - } - - if (! image->data) { - XDestroyImage(image); - XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); - return None; - } - - XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap, - DefaultGC(control->getBaseDisplay()->getXDisplay(), - control->getScreenInfo()->getScreenNumber()), - image, 0, 0, 0, 0, width, height); - - if (image->data) { - delete [] image->data; - image->data = NULL; - } - - XDestroyImage(image); - - return pixmap; -} - - -void BImage::bevel1(void) { - if (width > 2 && height > 2) { - unsigned char *pr = red, *pg = green, *pb = blue; - - register unsigned char r, g, b, rr ,gg ,bb; - register unsigned int w = width, h = height - 1, wh = w * h; - - while (--w) { - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *pr = rr; - *pg = gg; - *pb = bb; - - r = *(pr + wh); - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *(pg + wh); - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *(pb + wh); - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *((pr++) + wh) = rr; - *((pg++) + wh) = gg; - *((pb++) + wh) = bb; - } - - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *pr = rr; - *pg = gg; - *pb = bb; - - r = *(pr + wh); - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *(pg + wh); - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *(pb + wh); - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *(pr + wh) = rr; - *(pg + wh) = gg; - *(pb + wh) = bb; - - pr = red + width; - pg = green + width; - pb = blue + width; - - while (--h) { - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *pr = rr; - *pg = gg; - *pb = bb; - - pr += width - 1; - pg += width - 1; - pb += width - 1; - - r = *pr; - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *pg; - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *pb; - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *(pr++) = rr; - *(pg++) = gg; - *(pb++) = bb; - } - - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *pr = rr; - *pg = gg; - *pb = bb; - - pr += width - 1; - pg += width - 1; - pb += width - 1; - - r = *pr; - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *pg; - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *pb; - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *pr = rr; - *pg = gg; - *pb = bb; - } -} - - -void BImage::bevel2(void) { - if (width > 4 && height > 4) { - unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1, - *pg = green + width + 1, *pb = blue + width + 1; - unsigned int w = width - 2, h = height - 1, wh = width * (height - 3); - - while (--w) { - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *pr = rr; - *pg = gg; - *pb = bb; - - r = *(pr + wh); - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *(pg + wh); - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *(pb + wh); - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *((pr++) + wh) = rr; - *((pg++) + wh) = gg; - *((pb++) + wh) = bb; - } - - pr = red + width; - pg = green + width; - pb = blue + width; - - while (--h) { - r = *pr; - rr = r + (r >> 1); - if (rr < r) rr = ~0; - g = *pg; - gg = g + (g >> 1); - if (gg < g) gg = ~0; - b = *pb; - bb = b + (b >> 1); - if (bb < b) bb = ~0; - - *(++pr) = rr; - *(++pg) = gg; - *(++pb) = bb; - - pr += width - 3; - pg += width - 3; - pb += width - 3; - - r = *pr; - rr = (r >> 2) + (r >> 1); - if (rr > r) rr = 0; - g = *pg; - gg = (g >> 2) + (g >> 1); - if (gg > g) gg = 0; - b = *pb; - bb = (b >> 2) + (b >> 1); - if (bb > b) bb = 0; - - *(pr++) = rr; - *(pg++) = gg; - *(pb++) = bb; - - pr++; pg++; pb++; - } - } -} - - -void BImage::border(const BTexture &texture) { - if (width < 2 || height < 2) return; - - register unsigned int i; - int r = texture.borderColor().red(), - g = texture.borderColor().green(), - b = texture.borderColor().blue(); - - unsigned char *pr, *pg, *pb; - - // top line - pr = red; - pg = green; - pb = blue; - for (i = 0; i < width; ++i) { - *pr++ = r; - *pg++ = g; - *pb++ = b; - } - - if (height > 2) { - // left and right lines (pr,pg,pb are already lined up) - for (i = 1; i < height - 1; ++i) { - *pr = r; - *pg = g; - *pb = b; - pr += width - 1; - pg += width - 1; - pb += width - 1; - *pr++ = r; - *pg++ = g; - *pb++ = b; - } - } - - // bottom line (pr,pg,pb are already lined up) - for (i = 0; i < width; ++i) { - *pr++ = r; - *pg++ = g; - *pb++ = b; - } -} - - -void BImage::invert(void) { - register unsigned int i, j, wh = (width * height) - 1; - unsigned char tmp; - - for (i = 0, j = wh; j > i; j--, i++) { - tmp = *(red + j); - *(red + j) = *(red + i); - *(red + i) = tmp; - - tmp = *(green + j); - *(green + j) = *(green + i); - *(green + i) = tmp; - - tmp = *(blue + j); - *(blue + j) = *(blue + i); - *(blue + i) = tmp; - } -} - - -void BImage::dgradient(void) { - // diagonal gradient code was written by Mike Cole - // modified for interlacing by Brad Hughes - - float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, - xr = (float) from.red(), - xg = (float) from.green(), - xb = (float) from.blue(); - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable; - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - // Create X table - drx /= w; - dgx /= w; - dbx /= w; - - for (x = 0; x < width; x++) { - *(xt++) = (unsigned char) (xr); - *(xt++) = (unsigned char) (xg); - *(xt++) = (unsigned char) (xb); - - xr += drx; - xg += dgx; - xb += dbx; - } - - // Create Y table - dry /= h; - dgy /= h; - dby /= h; - - for (y = 0; y < height; y++) { - *(yt++) = ((unsigned char) yr); - *(yt++) = ((unsigned char) yg); - *(yt++) = ((unsigned char) yb); - - yr += dry; - yg += dgy; - yb += dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal dgradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = *(xt++) + *(yt); - *(pg++) = *(xt++) + *(yt + 1); - *(pb++) = *(xt++) + *(yt + 2); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = *(xt++) + *(yt); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = *(xt++) + *(yt + 1); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = *(xt++) + *(yt + 2); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = *(xt++) + *(yt); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = *(xt++) + *(yt + 1); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = *(xt++) + *(yt + 2); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} - - -void BImage::hgradient(void) { - float drx, dgx, dbx, - xr = (float) from.red(), - xg = (float) from.green(), - xb = (float) from.blue(); - unsigned char *pr = red, *pg = green, *pb = blue; - - register unsigned int x, y; - - drx = (float) (to.red() - from.red()); - dgx = (float) (to.green() - from.green()); - dbx = (float) (to.blue() - from.blue()); - - drx /= width; - dgx /= width; - dbx /= width; - - if (interlaced && height > 2) { - // faked interlacing effect - unsigned char channel, channel2; - - for (x = 0; x < width; x++, pr++, pg++, pb++) { - channel = (unsigned char) xr; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *pr = channel2; - - channel = (unsigned char) xg; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *pg = channel2; - - channel = (unsigned char) xb; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *pb = channel2; - - - channel = (unsigned char) xr; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr + width) = channel2; - - channel = (unsigned char) xg; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg + width) = channel2; - - channel = (unsigned char) xb; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb + width) = channel2; - - xr += drx; - xg += dgx; - xb += dbx; - } - - pr += width; - pg += width; - pb += width; - - int offset; - - for (y = 2; y < height; y++, pr += width, pg += width, pb += width) { - if (y & 1) offset = width; else offset = 0; - - memcpy(pr, (red + offset), width); - memcpy(pg, (green + offset), width); - memcpy(pb, (blue + offset), width); - } - } else { - // normal hgradient - for (x = 0; x < width; x++) { - *(pr++) = (unsigned char) (xr); - *(pg++) = (unsigned char) (xg); - *(pb++) = (unsigned char) (xb); - - xr += drx; - xg += dgx; - xb += dbx; - } - - for (y = 1; y < height; y++, pr += width, pg += width, pb += width) { - memcpy(pr, red, width); - memcpy(pg, green, width); - memcpy(pb, blue, width); - } - } -} - - -void BImage::vgradient(void) { - float dry, dgy, dby, - yr = (float) from.red(), - yg = (float) from.green(), - yb = (float) from.blue(); - unsigned char *pr = red, *pg = green, *pb = blue; - - register unsigned int y; - - dry = (float) (to.red() - from.red()); - dgy = (float) (to.green() - from.green()); - dby = (float) (to.blue() - from.blue()); - - dry /= height; - dgy /= height; - dby /= height; - - if (interlaced) { - // faked interlacing effect - unsigned char channel, channel2; - - for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { - if (y & 1) { - channel = (unsigned char) yr; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - memset(pr, channel2, width); - - channel = (unsigned char) yg; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - memset(pg, channel2, width); - - channel = (unsigned char) yb; - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - memset(pb, channel2, width); - } else { - channel = (unsigned char) yr; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - memset(pr, channel2, width); - - channel = (unsigned char) yg; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - memset(pg, channel2, width); - - channel = (unsigned char) yb; - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - memset(pb, channel2, width); - } - - yr += dry; - yg += dgy; - yb += dby; - } - } else { - // normal vgradient - for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { - memset(pr, (unsigned char) yr, width); - memset(pg, (unsigned char) yg, width); - memset(pb, (unsigned char) yb, width); - - yr += dry; - yg += dgy; - yb += dby; - } - } -} - - -void BImage::pgradient(void) { - // pyramid gradient - based on original dgradient, written by - // Mosfet (mosfet@kde.org) - // adapted from kde sources for Blackbox by Brad Hughes - - float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, - xr, xg, xb; - int rsign, gsign, bsign; - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int tr = to.red(), tg = to.green(), tb = to.blue(), - *xt = xtable, *yt = ytable; - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - rsign = (drx < 0) ? -1 : 1; - gsign = (dgx < 0) ? -1 : 1; - bsign = (dbx < 0) ? -1 : 1; - - xr = yr = (drx / 2); - xg = yg = (dgx / 2); - xb = yb = (dbx / 2); - - // Create X table - drx /= width; - dgx /= width; - dbx /= width; - - for (x = 0; x < width; x++) { - *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); - *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); - *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); - - xr -= drx; - xg -= dgx; - xb -= dbx; - } - - // Create Y table - dry /= height; - dgy /= height; - dby /= height; - - for (y = 0; y < height; y++) { - *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); - *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); - *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); - - yr -= dry; - yg -= dgy; - yb -= dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal pgradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); - *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); - *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} - - -void BImage::rgradient(void) { - // rectangle gradient - based on original dgradient, written by - // Mosfet (mosfet@kde.org) - // adapted from kde sources for Blackbox by Brad Hughes - - float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; - int rsign, gsign, bsign; - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int tr = to.red(), tg = to.green(), tb = to.blue(), - *xt = xtable, *yt = ytable; - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - rsign = (drx < 0) ? -2 : 2; - gsign = (dgx < 0) ? -2 : 2; - bsign = (dbx < 0) ? -2 : 2; - - xr = yr = (drx / 2); - xg = yg = (dgx / 2); - xb = yb = (dbx / 2); - - // Create X table - drx /= width; - dgx /= width; - dbx /= width; - - for (x = 0; x < width; x++) { - *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); - *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); - *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); - - xr -= drx; - xg -= dgx; - xb -= dbx; - } - - // Create Y table - dry /= height; - dgy /= height; - dby /= height; - - for (y = 0; y < height; y++) { - *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); - *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); - *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); - - yr -= dry; - yg -= dgy; - yb -= dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal rgradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); - *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); - *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} - - -void BImage::egradient(void) { - // elliptic gradient - based on original dgradient, written by - // Mosfet (mosfet@kde.org) - // adapted from kde sources for Blackbox by Brad Hughes - - float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb; - int rsign, gsign, bsign; - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int *xt = xtable, *yt = ytable, - tr = (unsigned long) to.red(), - tg = (unsigned long) to.green(), - tb = (unsigned long) to.blue(); - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - rsign = (drx < 0) ? -1 : 1; - gsign = (dgx < 0) ? -1 : 1; - bsign = (dbx < 0) ? -1 : 1; - - xr = yr = (drx / 2); - xg = yg = (dgx / 2); - xb = yb = (dbx / 2); - - // Create X table - drx /= width; - dgx /= width; - dbx /= width; - - for (x = 0; x < width; x++) { - *(xt++) = (unsigned long) (xr * xr); - *(xt++) = (unsigned long) (xg * xg); - *(xt++) = (unsigned long) (xb * xb); - - xr -= drx; - xg -= dgx; - xb -= dbx; - } - - // Create Y table - dry /= height; - dgy /= height; - dby /= height; - - for (y = 0; y < height; y++) { - *(yt++) = (unsigned long) (yr * yr); - *(yt++) = (unsigned long) (yg * yg); - *(yt++) = (unsigned long) (yb * yb); - - yr -= dry; - yg -= dgy; - yb -= dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal egradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = (unsigned char) - (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); - *(pg++) = (unsigned char) - (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); - *(pb++) = (unsigned char) - (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = (unsigned char) - (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = (unsigned char) - (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = (unsigned char) - (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = (unsigned char) - (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = (unsigned char) - (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = (unsigned char) - (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} - - -void BImage::pcgradient(void) { - // pipe cross gradient - based on original dgradient, written by - // Mosfet (mosfet@kde.org) - // adapted from kde sources for Blackbox by Brad Hughes - - float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; - int rsign, gsign, bsign; - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int *xt = xtable, *yt = ytable, - tr = to.red(), - tg = to.green(), - tb = to.blue(); - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - rsign = (drx < 0) ? -2 : 2; - gsign = (dgx < 0) ? -2 : 2; - bsign = (dbx < 0) ? -2 : 2; - - xr = yr = (drx / 2); - xg = yg = (dgx / 2); - xb = yb = (dbx / 2); - - // Create X table - drx /= width; - dgx /= width; - dbx /= width; - - for (x = 0; x < width; x++) { - *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); - *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); - *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); - - xr -= drx; - xg -= dgx; - xb -= dbx; - } - - // Create Y table - dry /= height; - dgy /= height; - dby /= height; - - for (y = 0; y < height; y++) { - *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); - *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); - *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); - - yr -= dry; - yg -= dgy; - yb -= dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal pcgradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); - *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); - *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2)))); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} - - -void BImage::cdgradient(void) { - // cross diagonal gradient - based on original dgradient, written by - // Mosfet (mosfet@kde.org) - // adapted from kde sources for Blackbox by Brad Hughes - - float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, - xr = (float) from.red(), - xg = (float) from.green(), - xb = (float) from.blue(); - unsigned char *pr = red, *pg = green, *pb = blue; - unsigned int w = width * 2, h = height * 2, *xt, *yt; - - register unsigned int x, y; - - dry = drx = (float) (to.red() - from.red()); - dgy = dgx = (float) (to.green() - from.green()); - dby = dbx = (float) (to.blue() - from.blue()); - - // Create X table - drx /= w; - dgx /= w; - dbx /= w; - - for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) { - *(xt--) = (unsigned char) xb; - *(xt--) = (unsigned char) xg; - *(xt--) = (unsigned char) xr; - - xr += drx; - xg += dgx; - xb += dbx; - } - - // Create Y table - dry /= h; - dgy /= h; - dby /= h; - - for (yt = ytable, y = 0; y < height; y++) { - *(yt++) = (unsigned char) yr; - *(yt++) = (unsigned char) yg; - *(yt++) = (unsigned char) yb; - - yr += dry; - yg += dgy; - yb += dby; - } - - // Combine tables to create gradient - - if (! interlaced) { - // normal cdgradient - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - *(pr++) = *(xt++) + *(yt); - *(pg++) = *(xt++) + *(yt + 1); - *(pb++) = *(xt++) + *(yt + 2); - } - } - } else { - // faked interlacing effect - unsigned char channel, channel2; - - for (yt = ytable, y = 0; y < height; y++, yt += 3) { - for (xt = xtable, x = 0; x < width; x++) { - if (y & 1) { - channel = *(xt++) + *(yt); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pr++) = channel2; - - channel = *(xt++) + *(yt + 1); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pg++) = channel2; - - channel = *(xt++) + *(yt + 2); - channel2 = (channel >> 1) + (channel >> 2); - if (channel2 > channel) channel2 = 0; - *(pb++) = channel2; - } else { - channel = *(xt++) + *(yt); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pr++) = channel2; - - channel = *(xt++) + *(yt + 1); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pg++) = channel2; - - channel = *(xt++) + *(yt + 2); - channel2 = channel + (channel >> 3); - if (channel2 < channel) channel2 = ~0; - *(pb++) = channel2; - } - } - } - } -} diff --git a/src/Image.hh b/src/Image.hh deleted file mode 100644 index 94cb3c60..00000000 --- a/src/Image.hh +++ /dev/null @@ -1,168 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Image.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Image_hh -#define __Image_hh - -extern "C" { -#include -#include -} - -#include - -#include "Timer.hh" -#include "BaseDisplay.hh" -#include "Color.hh" - -class BImageControl; -class BTexture; - -class BImage { -private: - BImageControl *control; - bool interlaced; - XColor *colors; - - BColor from, to; - int red_offset, green_offset, blue_offset, red_bits, green_bits, blue_bits, - ncolors, cpc, cpccpc; - unsigned char *red, *green, *blue, *red_table, *green_table, *blue_table; - unsigned int width, height, *xtable, *ytable; - - void TrueColorDither(unsigned int bit_depth, int bytes_per_line, - unsigned char *pixel_data); - void PseudoColorDither(int bytes_per_line, unsigned char *pixel_data); -#ifdef ORDEREDPSEUDO - void OrderedPseudoColorDither(int bytes_per_line, unsigned char *pixel_data); -#endif - - Pixmap renderPixmap(void); - Pixmap render_solid(const BTexture &texture); - Pixmap render_gradient(const BTexture &texture); - - XImage *renderXImage(void); - - void invert(void); - void bevel1(void); - void bevel2(void); - void border(const BTexture &texture); - void dgradient(void); - void egradient(void); - void hgradient(void); - void pgradient(void); - void rgradient(void); - void vgradient(void); - void cdgradient(void); - void pcgradient(void); - - -public: - BImage(BImageControl *c, int w, int h); - ~BImage(void); - - Pixmap render(const BTexture &texture); -}; - - -class BImageControl : public TimeoutHandler { -public: - struct CachedImage { - Pixmap pixmap; - - unsigned int count, width, height; - unsigned long pixel1, pixel2, texture; - }; - - BImageControl(BaseDisplay *dpy, const ScreenInfo *scrn, - bool _dither= False, int _cpc = 4, - unsigned long cache_timeout = 300000l, - unsigned long cmax = 200l); - virtual ~BImageControl(void); - - inline BaseDisplay *getBaseDisplay(void) const { return basedisplay; } - - inline bool doDither(void) { return dither; } - - inline const ScreenInfo *getScreenInfo(void) { return screeninfo; } - - inline Window getDrawable(void) const { return window; } - - inline Visual *getVisual(void) { return screeninfo->getVisual(); } - - inline int getBitsPerPixel(void) const { return bits_per_pixel; } - inline int getDepth(void) const { return screen_depth; } - inline int getColorsPerChannel(void) const - { return colors_per_channel; } - - unsigned long getSqrt(unsigned int x); - - Pixmap renderImage(unsigned int width, unsigned int height, - const BTexture &texture); - - void installRootColormap(void); - void removeImage(Pixmap pixmap); - void getColorTables(unsigned char **rmt, unsigned char **gmt, - unsigned char **bmt, - int *roff, int *goff, int *boff, - int *rbit, int *gbit, int *bbit); - void getXColorTable(XColor **c, int *n); - void getGradientBuffers(unsigned int w, unsigned int h, - unsigned int **xbuf, unsigned int **ybuf); - void setDither(bool d) { dither = d; } - void setColorsPerChannel(int cpc); - - virtual void timeout(void); - -private: - bool dither; - BaseDisplay *basedisplay; - const ScreenInfo *screeninfo; -#ifdef TIMEDCACHE - BTimer *timer; -#endif // TIMEDCACHE - - Colormap colormap; - - Window window; - XColor *colors; - int colors_per_channel, ncolors, screen_number, screen_depth, - bits_per_pixel, red_offset, green_offset, blue_offset, - red_bits, green_bits, blue_bits; - unsigned char red_color_table[256], green_color_table[256], - blue_color_table[256]; - unsigned int *grad_xbuffer, *grad_ybuffer, grad_buffer_width, - grad_buffer_height; - unsigned long *sqrt_table, cache_max; - - typedef std::list CacheContainer; - CacheContainer cache; - - Pixmap searchCache(const unsigned int width, const unsigned int height, - const unsigned long texture, - const BColor &c1, const BColor &c2); -}; - - -#endif // __Image_hh - diff --git a/src/ImageControl.cc b/src/ImageControl.cc deleted file mode 100644 index c93a40f9..00000000 --- a/src/ImageControl.cc +++ /dev/null @@ -1,599 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// ImageControl.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#ifdef HAVE_CTYPE_H -# include -#endif // HAVE_CTYPE_H - -#include -} - -#include - -#include "blackbox.hh" -#include "i18n.hh" -#include "BaseDisplay.hh" -#include "Color.hh" -#include "Image.hh" -#include "Texture.hh" - -static unsigned long bsqrt(unsigned long x) { - if (x <= 0) return 0; - if (x == 1) return 1; - - unsigned long r = x >> 1; - unsigned long q; - - while (1) { - q = x / r; - if (q >= r) return r; - r = (r + q) >> 1; - } -} - -BImageControl *ctrl = 0; - -BImageControl::BImageControl(BaseDisplay *dpy, const ScreenInfo *scrn, - bool _dither, int _cpc, - unsigned long cache_timeout, - unsigned long cmax) { - if (! ctrl) ctrl = this; - - basedisplay = dpy; - screeninfo = scrn; - setDither(_dither); - setColorsPerChannel(_cpc); - - cache_max = cmax; -#ifdef TIMEDCACHE - if (cache_timeout) { - timer = new BTimer(basedisplay, this); - timer->setTimeout(cache_timeout); - timer->start(); - } else { - timer = (BTimer *) 0; - } -#endif // TIMEDCACHE - - colors = (XColor *) 0; - ncolors = 0; - - grad_xbuffer = grad_ybuffer = (unsigned int *) 0; - grad_buffer_width = grad_buffer_height = 0; - - sqrt_table = (unsigned long *) 0; - - screen_depth = screeninfo->getDepth(); - window = screeninfo->getRootWindow(); - screen_number = screeninfo->getScreenNumber(); - colormap = screeninfo->getColormap(); - - int count; - XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(), - &count); - if (pmv) { - bits_per_pixel = 0; - for (int i = 0; i < count; i++) - if (pmv[i].depth == screen_depth) { - bits_per_pixel = pmv[i].bits_per_pixel; - break; - } - - XFree(pmv); - } - - if (bits_per_pixel == 0) bits_per_pixel = screen_depth; - if (bits_per_pixel >= 24) setDither(False); - - red_offset = green_offset = blue_offset = 0; - - switch (getVisual()->c_class) { - case TrueColor: { - int i; - - // compute color tables - unsigned long red_mask = getVisual()->red_mask, - green_mask = getVisual()->green_mask, - blue_mask = getVisual()->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_bits = 255 / red_mask; - green_bits = 255 / green_mask; - blue_bits = 255 / blue_mask; - - for (i = 0; i < 256; i++) { - red_color_table[i] = i / red_bits; - green_color_table[i] = i / green_bits; - blue_color_table[i] = i / blue_bits; - } - break; - } - - case PseudoColor: - case StaticColor: { - ncolors = colors_per_channel * colors_per_channel * colors_per_channel; - - if (ncolors > (1 << screen_depth)) { - colors_per_channel = (1 << screen_depth) / 3; - ncolors = colors_per_channel * colors_per_channel * colors_per_channel; - } - - if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { - fprintf(stderr, - i18n(ImageSet, ImageInvalidColormapSize, - "BImageControl::BImageControl: invalid colormap size %d " - "(%d/%d/%d) - reducing"), - ncolors, colors_per_channel, colors_per_channel, - colors_per_channel); - - colors_per_channel = (1 << screen_depth) / 3; - } - - colors = new XColor[ncolors]; - if (! colors) { - fprintf(stderr, i18n(ImageSet, ImageErrorAllocatingColormap, - "BImageControl::BImageControl: error allocating " - "colormap\n")); - exit(1); - } - - int i = 0, ii, p, r, g, b, - -#ifdef ORDEREDPSEUDO - bits = 256 / colors_per_channel; -#else // !ORDEREDPSEUDO - bits = 255 / (colors_per_channel - 1); -#endif // ORDEREDPSEUDO - - red_bits = green_bits = blue_bits = bits; - - for (i = 0; i < 256; i++) - red_color_table[i] = green_color_table[i] = blue_color_table[i] = - i / bits; - - for (r = 0, i = 0; r < colors_per_channel; r++) - for (g = 0; g < colors_per_channel; g++) - for (b = 0; b < colors_per_channel; b++, i++) { - colors[i].red = (r * 0xffff) / (colors_per_channel - 1); - colors[i].green = (g * 0xffff) / (colors_per_channel - 1); - colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);; - colors[i].flags = DoRed|DoGreen|DoBlue; - } - - for (i = 0; i < ncolors; i++) { - if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { - fprintf(stderr, i18n(ImageSet, ImageColorAllocFail, - "couldn't alloc color %i %i %i\n"), - colors[i].red, colors[i].green, colors[i].blue); - colors[i].flags = 0; - } else { - colors[i].flags = DoRed|DoGreen|DoBlue; - } - } - - XColor icolors[256]; - int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth)); - - for (i = 0; i < incolors; i++) - icolors[i].pixel = i; - - XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); - for (i = 0; i < ncolors; i++) { - if (! colors[i].flags) { - unsigned long chk = 0xffffffff, pixel, close = 0; - - p = 2; - while (p--) { - for (ii = 0; ii < incolors; ii++) { - r = (colors[i].red - icolors[i].red) >> 8; - g = (colors[i].green - icolors[i].green) >> 8; - b = (colors[i].blue - icolors[i].blue) >> 8; - pixel = (r * r) + (g * g) + (b * b); - - if (pixel < chk) { - chk = pixel; - close = ii; - } - - colors[i].red = icolors[close].red; - colors[i].green = icolors[close].green; - colors[i].blue = icolors[close].blue; - - if (XAllocColor(basedisplay->getXDisplay(), colormap, - &colors[i])) { - colors[i].flags = DoRed|DoGreen|DoBlue; - break; - } - } - } - } - } - - break; - } - - case GrayScale: - case StaticGray: { - if (getVisual()->c_class == StaticGray) { - ncolors = 1 << screen_depth; - } else { - ncolors = colors_per_channel * colors_per_channel * colors_per_channel; - - if (ncolors > (1 << screen_depth)) { - colors_per_channel = (1 << screen_depth) / 3; - ncolors = - colors_per_channel * colors_per_channel * colors_per_channel; - } - } - - if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { - fprintf(stderr, - i18n(ImageSet, ImageInvalidColormapSize, - "BImageControl::BImageControl: invalid colormap size %d " - "(%d/%d/%d) - reducing"), - ncolors, colors_per_channel, colors_per_channel, - colors_per_channel); - - colors_per_channel = (1 << screen_depth) / 3; - } - - colors = new XColor[ncolors]; - if (! colors) { - fprintf(stderr, - i18n(ImageSet, ImageErrorAllocatingColormap, - "BImageControl::BImageControl: error allocating colormap\n")); - exit(1); - } - - int i = 0, ii, p, bits = 255 / (colors_per_channel - 1); - red_bits = green_bits = blue_bits = bits; - - for (i = 0; i < 256; i++) - red_color_table[i] = green_color_table[i] = blue_color_table[i] = - i / bits; - - for (i = 0; i < ncolors; i++) { - colors[i].red = (i * 0xffff) / (colors_per_channel - 1); - colors[i].green = (i * 0xffff) / (colors_per_channel - 1); - colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);; - colors[i].flags = DoRed|DoGreen|DoBlue; - - if (! XAllocColor(basedisplay->getXDisplay(), colormap, - &colors[i])) { - fprintf(stderr, i18n(ImageSet, ImageColorAllocFail, - "couldn't alloc color %i %i %i\n"), - colors[i].red, colors[i].green, colors[i].blue); - colors[i].flags = 0; - } else { - colors[i].flags = DoRed|DoGreen|DoBlue; - } - } - - XColor icolors[256]; - int incolors = (((1 << screen_depth) > 256) ? 256 : - (1 << screen_depth)); - - for (i = 0; i < incolors; i++) - icolors[i].pixel = i; - - XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); - for (i = 0; i < ncolors; i++) { - if (! colors[i].flags) { - unsigned long chk = 0xffffffff, pixel, close = 0; - - p = 2; - while (p--) { - for (ii = 0; ii < incolors; ii++) { - int r = (colors[i].red - icolors[i].red) >> 8; - int g = (colors[i].green - icolors[i].green) >> 8; - int b = (colors[i].blue - icolors[i].blue) >> 8; - pixel = (r * r) + (g * g) + (b * b); - - if (pixel < chk) { - chk = pixel; - close = ii; - } - - colors[i].red = icolors[close].red; - colors[i].green = icolors[close].green; - colors[i].blue = icolors[close].blue; - - if (XAllocColor(basedisplay->getXDisplay(), colormap, - &colors[i])) { - colors[i].flags = DoRed|DoGreen|DoBlue; - break; - } - } - } - } - } - - break; - } - - default: - fprintf(stderr, - i18n(ImageSet, ImageUnsupVisual, - "BImageControl::BImageControl: unsupported visual %d\n"), - getVisual()->c_class); - exit(1); - } -} - - -BImageControl::~BImageControl(void) { - delete [] sqrt_table; - - delete [] grad_xbuffer; - - delete [] grad_ybuffer; - - if (colors) { - unsigned long *pixels = new unsigned long [ncolors]; - - for (int i = 0; i < ncolors; i++) - *(pixels + i) = (*(colors + i)).pixel; - - XFreeColors(basedisplay->getXDisplay(), colormap, pixels, ncolors, 0); - - delete [] colors; - } - - if (! cache.empty()) { - //#ifdef DEBUG - fprintf(stderr, i18n(ImageSet, ImagePixmapRelease, - "BImageContol::~BImageControl: pixmap cache - " - "releasing %d pixmaps\n"), cache.size()); - //#endif - CacheContainer::iterator it = cache.begin(); - const CacheContainer::iterator end = cache.end(); - for (; it != end; ++it) - XFreePixmap(basedisplay->getXDisplay(), it->pixmap); - } -#ifdef TIMEDCACHE - if (timer) { - timer->stop(); - delete timer; - } -#endif // TIMEDCACHE -} - - -Pixmap BImageControl::searchCache(const unsigned int width, - const unsigned int height, - const unsigned long texture, - const BColor &c1, const BColor &c2) { - if (cache.empty()) - return None; - - CacheContainer::iterator it = cache.begin(); - const CacheContainer::iterator end = cache.end(); - for (; it != end; ++it) { - CachedImage& tmp = *it; - if (tmp.width == width && tmp.height == height && - tmp.texture == texture && tmp.pixel1 == c1.pixel()) - if (texture & BTexture::Gradient) { - if (tmp.pixel2 == c2.pixel()) { - tmp.count++; - return tmp.pixmap; - } - } else { - tmp.count++; - return tmp.pixmap; - } - } - return None; -} - - -Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, - const BTexture &texture) { - if (texture.texture() & BTexture::Parent_Relative) return ParentRelative; - - Pixmap pixmap = searchCache(width, height, texture.texture(), - texture.color(), texture.colorTo()); - if (pixmap) return pixmap; - - BImage image(this, width, height); - pixmap = image.render(texture); - - if (! pixmap) - return None; - - CachedImage tmp; - - tmp.pixmap = pixmap; - tmp.width = width; - tmp.height = height; - tmp.count = 1; - tmp.texture = texture.texture(); - tmp.pixel1 = texture.color().pixel(); - - if (texture.texture() & BTexture::Gradient) - tmp.pixel2 = texture.colorTo().pixel(); - else - tmp.pixel2 = 0l; - - cache.push_back(tmp); - - if (cache.size() > cache_max) { -#ifdef DEBUG - fprintf(stderr, i18n(ImageSet, ImagePixmapCacheLarge, - "BImageControl::renderImage: cache is large, " - "forcing cleanout\n")); -#endif // DEBUG - - timeout(); - } - - return pixmap; -} - - -void BImageControl::removeImage(Pixmap pixmap) { - if (! pixmap) - return; - - CacheContainer::iterator it = cache.begin(); - const CacheContainer::iterator end = cache.end(); - for (; it != end; ++it) { - CachedImage &tmp = *it; - if (tmp.pixmap == pixmap && tmp.count > 0) - tmp.count--; - } - -#ifdef TIMEDCACHE - if (! timer) -#endif // TIMEDCACHE - timeout(); -} - - -void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt, - unsigned char **bmt, - int *roff, int *goff, int *boff, - int *rbit, int *gbit, int *bbit) { - if (rmt) *rmt = red_color_table; - if (gmt) *gmt = green_color_table; - if (bmt) *bmt = blue_color_table; - - if (roff) *roff = red_offset; - if (goff) *goff = green_offset; - if (boff) *boff = blue_offset; - - if (rbit) *rbit = red_bits; - if (gbit) *gbit = green_bits; - if (bbit) *bbit = blue_bits; -} - - -void BImageControl::getXColorTable(XColor **c, int *n) { - if (c) *c = colors; - if (n) *n = ncolors; -} - - -void BImageControl::getGradientBuffers(unsigned int w, - unsigned int h, - unsigned int **xbuf, - unsigned int **ybuf) -{ - if (w > grad_buffer_width) { - if (grad_xbuffer) - delete [] grad_xbuffer; - - grad_buffer_width = w; - - grad_xbuffer = new unsigned int[grad_buffer_width * 3]; - } - - if (h > grad_buffer_height) { - if (grad_ybuffer) - delete [] grad_ybuffer; - - grad_buffer_height = h; - - grad_ybuffer = new unsigned int[grad_buffer_height * 3]; - } - - *xbuf = grad_xbuffer; - *ybuf = grad_ybuffer; -} - - -void BImageControl::installRootColormap(void) { - int ncmap = 0; - Colormap *cmaps = - XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap); - - if (cmaps) { - bool install = True; - for (int i = 0; i < ncmap; i++) - if (*(cmaps + i) == colormap) - install = False; - - if (install) - XInstallColormap(basedisplay->getXDisplay(), colormap); - - XFree(cmaps); - } -} - - -void BImageControl::setColorsPerChannel(int cpc) { - if (cpc < 2) cpc = 2; - if (cpc > 6) cpc = 6; - - colors_per_channel = cpc; -} - - -unsigned long BImageControl::getSqrt(unsigned int x) { - if (! sqrt_table) { - // build sqrt table for use with elliptic gradient - - sqrt_table = new unsigned long[(256 * 256 * 2) + 1]; - - for (int i = 0; i < (256 * 256 * 2); i++) - *(sqrt_table + i) = bsqrt(i); - } - - return (*(sqrt_table + x)); -} - - -struct ZeroRefCheck { - inline bool operator()(const BImageControl::CachedImage &image) const { - return (image.count == 0); - } -}; - -struct CacheCleaner { - Display *display; - ZeroRefCheck ref_check; - CacheCleaner(Display *d): display(d) {} - inline void operator()(const BImageControl::CachedImage& image) const { - if (ref_check(image)) - XFreePixmap(display, image.pixmap); - } -}; - - -void BImageControl::timeout(void) { - CacheCleaner cleaner(basedisplay->getXDisplay()); - std::for_each(cache.begin(), cache.end(), cleaner); - cache.remove_if(cleaner.ref_check); -} - diff --git a/src/Netizen.cc b/src/Netizen.cc deleted file mode 100644 index a50f5e0b..00000000 --- a/src/Netizen.cc +++ /dev/null @@ -1,117 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Netizen.cc for Blackbox - An X11 Window Manager -// Copyright (c) 2001 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif // HAVE_CONFIG_H - -#include "Netizen.hh" -#include "Screen.hh" -#include "XAtom.hh" - -Netizen::Netizen(BScreen *scr, Window win) { - screen = scr; - blackbox = scr->getBlackbox(); - xatom = blackbox->getXAtom(); - window = win; - - event.type = ClientMessage; - event.xclient.message_type = - xatom->getAtom(XAtom::blackbox_structure_messages); - event.xclient.display = blackbox->getXDisplay(); - event.xclient.window = window; - event.xclient.format = 32; - event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_startup); - event.xclient.data.l[1] = event.xclient.data.l[2] = - event.xclient.data.l[3] = event.xclient.data.l[4] = 0l; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendWorkspaceCount(void) { - event.xclient.data.l[0] = - xatom->getAtom(XAtom::blackbox_notify_workspace_count); - event.xclient.data.l[1] = screen->getWorkspaceCount(); - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendCurrentWorkspace(void) { - event.xclient.data.l[0] = - xatom->getAtom(XAtom::blackbox_notify_current_workspace); - event.xclient.data.l[1] = screen->getCurrentWorkspaceID(); - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendWindowFocus(Window w) { - event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_focus); - event.xclient.data.l[1] = w; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendWindowAdd(Window w, unsigned long p) { - event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_add); - event.xclient.data.l[1] = w; - event.xclient.data.l[2] = p; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); - - event.xclient.data.l[2] = 0l; -} - - -void Netizen::sendWindowDel(Window w) { - event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_del); - event.xclient.data.l[1] = w; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendWindowRaise(Window w) { - event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_raise); - event.xclient.data.l[1] = w; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendWindowLower(Window w) { - event.xclient.data.l[0] = - xatom->getAtom(XAtom::blackbox_notify_window_lower); - event.xclient.data.l[1] = w; - - XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event); -} - - -void Netizen::sendConfigNotify(XEvent *e) { - XSendEvent(blackbox->getXDisplay(), window, False, - StructureNotifyMask, e); -} diff --git a/src/Netizen.hh b/src/Netizen.hh deleted file mode 100644 index aebd20e1..00000000 --- a/src/Netizen.hh +++ /dev/null @@ -1,63 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Netizen.hh for Blackbox - An X11 Window Manager -// Copyright (c) 2001 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Netizen_hh -#define __Netizen_hh - -extern "C" { -#include -} - -// forward declaration -class Blackbox; -class BScreen; -class Netizen; -class XAtom; - -class Netizen { -private: - Blackbox *blackbox; - BScreen *screen; - XAtom *xatom; - Window window; - XEvent event; - -public: - Netizen(BScreen *, Window); - - inline Window getWindowID(void) const { return window; } - - void sendWorkspaceCount(void); - void sendCurrentWorkspace(void); - - void sendWindowFocus(Window); - void sendWindowAdd(Window, unsigned long); - void sendWindowDel(Window); - void sendWindowRaise(Window); - void sendWindowLower(Window); - - void sendConfigNotify(XEvent *); -}; - - -#endif // __Netizen_hh diff --git a/src/Screen.cc b/src/Screen.cc deleted file mode 100644 index eb933206..00000000 --- a/src/Screen.cc +++ /dev/null @@ -1,2780 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Screen.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -#include - -#ifdef XINERAMA -# include -# include -#endif // XINERAMA - -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H - -#ifdef HAVE_CTYPE_H -# include -#endif // HAVE_CTYPE_H - -#ifdef HAVE_UNISTD_H -# include -# include -#endif // HAVE_UNISTD_H - -#ifdef HAVE_DIRENT_H -# include -#endif // HAVE_DIRENT_H - -#ifdef HAVE_LOCALE_H -# include -#endif // HAVE_LOCALE_H - -#ifdef HAVE_SYS_STAT_H -# include -#endif // HAVE_SYS_STAT_H - -#ifdef HAVE_STDARG_H -# include -#endif // HAVE_STDARG_H -} - -#include - -#include -#include -#include -using std::string; - -#include "i18n.hh" -#include "blackbox.hh" -#include "Clientmenu.hh" -#include "Font.hh" -#include "GCCache.hh" -#include "Iconmenu.hh" -#include "Image.hh" -#include "Screen.hh" -#include "Slit.hh" -#include "Rootmenu.hh" -#include "Toolbar.hh" -#include "Util.hh" -#include "Window.hh" -#include "Workspace.hh" -#include "Workspacemenu.hh" -#include "Util.hh" -#include "XAtom.hh" - -#ifndef FONT_ELEMENT_SIZE -#define FONT_ELEMENT_SIZE 50 -#endif // FONT_ELEMENT_SIZE - - -static bool running = True; - -static int anotherWMRunning(Display *display, XErrorEvent *) { - fprintf(stderr, i18n(ScreenSet, ScreenAnotherWMRunning, - "BScreen::BScreen: an error occured while querying the X server.\n" - " another window manager already running on display %s.\n"), - DisplayString(display)); - - running = False; - - return(-1); -} - - -BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) { - blackbox = bb; - screenstr = "session.screen" + itostring(scrn) + '.'; - config = blackbox->getConfig(); - xatom = blackbox->getXAtom(); - - event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask | - SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask; - - XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning); - XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask); - XSync(getBaseDisplay()->getXDisplay(), False); - XSetErrorHandler((XErrorHandler) old); - - managed = running; - if (! managed) return; - - fprintf(stderr, i18n(ScreenSet, ScreenManagingScreen, - "BScreen::BScreen: managing screen %d " - "using visual 0x%lx, depth %d\n"), - getScreenNumber(), XVisualIDFromVisual(getVisual()), - getDepth()); - - rootmenu = 0; - - resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font = - resource.wstyle.font = (BFont *) 0; - - geom_pixmap = None; - - xatom->setSupported(this); // set-up netwm support -#ifdef HAVE_GETPID - xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal, - (unsigned long) getpid()); -#endif // HAVE_GETPID - unsigned long geometry[] = { getWidth(), - getHeight()}; - xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry, - XAtom::cardinal, geometry, 2); - unsigned long viewport[] = {0,0}; - xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport, - XAtom::cardinal, viewport, 2); - - - XDefineCursor(blackbox->getXDisplay(), getRootWindow(), - blackbox->getSessionCursor()); - - updateAvailableArea(); - - image_control = - new BImageControl(blackbox, this, True, blackbox->getColorsPerChannel(), - blackbox->getCacheLife(), blackbox->getCacheMax()); - image_control->installRootColormap(); - root_colormap_installed = True; - - load_rc(); - LoadStyle(); - - XGCValues gcv; - gcv.foreground = WhitePixel(blackbox->getXDisplay(), getScreenNumber()) - ^ BlackPixel(blackbox->getXDisplay(), getScreenNumber()); - gcv.function = GXxor; - gcv.subwindow_mode = IncludeInferiors; - opGC = XCreateGC(blackbox->getXDisplay(), getRootWindow(), - GCForeground | GCFunction | GCSubwindowMode, &gcv); - - const char *s = i18n(ScreenSet, ScreenPositionLength, - "0: 0000 x 0: 0000"); - geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2; - geom_h = resource.wstyle.font->height() + resource.bevel_width * 2; - - XSetWindowAttributes attrib; - unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder; - attrib.border_pixel = getBorderColor()->pixel(); - attrib.colormap = getColormap(); - attrib.save_under = True; - - geom_window = XCreateWindow(blackbox->getXDisplay(), getRootWindow(), - 0, 0, geom_w, geom_h, resource.border_width, - getDepth(), InputOutput, getVisual(), - mask, &attrib); - geom_visible = False; - - BTexture* texture = &(resource.wstyle.l_focus); - geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); - if (geom_pixmap == ParentRelative) { - texture = &(resource.wstyle.t_focus); - geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); - } - if (! geom_pixmap) - XSetWindowBackground(blackbox->getXDisplay(), geom_window, - texture->color().pixel()); - else - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - geom_window, geom_pixmap); - - workspacemenu = new Workspacemenu(this); - iconmenu = new Iconmenu(this); - configmenu = new Configmenu(this); - - if (resource.workspaces > 0) { - for (unsigned int i = 0; i < resource.workspaces; ++i) { - Workspace *wkspc = new Workspace(this, workspacesList.size()); - workspacesList.push_back(wkspc); - workspacemenu->insertWorkspace(wkspc); - workspacemenu->update(); - - } - } else { - Workspace *wkspc = new Workspace(this, workspacesList.size()); - workspacesList.push_back(wkspc); - workspacemenu->insertWorkspace(wkspc); - workspacemenu->update(); - } - saveWorkspaceNames(); - - updateNetizenWorkspaceCount(); - - workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu); - workspacemenu->update(); - - current_workspace = workspacesList.front(); - - xatom->setValue(getRootWindow(), XAtom::net_current_desktop, - XAtom::cardinal, 0); //first workspace - - workspacemenu->setItemSelected(2, True); - - toolbar = new Toolbar(this); - - slit = new Slit(this); - - InitMenu(); - - raiseWindows(0, 0); // this also initializes the empty stacking list - rootmenu->update(); - - updateClientList(); // initialize the client lists, which will be empty - updateAvailableArea(); - - changeWorkspaceID(0); - - unsigned int i, j, nchild; - Window r, p, *children; - XQueryTree(blackbox->getXDisplay(), getRootWindow(), &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(blackbox->getXDisplay(), - 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 || ! blackbox->validateWindow(children[i])) - continue; - - XWindowAttributes attrib; - if (XGetWindowAttributes(blackbox->getXDisplay(), children[i], &attrib)) { - if (attrib.override_redirect) continue; - - if (attrib.map_state != IsUnmapped) { - manageWindow(children[i]); - } - } - } - - XFree(children); - - // call this again just in case a window we found updates the Strut list - updateAvailableArea(); -} - - -BScreen::~BScreen(void) { - if (! managed) return; - - if (geom_pixmap != None) - image_control->removeImage(geom_pixmap); - - if (geom_window != None) - XDestroyWindow(blackbox->getXDisplay(), geom_window); - - std::for_each(workspacesList.begin(), workspacesList.end(), - PointerAssassin()); - - std::for_each(iconList.begin(), iconList.end(), PointerAssassin()); - - std::for_each(netizenList.begin(), netizenList.end(), PointerAssassin()); - - while (! systrayWindowList.empty()) - removeSystrayWindow(systrayWindowList[0]); - - delete rootmenu; - delete workspacemenu; - delete iconmenu; - delete configmenu; - delete slit; - delete toolbar; - delete image_control; - - if (resource.wstyle.font) - delete resource.wstyle.font; - if (resource.mstyle.t_font) - delete resource.mstyle.t_font; - if (resource.mstyle.f_font) - delete resource.mstyle.f_font; - if (resource.tstyle.font) - delete resource.tstyle.font; - -#ifdef BITMAPBUTTONS - if (resource.wstyle.close_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask); - if (resource.wstyle.max_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask); - if (resource.wstyle.icon_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask); - if (resource.wstyle.stick_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask); - - if (resource.tstyle.left_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask); - if (resource.tstyle.right_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask); - - if (resource.mstyle.bullet_image.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask); - if (resource.mstyle.tick_image.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask); - - resource.wstyle.max_button.mask = resource.wstyle.close_button.mask = - resource.wstyle.icon_button.mask = - resource.wstyle.stick_button.mask = None; - resource.tstyle.left_button.mask = resource.tstyle.right_button.mask = None; - resource.mstyle.bullet_image.mask = resource.mstyle.tick_image.mask = None; -#endif // BITMAPBUTTONS - - XFreeGC(blackbox->getXDisplay(), opGC); -} - - -void BScreen::saveSloppyFocus(bool s) { - resource.sloppy_focus = s; - - string fmodel; - if (resource.sloppy_focus) { - fmodel = "SloppyFocus"; - if (resource.auto_raise) fmodel += " AutoRaise"; - if (resource.click_raise) fmodel += " ClickRaise"; - } else { - fmodel = "ClickToFocus"; - } - config->setValue(screenstr + "focusModel", fmodel); -} - - -void BScreen::saveAutoRaise(bool a) { - resource.auto_raise = a; - saveSloppyFocus(resource.sloppy_focus); -} - - -void BScreen::saveClickRaise(bool c) { - resource.click_raise = c; - saveSloppyFocus(resource.sloppy_focus); -} - - -void BScreen::saveImageDither(bool d) { - image_control->setDither(d); - config->setValue(screenstr + "imageDither", doImageDither()); -} - - -void BScreen::saveOpaqueMove(bool o) { - resource.opaque_move = o; - config->setValue(screenstr + "opaqueMove", resource.opaque_move); -} - - -void BScreen::saveFullMax(bool f) { - resource.full_max = f; - config->setValue(screenstr + "fullMaximization", resource.full_max); -} - - -void BScreen::saveFocusNew(bool f) { - resource.focus_new = f; - config->setValue(screenstr + "focusNewWindows", resource.focus_new); -} - - -void BScreen::saveFocusLast(bool f) { - resource.focus_last = f; - config->setValue(screenstr + "focusLastWindow", resource.focus_last); -} - - -void BScreen::saveAAFonts(bool f) { - resource.aa_fonts = f; - config->setValue(screenstr + "antialiasFonts", resource.aa_fonts); - reconfigure(); -} - - -void BScreen::saveShadowFonts(bool f) { - resource.shadow_fonts = f; - config->setValue(screenstr + "dropShadowFonts", resource.shadow_fonts); - reconfigure(); -} - - -void BScreen::saveHideToolbar(bool h) { - resource.hide_toolbar = h; - if (resource.hide_toolbar) - toolbar->unmapToolbar(); - else - toolbar->mapToolbar(); - config->setValue(screenstr + "hideToolbar", resource.hide_toolbar); -} - - -void BScreen::saveWindowToEdgeSnap(int s) { - resource.snap_to_edges = s; - - const char *snap; - switch (resource.snap_to_edges) { - case WindowNoSnap: snap = "NoSnap"; break; - case WindowResistance: snap = "Resistance"; break; - case WindowSnap: default: snap = "Snap"; break; - } - config->setValue(screenstr + "windowToEdgeSnap", snap); -} - - -void BScreen::saveWindowToWindowSnap(int s) { - resource.snap_to_windows = s; - - const char *snap; - switch (resource.snap_to_windows) { - case WindowNoSnap: snap = "NoSnap"; break; - case WindowResistance: snap = "Resistance"; break; - case WindowSnap: default: snap = "Snap"; break; - } - config->setValue(screenstr + "windowToWindowSnap", snap); -} - - -void BScreen::saveResizeZones(unsigned int z) { - resource.resize_zones = z; - config->setValue(screenstr + "resizeZones", resource.resize_zones); -} - - -void BScreen::saveWindowCornerSnap(bool s) { - resource.window_corner_snap = s; - config->setValue(screenstr + "windowCornerSnap", - resource.window_corner_snap); -} - - -void BScreen::saveWorkspaces(unsigned int w) { - resource.workspaces = w; - config->setValue(screenstr + "workspaces", resource.workspaces); -} - - -void BScreen::savePlacementPolicy(int p) { - resource.placement_policy = p; - const char *placement; - switch (resource.placement_policy) { - case CascadePlacement: placement = "CascadePlacement"; break; - case UnderMousePlacement: placement = "UnderMousePlacement"; break; - case ClickMousePlacement: placement = "ClickMousePlacement"; break; - case ColSmartPlacement: placement = "ColSmartPlacement"; break; - case RowSmartPlacement: default: placement = "RowSmartPlacement"; break; - } - config->setValue(screenstr + "windowPlacement", placement); -} - - -void BScreen::saveResistanceSize(int s) { - resource.resistance_size = s; - config->setValue(screenstr + "resistanceSize", - resource.resistance_size); -} - - -void BScreen::saveSnapThreshold(int t) { - resource.snap_threshold = t; - config->setValue(screenstr + "edgeSnapThreshold", - resource.snap_threshold); -} - - -void BScreen::saveSnapOffset(int t) { - resource.snap_offset = t; - config->setValue(screenstr + "edgeSnapOffset", - resource.snap_offset); -} - - -void BScreen::saveRowPlacementDirection(int d) { - resource.row_direction = d; - config->setValue(screenstr + "rowPlacementDirection", - resource.row_direction == LeftRight ? - "LeftToRight" : "RightToLeft"); -} - - -void BScreen::saveColPlacementDirection(int d) { - resource.col_direction = d; - config->setValue(screenstr + "colPlacementDirection", - resource.col_direction == TopBottom ? - "TopToBottom" : "BottomToTop"); -} - - -#ifdef HAVE_STRFTIME -void BScreen::saveStrftimeFormat(const std::string& format) { - resource.strftime_format = format; - config->setValue(screenstr + "strftimeFormat", resource.strftime_format); -} - -#else // !HAVE_STRFTIME - -void BScreen::saveDateFormat(int f) { - resource.date_format = f; - config->setValue(screenstr + "dateFormat", - resource.date_format == B_EuropeanDate ? - "European" : "American"); -} - - -void BScreen::saveClock24Hour(bool c) { - resource.clock24hour = c; - config->setValue(screenstr + "clockFormat", resource.clock24hour ? 24 : 12); -} -#endif // HAVE_STRFTIME - - -void BScreen::saveWorkspaceNames() { - string names; - - for (unsigned int i = 0; i < workspacesList.size(); ++i) { - names += workspacesList[i]->getName(); - if (i < workspacesList.size() - 1) - names += ','; - } - - config->setValue(screenstr + "workspaceNames", names); -} - - -void BScreen::savePlaceIgnoreShaded(bool i) { - resource.ignore_shaded = i; - config->setValue(screenstr + "placementIgnoreShaded", - resource.ignore_shaded); -} - - -void BScreen::savePlaceIgnoreMaximized(bool i) { - resource.ignore_maximized = i; - config->setValue(screenstr + "placementIgnoreMaximized", - resource.ignore_maximized); -} - - -void BScreen::saveAllowScrollLock(bool a) { - resource.allow_scroll_lock = a; - config->setValue(screenstr + "disableBindingsWithScrollLock", - resource.allow_scroll_lock); -} - - -void BScreen::saveWorkspaceWarping(bool w) { - resource.workspace_warping = w; - config->setValue(screenstr + "workspaceWarping", - resource.workspace_warping); -} - - -void BScreen::saveRootScrollDirection(int d) { - resource.root_scroll = d; - const char *dir; - switch (resource.root_scroll) { - case NoScroll: dir = "None"; break; - case ReverseScroll: dir = "Reverse"; break; - case NormalScroll: default: dir = "Normal"; break; - } - config->setValue(screenstr + "rootScrollDirection", dir); -} - - -void BScreen::saveRootMenuButton(unsigned int b) { - resource.root_menu_button = b; - const char *but; - switch (resource.root_menu_button) { - case 0: but = "None"; break; - case 1: but = "Left"; break; - case 2: but = "Middle"; break; - case 3: default: but = "Right"; break; - } - config->setValue(screenstr + "rootMenuButton", but); -} - - -void BScreen::saveWorkspaceMenuButton(unsigned int b) { - resource.workspace_menu_button = b; - const char *but; - switch (resource.workspace_menu_button) { - case 0: but = "None"; break; - case 1: but = "Left"; break; - case 2: default: but = "Middle"; break; - case 3: but = "Right"; break; - } - config->setValue(screenstr + "workspaceMenuButton", but); -} - - -void BScreen::save_rc(void) { - saveSloppyFocus(resource.sloppy_focus); - saveAutoRaise(resource.auto_raise); - saveImageDither(doImageDither()); - saveShadowFonts(resource.shadow_fonts); - saveAAFonts(resource.aa_fonts); - saveResizeZones(resource.resize_zones); - saveOpaqueMove(resource.opaque_move); - saveFullMax(resource.full_max); - saveFocusNew(resource.focus_new); - saveFocusLast(resource.focus_last); - saveHideToolbar(resource.hide_toolbar); - saveWindowToWindowSnap(resource.snap_to_windows); - saveWindowToEdgeSnap(resource.snap_to_edges); - saveWindowCornerSnap(resource.window_corner_snap); - saveWorkspaces(resource.workspaces); - savePlacementPolicy(resource.placement_policy); - saveSnapThreshold(resource.snap_threshold); - saveSnapOffset(resource.snap_offset); - saveResistanceSize(resource.resistance_size); - saveRowPlacementDirection(resource.row_direction); - saveColPlacementDirection(resource.col_direction); -#ifdef HAVE_STRFTIME - saveStrftimeFormat(resource.strftime_format); -#else // !HAVE_STRFTIME - saveDateFormat(resource.date_format); - savwClock24Hour(resource.clock24hour); -#endif // HAVE_STRFTIME - savePlaceIgnoreShaded(resource.ignore_shaded); - savePlaceIgnoreMaximized(resource.ignore_maximized); - saveAllowScrollLock(resource.allow_scroll_lock); - saveWorkspaceWarping(resource.workspace_warping); - saveRootScrollDirection(resource.root_scroll); - saveRootMenuButton(resource.root_menu_button); - saveWorkspaceMenuButton(resource.workspace_menu_button); - - toolbar->save_rc(); - slit->save_rc(); -} - - -void BScreen::load_rc(void) { - std::string s; - bool b; - - if (! config->getValue(screenstr + "fullMaximization", resource.full_max)) - resource.full_max = false; - - if (! config->getValue(screenstr + "focusNewWindows", resource.focus_new)) - resource.focus_new = false; - - if (! config->getValue(screenstr + "focusLastWindow", resource.focus_last)) - resource.focus_last = false; - - if (! config->getValue(screenstr + "workspaces", resource.workspaces)) - resource.workspaces = 1; - - if (! config->getValue(screenstr + "opaqueMove", resource.opaque_move)) - resource.opaque_move = false; - - if (! config->getValue(screenstr + "antialiasFonts", resource.aa_fonts)) - resource.aa_fonts = true; - - if (! resource.aa_fonts || - ! config->getValue(screenstr + "dropShadowFonts", resource.shadow_fonts)) - resource.shadow_fonts = false; - - if (! config->getValue(screenstr + "resizeZones", resource.resize_zones) || - (resource.resize_zones != 1 && resource.resize_zones != 2 && - resource.resize_zones != 4)) - resource.resize_zones = 4; - - if (! config->getValue(screenstr + "hideToolbar", resource.hide_toolbar)) - resource.hide_toolbar = false; - - resource.snap_to_windows = WindowResistance; - if (config->getValue(screenstr + "windowToWindowSnap", s)) { - if (s == "NoSnap") - resource.snap_to_windows = WindowNoSnap; - else if (s == "Snap") - resource.snap_to_windows = WindowSnap; - } - - resource.snap_to_edges = WindowResistance; - if (config->getValue(screenstr + "windowToEdgeSnap", s)) { - if (s == "NoSnap") - resource.snap_to_edges = WindowNoSnap; - else if (s == "Snap") - resource.snap_to_edges = WindowSnap; - } - - if (! config->getValue(screenstr + "windowCornerSnap", - resource.window_corner_snap)) - resource.window_corner_snap = true; - - if (! config->getValue(screenstr + "imageDither", b)) - b = true; - image_control->setDither(b); - - if (! config->getValue(screenstr + "edgeSnapOffset", - resource.snap_offset)) - resource.snap_offset = 0; - if (resource.snap_offset > 50) // sanity check, setting this huge would - resource.snap_offset = 50; // seriously suck. - - if (! config->getValue(screenstr + "edgeSnapThreshold", - resource.snap_threshold)) - resource.snap_threshold = 4; - - if (! config->getValue(screenstr + "resistanceSize", - resource.resistance_size)) - resource.resistance_size = 18; - - if (config->getValue(screenstr + "rowPlacementDirection", s) && - s == "RightToLeft") - resource.row_direction = RightLeft; - else - resource.row_direction = LeftRight; - - if (config->getValue(screenstr + "colPlacementDirection", s) && - s == "BottomToTop") - resource.col_direction = BottomTop; - else - resource.col_direction = TopBottom; - - if (config->getValue(screenstr + "workspaceNames", s)) { - XAtom::StringVect workspaceNames; - - string::const_iterator it = s.begin(), end = s.end(); - while(1) { - string::const_iterator tmp = it; // current string.begin() - it = std::find(tmp, end, ','); // look for comma between tmp and end - workspaceNames.push_back(string(tmp, it)); // s[tmp:it] - if (it == end) - break; - ++it; - } - - xatom->setValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8, - workspaceNames); - } - - resource.sloppy_focus = true; - resource.auto_raise = false; - resource.click_raise = false; - if (config->getValue(screenstr + "focusModel", s)) { - if (s.find("ClickToFocus") != string::npos) { - resource.sloppy_focus = false; - } else { - // must be sloppy - if (s.find("AutoRaise") != string::npos) - resource.auto_raise = true; - if (s.find("ClickRaise") != string::npos) - resource.click_raise = true; - } - } - - if (config->getValue(screenstr + "windowPlacement", s)) { - if (s == "CascadePlacement") - resource.placement_policy = CascadePlacement; - else if (s == "UnderMousePlacement") - resource.placement_policy = UnderMousePlacement; - else if (s == "ClickMousePlacement") - resource.placement_policy = ClickMousePlacement; - else if (s == "ColSmartPlacement") - resource.placement_policy = ColSmartPlacement; - else //if (s == "RowSmartPlacement") - resource.placement_policy = RowSmartPlacement; - } else - resource.placement_policy = RowSmartPlacement; - -#ifdef HAVE_STRFTIME - if (! config->getValue(screenstr + "strftimeFormat", - resource.strftime_format)) - resource.strftime_format = "%I:%M %p"; -#else // !HAVE_STRFTIME - long l; - - if (config->getValue(screenstr + "dateFormat", s) && s == "European") - resource.date_format = B_EuropeanDate; - else - resource.date_format = B_AmericanDate; - - if (! config->getValue(screenstr + "clockFormat", l)) - l = 12; - resource.clock24hour = l == 24; -#endif // HAVE_STRFTIME - - if (! config->getValue(screenstr + "placementIgnoreShaded", - resource.ignore_shaded)) - resource.ignore_shaded = true; - - if (! config->getValue(screenstr + "placementIgnoreMaximized", - resource.ignore_maximized)) - resource.ignore_maximized = true; - - if (! config->getValue(screenstr + "disableBindingsWithScrollLock", - resource.allow_scroll_lock)) - resource.allow_scroll_lock = false; - - if (! config->getValue(screenstr + "workspaceWarping", - resource.workspace_warping)) - resource.workspace_warping = false; - - resource.root_scroll = NormalScroll; - if (config->getValue(screenstr + "rootScrollDirection", s)) { - if (s == "None") - resource.root_scroll = NoScroll; - else if (s == "Reverse") - resource.root_scroll = ReverseScroll; - } - - resource.root_menu_button = 3; - if (config->getValue(screenstr + "rootMenuButton", s)) { - if (s == "None") - resource.root_menu_button = 0; - else if (s == "Left") - resource.root_menu_button = 1; - else if (s == "Middle") - resource.root_menu_button = 2; - } - - resource.workspace_menu_button = 2; - if (config->getValue(screenstr + "workspaceMenuButton", s)) { - if (s == "None") - resource.workspace_menu_button = 0; - else if (s == "Left") - resource.workspace_menu_button = 1; - else if (s == "Right") - resource.workspace_menu_button = 3; - } - // cant both be the same - if (resource.workspace_menu_button == resource.root_menu_button) - resource.workspace_menu_button = 0; -} - - -void BScreen::changeWorkspaceCount(unsigned int new_count) { - assert(new_count > 0); - - if (new_count < workspacesList.size()) { - // shrink - for (unsigned int i = workspacesList.size(); i > new_count; --i) - removeLastWorkspace(); - // removeLast already sets the current workspace to the - // last available one. - } else if (new_count > workspacesList.size()) { - // grow - for(unsigned int i = workspacesList.size(); i < new_count; ++i) - addWorkspace(); - } -} - - -void BScreen::reconfigure(void) { - // don't reconfigure while saving the initial rc file, it's a waste and it - // breaks somethings (workspace names) - if (blackbox->isStartup()) return; - - load_rc(); - toolbar->load_rc(); - slit->load_rc(); - LoadStyle(); - - // we need to do this explicitly, because just loading this value from the rc - // does nothing - changeWorkspaceCount(resource.workspaces); - - XGCValues gcv; - gcv.foreground = WhitePixel(blackbox->getXDisplay(), - getScreenNumber()); - gcv.function = GXinvert; - gcv.subwindow_mode = IncludeInferiors; - XChangeGC(blackbox->getXDisplay(), opGC, - GCForeground | GCFunction | GCSubwindowMode, &gcv); - - const char *s = i18n(ScreenSet, ScreenPositionLength, - "0: 0000 x 0: 0000"); - - geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2; - geom_h = resource.wstyle.font->height() + resource.bevel_width * 2; - - BTexture* texture = &(resource.wstyle.l_focus); - geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); - if (geom_pixmap == ParentRelative) { - texture = &(resource.wstyle.t_focus); - geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); - } - if (! geom_pixmap) - XSetWindowBackground(blackbox->getXDisplay(), geom_window, - texture->color().pixel()); - else - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - geom_window, geom_pixmap); - - XSetWindowBorderWidth(blackbox->getXDisplay(), geom_window, - resource.border_width); - XSetWindowBorder(blackbox->getXDisplay(), geom_window, - resource.border_color.pixel()); - - workspacemenu->reconfigure(); - iconmenu->reconfigure(); - - typedef std::vector SubList; - SubList remember_subs; - - // save the current open menus - Basemenu *menu = rootmenu; - int submenu; - while ((submenu = menu->getCurrentSubmenu()) >= 0) { - remember_subs.push_back(submenu); - menu = menu->find(submenu)->submenu(); - assert(menu); - } - - InitMenu(); - raiseWindows(0, 0); - rootmenu->reconfigure(); - - // reopen the saved menus - menu = rootmenu; - const SubList::iterator subs_end = remember_subs.end(); - for (SubList::iterator it = remember_subs.begin(); it != subs_end; ++it) { - menu->drawSubmenu(*it); - menu = menu->find(*it)->submenu(); - if (! menu) - break; - } - - configmenu->reconfigure(); - - toolbar->reconfigure(); - - slit->reconfigure(); - - std::for_each(workspacesList.begin(), workspacesList.end(), - std::mem_fun(&Workspace::reconfigure)); - - BlackboxWindowList::iterator iit = iconList.begin(); - for (; iit != iconList.end(); ++iit) { - BlackboxWindow *bw = *iit; - if (bw->validateClient()) - bw->reconfigure(); - } - - image_control->timeout(); -} - - -void BScreen::rereadMenu(void) { - InitMenu(); - raiseWindows(0, 0); - - rootmenu->reconfigure(); -} - - -void BScreen::LoadStyle(void) { - Configuration style(False); - - const char *sfile = blackbox->getStyleFilename(); - if (sfile != NULL) { - style.setFile(sfile); - if (! style.load()) { - style.setFile(DEFAULTSTYLE); - if (! style.load()) - style.create(); // hardcoded default values will be used. - } - } - - // merge in the rc file - style.merge(config->file(), True); - - string s; - - // load fonts/fontsets - if (resource.wstyle.font) - delete resource.wstyle.font; - if (resource.tstyle.font) - delete resource.tstyle.font; - if (resource.mstyle.f_font) - delete resource.mstyle.f_font; - if (resource.mstyle.t_font) - delete resource.mstyle.t_font; - resource.wstyle.font = resource.tstyle.font = resource.mstyle.f_font = - resource.mstyle.t_font = (BFont *) 0; - - resource.wstyle.font = readDatabaseFont("window.", style); - resource.tstyle.font = readDatabaseFont("toolbar.", style); - resource.mstyle.t_font = readDatabaseFont("menu.title.", style); - resource.mstyle.f_font = readDatabaseFont("menu.frame.", style); - - // load window config - resource.wstyle.t_focus = - readDatabaseTexture("window.title.focus", "white", style); - resource.wstyle.t_unfocus = - readDatabaseTexture("window.title.unfocus", "black", style); - resource.wstyle.l_focus = - readDatabaseTexture("window.label.focus", "white", style); - resource.wstyle.l_unfocus = - readDatabaseTexture("window.label.unfocus", "black", style); - resource.wstyle.h_focus = - readDatabaseTexture("window.handle.focus", "white", style); - resource.wstyle.h_unfocus = - readDatabaseTexture("window.handle.unfocus", "black", style); - resource.wstyle.g_focus = - readDatabaseTexture("window.grip.focus", "white", style); - resource.wstyle.g_unfocus = - readDatabaseTexture("window.grip.unfocus", "black", style); - resource.wstyle.b_focus = - readDatabaseTexture("window.button.focus", "white", style); - resource.wstyle.b_unfocus = - readDatabaseTexture("window.button.unfocus", "black", style); - resource.wstyle.b_pressed = - readDatabaseTexture("window.button.pressed", "black", style); - - //if neither of these can be found, we will use the previous resource - resource.wstyle.b_pressed_focus = - readDatabaseTexture("window.button.pressed.focus", "black", style, true); - resource.wstyle.b_pressed_unfocus = - readDatabaseTexture("window.button.pressed.unfocus", "black", style, true); - -#ifdef BITMAPBUTTONS - if (resource.wstyle.close_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask); - if (resource.wstyle.max_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask); - if (resource.wstyle.icon_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask); - if (resource.wstyle.stick_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask); - - resource.wstyle.close_button.mask = resource.wstyle.max_button.mask = - resource.wstyle.icon_button.mask = - resource.wstyle.icon_button.mask = None; - - readDatabaseMask("window.button.close.mask", resource.wstyle.close_button, - style); - readDatabaseMask("window.button.max.mask", resource.wstyle.max_button, - style); - readDatabaseMask("window.button.icon.mask", resource.wstyle.icon_button, - style); - readDatabaseMask("window.button.stick.mask", resource.wstyle.stick_button, - style); -#endif // BITMAPBUTTONS - - // we create the window.frame texture by hand because it exists only to - // make the code cleaner and is not actually used for display - BColor color = readDatabaseColor("window.frame.focusColor", "white", style); - resource.wstyle.f_focus = BTexture("solid flat", getBaseDisplay(), - getScreenNumber(), image_control); - resource.wstyle.f_focus.setColor(color); - - color = readDatabaseColor("window.frame.unfocusColor", "white", style); - resource.wstyle.f_unfocus = BTexture("solid flat", getBaseDisplay(), - getScreenNumber(), image_control); - resource.wstyle.f_unfocus.setColor(color); - - resource.wstyle.l_text_focus = - readDatabaseColor("window.label.focus.textColor", "black", style); - resource.wstyle.l_text_unfocus = - readDatabaseColor("window.label.unfocus.textColor", "white", style); - resource.wstyle.b_pic_focus = - readDatabaseColor("window.button.focus.picColor", "black", style); - resource.wstyle.b_pic_unfocus = - readDatabaseColor("window.button.unfocus.picColor", "white", style); - - resource.wstyle.justify = LeftJustify; - if (style.getValue("window.justify", s)) { - if (s == "right" || s == "Right") - resource.wstyle.justify = RightJustify; - else if (s == "center" || s == "Center") - resource.wstyle.justify = CenterJustify; - } - - // sanity checks - if (resource.wstyle.t_focus.texture() == BTexture::Parent_Relative) - resource.wstyle.t_focus = resource.wstyle.f_focus; - if (resource.wstyle.t_unfocus.texture() == BTexture::Parent_Relative) - resource.wstyle.t_unfocus = resource.wstyle.f_unfocus; - if (resource.wstyle.h_focus.texture() == BTexture::Parent_Relative) - resource.wstyle.h_focus = resource.wstyle.f_focus; - if (resource.wstyle.h_unfocus.texture() == BTexture::Parent_Relative) - resource.wstyle.h_unfocus = resource.wstyle.f_unfocus; - - // load toolbar config -#ifdef BITMAPBUTTONS - if (resource.tstyle.left_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask); - if (resource.tstyle.right_button.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask); -#endif // BITMAPBUTTONS - - resource.tstyle.toolbar = - readDatabaseTexture("toolbar", "black", style); - resource.tstyle.label = - readDatabaseTexture("toolbar.label", "black", style); - resource.tstyle.window = - readDatabaseTexture("toolbar.windowLabel", "black", style); - resource.tstyle.button = - readDatabaseTexture("toolbar.button", "white", style); - resource.tstyle.pressed = - readDatabaseTexture("toolbar.button.pressed", "black", style); - resource.tstyle.clock = - readDatabaseTexture("toolbar.clock", "black", style); - resource.tstyle.l_text = - readDatabaseColor("toolbar.label.textColor", "white", style); - resource.tstyle.w_text = - readDatabaseColor("toolbar.windowLabel.textColor", "white", style); - resource.tstyle.c_text = - readDatabaseColor("toolbar.clock.textColor", "white", style); - resource.tstyle.b_pic = - readDatabaseColor("toolbar.button.picColor", "black", style); - -#ifdef BITMAPBUTTONS - readDatabaseMask("toolbar.button.left.mask", resource.tstyle.left_button, - style); - readDatabaseMask("toolbar.button.right.mask", resource.tstyle.right_button, - style); -#endif // BITMAPBUTTONS - - resource.tstyle.justify = LeftJustify; - if (style.getValue("toolbar.justify", s)) { - if (s == "right" || s == "Right") - resource.tstyle.justify = RightJustify; - else if (s == "center" || s == "Center") - resource.tstyle.justify = CenterJustify; - } - - // sanity checks - if (resource.tstyle.toolbar.texture() == BTexture::Parent_Relative) { - resource.tstyle.toolbar = BTexture("solid flat", getBaseDisplay(), - getScreenNumber(), image_control); - resource.tstyle.toolbar.setColor(BColor("black", getBaseDisplay(), - getScreenNumber())); - } - - // load menu config -#ifdef BITMAPBUTTONS - if (resource.mstyle.bullet_image.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask); - if (resource.mstyle.tick_image.mask != None) - XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask); -#endif // BITMAPBUTTONS - - resource.mstyle.title = - readDatabaseTexture("menu.title", "white", style); - resource.mstyle.frame = - readDatabaseTexture("menu.frame", "black", style); - resource.mstyle.hilite = - readDatabaseTexture("menu.hilite", "white", style); - resource.mstyle.t_text = - readDatabaseColor("menu.title.textColor", "black", style); - resource.mstyle.f_text = - readDatabaseColor("menu.frame.textColor", "white", style); - resource.mstyle.d_text = - readDatabaseColor("menu.frame.disableColor", "black", style); - resource.mstyle.h_text = - readDatabaseColor("menu.hilite.textColor", "black", style); - -#ifdef BITMAPBUTTONS - readDatabaseMask("menu.arrow.mask", resource.mstyle.bullet_image, style); - readDatabaseMask("menu.selected.mask", resource.mstyle.tick_image, style); -#endif // BITMAPBUTTONS - - resource.mstyle.t_justify = LeftJustify; - if (style.getValue("menu.title.justify", s)) { - if (s == "right" || s == "Right") - resource.mstyle.t_justify = RightJustify; - else if (s == "center" || s == "Center") - resource.mstyle.t_justify = CenterJustify; - } - - resource.mstyle.f_justify = LeftJustify; - if (style.getValue("menu.frame.justify", s)) { - if (s == "right" || s == "Right") - resource.mstyle.f_justify = RightJustify; - else if (s == "center" || s == "Center") - resource.mstyle.f_justify = CenterJustify; - } - - resource.mstyle.bullet = Basemenu::Triangle; - if (style.getValue("menu.bullet", s)) { - if (s == "empty" || s == "Empty") - resource.mstyle.bullet = Basemenu::Empty; - else if (s == "square" || s == "Square") - resource.mstyle.bullet = Basemenu::Square; - else if (s == "diamond" || s == "Diamond") - resource.mstyle.bullet = Basemenu::Diamond; - } - - resource.mstyle.bullet_pos = Basemenu::Left; - if (style.getValue("menu.bullet.position", s)) { - if (s == "right" || s == "Right") - resource.mstyle.bullet_pos = Basemenu::Right; - } - - // sanity checks - if (resource.mstyle.frame.texture() == BTexture::Parent_Relative) { - resource.mstyle.frame = BTexture("solid flat", getBaseDisplay(), - getScreenNumber(), image_control); - resource.mstyle.frame.setColor(BColor("black", getBaseDisplay(), - getScreenNumber())); - } - - resource.border_color = - readDatabaseColor("borderColor", "black", style); - - // load bevel, border and handle widths - if (! style.getValue("handleWidth", resource.handle_width) || - resource.handle_width > (getWidth() / 2) || resource.handle_width == 0) - resource.handle_width = 6; - - if (! style.getValue("borderWidth", resource.border_width)) - resource.border_width = 1; - - if (! style.getValue("bevelWidth", resource.bevel_width) || - resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0) - resource.bevel_width = 3; - - if (! style.getValue("frameWidth", resource.frame_width) || - resource.frame_width > (getWidth() / 2)) - resource.frame_width = resource.bevel_width; - - if (style.getValue("rootCommand", s)) - bexec(s, displayString()); -} - - -void BScreen::addIcon(BlackboxWindow *w) { - if (! w) return; - - w->setWorkspace(BSENTINEL); - w->setWindowNumber(iconList.size()); - - iconList.push_back(w); - - const char* title = w->getIconTitle(); - iconmenu->insert(title); - iconmenu->update(); -} - - -void BScreen::removeIcon(BlackboxWindow *w) { - if (! w) return; - - iconList.remove(w); - - iconmenu->remove(w->getWindowNumber()); - iconmenu->update(); - - BlackboxWindowList::iterator it = iconList.begin(), - end = iconList.end(); - for (int i = 0; it != end; ++it) - (*it)->setWindowNumber(i++); -} - - -BlackboxWindow *BScreen::getIcon(unsigned int index) { - if (index < iconList.size()) { - BlackboxWindowList::iterator it = iconList.begin(); - while (index-- > 0) // increment to index - ++it; - return *it; - } - - return (BlackboxWindow *) 0; -} - - -unsigned int BScreen::addWorkspace(void) { - Workspace *wkspc = new Workspace(this, workspacesList.size()); - workspacesList.push_back(wkspc); - saveWorkspaces(getWorkspaceCount()); - saveWorkspaceNames(); - - workspacemenu->insertWorkspace(wkspc); - workspacemenu->update(); - - toolbar->reconfigure(); - - updateNetizenWorkspaceCount(); - - return workspacesList.size(); -} - - -unsigned int BScreen::removeLastWorkspace(void) { - if (workspacesList.size() == 1) - return 1; - - Workspace *wkspc = workspacesList.back(); - - if (current_workspace->getID() == wkspc->getID()) - changeWorkspaceID(current_workspace->getID() - 1); - - wkspc->removeAll(); - - workspacemenu->removeWorkspace(wkspc); - workspacemenu->update(); - - workspacesList.pop_back(); - delete wkspc; - - saveWorkspaces(getWorkspaceCount()); - saveWorkspaceNames(); - - toolbar->reconfigure(); - - updateNetizenWorkspaceCount(); - - return workspacesList.size(); -} - - -void BScreen::changeWorkspaceID(unsigned int id) { - if (! current_workspace || id == current_workspace->getID()) return; - - BlackboxWindow *focused = blackbox->getFocusedWindow(); - if (focused && focused->getScreen() == this) { - assert(focused->isStuck() || - focused->getWorkspaceNumber() == current_workspace->getID()); - - current_workspace->setLastFocusedWindow(focused); - } else { - // if no window had focus, no need to store a last focus - current_workspace->setLastFocusedWindow((BlackboxWindow *) 0); - } - - // when we switch workspaces, unfocus whatever was focused if it is going - // to be unmapped - if (focused && ! focused->isStuck()) - blackbox->setFocusedWindow((BlackboxWindow *) 0); - - current_workspace->hideAll(); - workspacemenu->setItemSelected(current_workspace->getID() + 2, False); - - current_workspace = getWorkspace(id); - - xatom->setValue(getRootWindow(), XAtom::net_current_desktop, - XAtom::cardinal, id); - - workspacemenu->setItemSelected(current_workspace->getID() + 2, True); - toolbar->redrawWorkspaceLabel(True); - - current_workspace->showAll(); - - int x, y, rx, ry; - Window c, r; - unsigned int m; - BlackboxWindow *win = (BlackboxWindow *) 0; - bool f = False; - - XSync(blackbox->getXDisplay(), False); - - // If sloppy focus and we can find the client window under the pointer, - // try to focus it. - if (resource.sloppy_focus && - XQueryPointer(blackbox->getXDisplay(), getRootWindow(), &r, &c, - &rx, &ry, &x, &y, &m) && - c != None) { - if ( (win = blackbox->searchWindow(c)) ) - f = win->setInputFocus(); - } - - // If that fails, and we're doing focus_last, try to focus the last window. - if (! f && resource.focus_last && - (win = current_workspace->getLastFocusedWindow())) - f = win->setInputFocus(); - - /* - if we found a focus target, then we set the focused window explicitly - because it is possible to switch off this workspace before the x server - generates the FocusIn event for the window. if that happens, openbox would - lose track of what window was the 'LastFocused' window on the workspace. - - if we did not find a focus target, then set the current focused window to - nothing. - */ - if (f) - blackbox->setFocusedWindow(win); - else - blackbox->setFocusedWindow((BlackboxWindow *) 0); - - updateNetizenCurrentWorkspace(); -} - - -/* - * Set the _NET_CLIENT_LIST root window property. - */ -void BScreen::updateClientList(void) { - if (windowList.size() > 0) { - Window *windows = new Window[windowList.size()]; - Window *win_it = windows; - BlackboxWindowList::iterator it = windowList.begin(); - const BlackboxWindowList::iterator end = windowList.end(); - for (; it != end; ++it, ++win_it) - *win_it = (*it)->getClientWindow(); - xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window, - windows, windowList.size()); - delete [] windows; - } else - xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window, - 0, 0); - - updateStackingList(); -} - - -/* - * Set the _NET_CLIENT_LIST_STACKING root window property. - */ -void BScreen::updateStackingList(void) { - - BlackboxWindowList stack_order; - - /* - * Get the stacking order from all of the workspaces. - * We start with the current workspace so that the sticky windows will be - * in the right order on the current workspace. - * XXX: Do we need to have sticky windows in the list once for each workspace? - */ - getCurrentWorkspace()->appendStackOrder(stack_order); - for (unsigned int i = 0; i < getWorkspaceCount(); ++i) - if (i != getCurrentWorkspaceID()) - getWorkspace(i)->appendStackOrder(stack_order); - - if (stack_order.size() > 0) { - // set the client list atoms - Window *windows = new Window[stack_order.size()]; - Window *win_it = windows; - BlackboxWindowList::iterator it = stack_order.begin(), - end = stack_order.end(); - for (; it != end; ++it, ++win_it) - *win_it = (*it)->getClientWindow(); - xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking, - XAtom::window, windows, stack_order.size()); - delete [] windows; - } else - xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking, - XAtom::window, 0, 0); -} - - -void BScreen::addSystrayWindow(Window window) { - XGrabServer(blackbox->getXDisplay()); - - XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask); - systrayWindowList.push_back(window); - xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows, - XAtom::window, - &systrayWindowList[0], systrayWindowList.size()); - blackbox->saveSystrayWindowSearch(window, this); - - XUngrabServer(blackbox->getXDisplay()); -} - - -void BScreen::removeSystrayWindow(Window window) { - XGrabServer(blackbox->getXDisplay()); - - WindowList::iterator it = systrayWindowList.begin(); - const WindowList::iterator end = systrayWindowList.end(); - for (; it != end; ++it) - if (*it == window) { - systrayWindowList.erase(it); - xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows, - XAtom::window, - &systrayWindowList[0], systrayWindowList.size()); - blackbox->removeSystrayWindowSearch(window); - XSelectInput(blackbox->getXDisplay(), window, NoEventMask); - break; - } - - assert(it != end); // not a systray window - - XUngrabServer(blackbox->getXDisplay()); -} - - -void BScreen::manageWindow(Window w) { - // is the window a KDE systray window? - Window systray; - if (xatom->getValue(w, XAtom::kde_net_wm_system_tray_window_for, - XAtom::window, systray) && systray != None) { - addSystrayWindow(w); - return; - } - - // is the window a docking app - XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), w); - if (wmhint && (wmhint->flags & StateHint) && - wmhint->initial_state == WithdrawnState) { - slit->addClient(w); - return; - } - - new BlackboxWindow(blackbox, w, this); - - BlackboxWindow *win = blackbox->searchWindow(w); - if (! win) - return; - - if (win->isDesktop()) { - desktopWindowList.push_back(win->getFrameWindow()); - } else { // if (win->isNormal()) { - // don't list desktop windows as managed windows - windowList.push_back(win); - updateClientList(); - - if (win->isTopmost()) - specialWindowList.push_back(win->getFrameWindow()); - } - - XMapRequestEvent mre; - mre.window = w; - if (blackbox->isStartup() && win->isNormal()) win->restoreAttributes(); - win->mapRequestEvent(&mre); -} - - -void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) { - // is the window a KDE systray window? - Window systray; - if (xatom->getValue(w->getClientWindow(), - XAtom::kde_net_wm_system_tray_window_for, - XAtom::window, systray) && systray != None) { - removeSystrayWindow(w->getClientWindow()); - return; - } - - w->restore(remap); - - // Remove the modality so that its parent won't try to re-focus the window - if (w->isModal()) w->setModal(False); - - if (w->getWorkspaceNumber() != BSENTINEL && - w->getWindowNumber() != BSENTINEL) { - getWorkspace(w->getWorkspaceNumber())->removeWindow(w); - if (w->isStuck()) { - for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i) - if (i != w->getWorkspaceNumber()) - getWorkspace(i)->removeWindow(w, True); - } - } else if (w->isIconic()) - removeIcon(w); - - if (w->isDesktop()) { - WindowList::iterator it = desktopWindowList.begin(); - const WindowList::iterator end = desktopWindowList.end(); - for (; it != end; ++it) - if (*it == w->getFrameWindow()) { - desktopWindowList.erase(it); - break; - } - assert(it != end); // the window wasnt a desktop window? - } else { // if (w->isNormal()) { - // we don't list desktop windows as managed windows - windowList.remove(w); - updateClientList(); - - if (w->isTopmost()) { - WindowList::iterator it = specialWindowList.begin(); - const WindowList::iterator end = specialWindowList.end(); - for (; it != end; ++it) - if (*it == w->getFrameWindow()) { - specialWindowList.erase(it); - break; - } - assert(it != end); // the window wasnt a special window? - } - } - - if (blackbox->getFocusedWindow() == w) - blackbox->setFocusedWindow((BlackboxWindow *) 0); - - removeNetizen(w->getClientWindow()); - - /* - some managed windows can also be window group controllers. when - unmanaging such windows, we should also delete the window group. - */ - BWindowGroup *group = blackbox->searchGroup(w->getClientWindow()); - delete group; - - delete w; -} - - -void BScreen::addNetizen(Netizen *n) { - netizenList.push_back(n); - - n->sendWorkspaceCount(); - n->sendCurrentWorkspace(); - - WorkspaceList::iterator it = workspacesList.begin(); - const WorkspaceList::iterator end = workspacesList.end(); - for (; it != end; ++it) - (*it)->sendWindowList(*n); - - Window f = ((blackbox->getFocusedWindow()) ? - blackbox->getFocusedWindow()->getClientWindow() : None); - n->sendWindowFocus(f); -} - - -void BScreen::removeNetizen(Window w) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) { - if ((*it)->getWindowID() == w) { - delete *it; - netizenList.erase(it); - break; - } - } -} - - -void BScreen::updateWorkArea(void) { - if (workspacesList.size() > 0) { - unsigned long *dims = new unsigned long[4 * workspacesList.size()]; - for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) { - // XXX: this could be different for each workspace - const Rect &area = availableArea(); - dims[(i * 4) + 0] = area.x(); - dims[(i * 4) + 1] = area.y(); - dims[(i * 4) + 2] = area.width(); - dims[(i * 4) + 3] = area.height(); - } - xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal, - dims, 4 * workspacesList.size()); - delete [] dims; - } else - xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal, - 0, 0); -} - - -void BScreen::updateNetizenCurrentWorkspace(void) { - std::for_each(netizenList.begin(), netizenList.end(), - std::mem_fun(&Netizen::sendCurrentWorkspace)); -} - - -void BScreen::updateNetizenWorkspaceCount(void) { - xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops, - XAtom::cardinal, workspacesList.size()); - - updateWorkArea(); - - std::for_each(netizenList.begin(), netizenList.end(), - std::mem_fun(&Netizen::sendWorkspaceCount)); -} - - -void BScreen::updateNetizenWindowFocus(void) { - Window f = ((blackbox->getFocusedWindow()) ? - blackbox->getFocusedWindow()->getClientWindow() : None); - - xatom->setValue(getRootWindow(), XAtom::net_active_window, - XAtom::window, f); - - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) - (*it)->sendWindowFocus(f); -} - - -void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) { - (*it)->sendWindowAdd(w, p); - } -} - - -void BScreen::updateNetizenWindowDel(Window w) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) - (*it)->sendWindowDel(w); -} - - -void BScreen::updateNetizenWindowRaise(Window w) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) - (*it)->sendWindowRaise(w); -} - - -void BScreen::updateNetizenWindowLower(Window w) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) - (*it)->sendWindowLower(w); -} - - -void BScreen::updateNetizenConfigNotify(XEvent *e) { - NetizenList::iterator it = netizenList.begin(); - for (; it != netizenList.end(); ++it) - (*it)->sendConfigNotify(e); -} - - -void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) { - // the 13 represents the number of blackbox windows such as menus - int bbwins = 15; -#ifdef XINERAMA - ++bbwins; -#endif // XINERAMA -#ifdef XFT - ++bbwins; -#endif // XFT - - Window *session_stack = new - Window[(num + workspacesList.size() + rootmenuList.size() + - specialWindowList.size() + bbwins)]; - unsigned int i = 0, k = num; - - XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID()); - *(session_stack + i++) = iconmenu->getWindowID(); - - WorkspaceList::iterator wit = workspacesList.begin(); - const WorkspaceList::iterator w_end = workspacesList.end(); - for (; wit != w_end; ++wit) - *(session_stack + i++) = (*wit)->getMenu()->getWindowID(); - - *(session_stack + i++) = workspacemenu->getWindowID(); - - *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID(); - *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID(); - *(session_stack + i++) = configmenu->getWindowSnapmenu()->getWindowID(); - *(session_stack + i++) = configmenu->getEdgeSnapmenu()->getWindowID(); -#ifdef XINERAMA - *(session_stack + i++) = configmenu->getXineramamenu()->getWindowID(); -#endif // XINERAMA -#ifdef XFT - *(session_stack + i++) = configmenu->getXftmenu()->getWindowID(); -#endif // XFT - *(session_stack + i++) = configmenu->getWindowID(); - - *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID(); - *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID(); - *(session_stack + i++) = slit->getMenu()->getWindowID(); - - *(session_stack + i++) = - toolbar->getMenu()->getPlacementmenu()->getWindowID(); - *(session_stack + i++) = toolbar->getMenu()->getWindowID(); - - RootmenuList::iterator rit = rootmenuList.begin(); - for (; rit != rootmenuList.end(); ++rit) - *(session_stack + i++) = (*rit)->getWindowID(); - *(session_stack + i++) = rootmenu->getWindowID(); - - if (toolbar->isOnTop()) - *(session_stack + i++) = toolbar->getWindowID(); - - if (slit->isOnTop()) - *(session_stack + i++) = slit->getWindowID(); - - WindowList::iterator sit, send = specialWindowList.end(); - for (sit = specialWindowList.begin(); sit != send; ++sit) - *(session_stack + i++) = *sit; - - while (k--) - *(session_stack + i++) = *(workspace_stack + k); - - XRestackWindows(blackbox->getXDisplay(), session_stack, i); - - delete [] session_stack; - - updateStackingList(); -} - - -void BScreen::lowerWindows(Window *workspace_stack, unsigned int num) { - assert(num > 0); // this would cause trouble in the XRaiseWindow call - - Window *session_stack = new Window[(num + desktopWindowList.size())]; - unsigned int i = 0, k = num; - - XLowerWindow(blackbox->getXDisplay(), workspace_stack[0]); - - while (k--) - *(session_stack + i++) = *(workspace_stack + k); - - WindowList::iterator dit = desktopWindowList.begin(); - const WindowList::iterator d_end = desktopWindowList.end(); - for (; dit != d_end; ++dit) - *(session_stack + i++) = *dit; - - XRestackWindows(blackbox->getXDisplay(), session_stack, i); - - delete [] session_stack; - - updateStackingList(); -} - - -void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id, - bool ignore_sticky) { - if (! w) return; - - if (wkspc_id == BSENTINEL) - wkspc_id = current_workspace->getID(); - - if (w->getWorkspaceNumber() == wkspc_id) - return; - - if (w->isIconic()) { - removeIcon(w); - getWorkspace(wkspc_id)->addWindow(w); - if (w->isStuck()) - for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i) - if (i != w->getWorkspaceNumber()) - getWorkspace(i)->addWindow(w, True); - } else if (ignore_sticky || ! w->isStuck()) { - if (w->isStuck()) - w->stick(); - getWorkspace(w->getWorkspaceNumber())->removeWindow(w); - getWorkspace(wkspc_id)->addWindow(w); - } - updateStackingList(); -} - - -void BScreen::propagateWindowName(const BlackboxWindow *bw) { - if (bw->isIconic()) { - iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle()); - iconmenu->update(); - } else { - Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu(); - clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle()); - clientmenu->update(); - - if (blackbox->getFocusedWindow() == bw) - toolbar->redrawWindowLabel(True); - } -} - - -void BScreen::nextFocus(void) const { - BlackboxWindow *focused = blackbox->getFocusedWindow(), - *next = focused; - - if (focused && - focused->getScreen()->getScreenNumber() == getScreenNumber() && - current_workspace->getCount() > 1) { - do { - next = current_workspace->getNextWindowInList(next); - } while (next != focused && ! next->setInputFocus()); - - if (next != focused) - current_workspace->raiseWindow(next); - } else if (current_workspace->getCount() > 0) { - next = current_workspace->getTopWindowOnStack(); - next->setInputFocus(); - current_workspace->raiseWindow(next); - } -} - - -void BScreen::prevFocus(void) const { - BlackboxWindow *focused = blackbox->getFocusedWindow(), - *next = focused; - - if (focused) { - // if window is not on this screen, ignore it - if (focused->getScreen()->getScreenNumber() != getScreenNumber()) - focused = (BlackboxWindow*) 0; - } - - if (focused && - focused->getScreen()->getScreenNumber() == getScreenNumber() && - current_workspace->getCount() > 1) { - // next is the next window to receive focus, current is a place holder - do { - next = current_workspace->getPrevWindowInList(next); - } while (next != focused && ! next->setInputFocus()); - - if (next != focused) - current_workspace->raiseWindow(next); - } else if (current_workspace->getCount() > 0) { - next = current_workspace->getTopWindowOnStack(); - next->setInputFocus(); - current_workspace->raiseWindow(next); - } -} - - -void BScreen::raiseFocus(void) const { - BlackboxWindow *focused = blackbox->getFocusedWindow(); - if (! focused) - return; - - // if on this Screen, raise it - if (focused->getScreen()->getScreenNumber() == getScreenNumber()) { - Workspace *workspace = getWorkspace(focused->getWorkspaceNumber()); - workspace->raiseWindow(focused); - } -} - - -void BScreen::InitMenu(void) { - if (rootmenu) { - rootmenuList.clear(); - - while (rootmenu->getCount()) - rootmenu->remove(0); - } else { - rootmenu = new Rootmenu(this); - } - bool defaultMenu = True; - - FILE *menu_file = (FILE *) 0; - const char *menu_filename = blackbox->getMenuFilename(); - - if (menu_filename) - if (! (menu_file = fopen(menu_filename, "r"))) - perror(menu_filename); - if (! menu_file) { // opening the menu file failed, try the default menu - menu_filename = DEFAULTMENU; - if (! (menu_file = fopen(menu_filename, "r"))) - perror(menu_filename); - } - - if (menu_file) { - if (feof(menu_file)) { - fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile, - "%s: Empty menu file"), - menu_filename); - } else { - char line[1024], label[1024]; - memset(line, 0, 1024); - memset(label, 0, 1024); - - while (fgets(line, 1024, menu_file) && ! feof(menu_file)) { - if (line[0] == '#') - continue; - - int i, key = 0, index = -1, len = strlen(line); - - for (i = 0; i < len; i++) { - if (line[i] == '[') index = 0; - else if (line[i] == ']') break; - else if (line[i] != ' ') - if (index++ >= 0) - key += tolower(line[i]); - } - - if (key == 517) { // [begin] - index = -1; - for (i = index; i < len; i++) { - if (line[i] == '(') index = 0; - else if (line[i] == ')') break; - else if (index++ >= 0) { - if (line[i] == '\\' && i < len - 1) i++; - label[index - 1] = line[i]; - } - } - - if (index == -1) index = 0; - label[index] = '\0'; - - rootmenu->setLabel(label); - defaultMenu = parseMenuFile(menu_file, rootmenu); - if (! defaultMenu) - blackbox->addMenuTimestamp(menu_filename); - break; - } - } - } - fclose(menu_file); - } - - if (defaultMenu) { - rootmenu->setInternalMenu(); - rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"), - BScreen::Execute, - i18n(ScreenSet, Screenxterm, "xterm")); - rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"), - BScreen::Restart); - rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"), - BScreen::Exit); - rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu, - "Openbox Menu")); - } -} - - -static -size_t string_within(char begin, char end, - const char *input, size_t start_at, size_t length, - char *output) { - bool parse = False; - size_t index = 0; - size_t i = start_at; - for (; i < length; ++i) { - if (input[i] == begin) { - parse = True; - } else if (input[i] == end) { - break; - } else if (parse) { - if (input[i] == '\\' && i < length - 1) i++; - output[index++] = input[i]; - } - } - - if (parse) - output[index] = '\0'; - else - output[0] = '\0'; - - return i; -} - - -bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) { - char line[1024], keyword[1024], label[1024], command[1024]; - bool done = False; - - while (! (done || feof(file))) { - memset(line, 0, 1024); - memset(label, 0, 1024); - memset(command, 0, 1024); - - if (! fgets(line, 1024, file)) - continue; - - if (line[0] == '#') // comment, skip it - continue; - - size_t line_length = strlen(line); - unsigned int key = 0; - - // get the keyword enclosed in []'s - size_t pos = string_within('[', ']', line, 0, line_length, keyword); - - if (keyword[0] == '\0') { // no keyword, no menu entry - continue; - } else { - size_t len = strlen(keyword); - for (size_t i = 0; i < len; ++i) { - if (keyword[i] != ' ') - key += tolower(keyword[i]); - } - } - - // get the label enclosed in ()'s - pos = string_within('(', ')', line, pos, line_length, label); - - // get the command enclosed in {}'s - pos = string_within('{', '}', line, pos, line_length, command); - - switch (key) { - case 311: // end - done = True; - - break; - - case 333: // nop - if (! *label) - label[0] = '\0'; - menu->insert(label); - - break; - - case 421: // exec - if (! (*label && *command)) { - fprintf(stderr, i18n(ScreenSet, ScreenEXECError, - "BScreen::parseMenuFile: [exec] error, " - "no menu label and/or command defined\n")); - continue; - } - - menu->insert(label, BScreen::Execute, command); - - break; - - case 442: // exit - if (! *label) { - fprintf(stderr, i18n(ScreenSet, ScreenEXITError, - "BScreen::parseMenuFile: [exit] error, " - "no menu label defined\n")); - continue; - } - - menu->insert(label, BScreen::Exit); - - break; - - case 561: { // style - if (! (*label && *command)) { - fprintf(stderr, - i18n(ScreenSet, ScreenSTYLEError, - "BScreen::parseMenuFile: [style] error, " - "no menu label and/or filename defined\n")); - continue; - } - - string style = expandTilde(command); - - menu->insert(label, BScreen::SetStyle, style.c_str()); - } - break; - - case 630: // config - if (! *label) { - fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError, - "BScreen::parseMenufile: [config] error, " - "no label defined")); - continue; - } - - menu->insert(label, configmenu); - - break; - - case 740: { // include - if (! *label) { - fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError, - "BScreen::parseMenuFile: [include] error, " - "no filename defined\n")); - continue; - } - - string newfile = expandTilde(label); - FILE *submenufile = fopen(newfile.c_str(), "r"); - - if (! submenufile) { - perror(newfile.c_str()); - continue; - } - - struct stat buf; - if (fstat(fileno(submenufile), &buf) || - ! S_ISREG(buf.st_mode)) { - fprintf(stderr, - i18n(ScreenSet, ScreenINCLUDEErrorReg, - "BScreen::parseMenuFile: [include] error: " - "'%s' is not a regular file\n"), newfile.c_str()); - break; - } - - if (! feof(submenufile)) { - if (! parseMenuFile(submenufile, menu)) - blackbox->addMenuTimestamp(newfile); - - fclose(submenufile); - } - } - - break; - - case 767: { // submenu - if (! *label) { - fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError, - "BScreen::parseMenuFile: [submenu] error, " - "no menu label defined\n")); - continue; - } - - Rootmenu *submenu = new Rootmenu(this); - - if (*command) - submenu->setLabel(command); - else - submenu->setLabel(label); - - parseMenuFile(file, submenu); - submenu->update(); - menu->insert(label, submenu); - rootmenuList.push_back(submenu); - } - - break; - - case 773: { // restart - if (! *label) { - fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError, - "BScreen::parseMenuFile: [restart] error, " - "no menu label defined\n")); - continue; - } - - if (*command) - menu->insert(label, BScreen::RestartOther, command); - else - menu->insert(label, BScreen::Restart); - } - - break; - - case 845: { // reconfig - if (! *label) { - fprintf(stderr, - i18n(ScreenSet, ScreenRECONFIGError, - "BScreen::parseMenuFile: [reconfig] error, " - "no menu label defined\n")); - continue; - } - - menu->insert(label, BScreen::Reconfigure); - } - - break; - - case 995: // stylesdir - case 1113: { // stylesmenu - bool newmenu = ((key == 1113) ? True : False); - - if (! *label || (! *command && newmenu)) { - fprintf(stderr, - i18n(ScreenSet, ScreenSTYLESDIRError, - "BScreen::parseMenuFile: [stylesdir/stylesmenu]" - " error, no directory defined\n")); - continue; - } - - char *directory = ((newmenu) ? command : label); - - string stylesdir = expandTilde(directory); - - struct stat statbuf; - - if (stat(stylesdir.c_str(), &statbuf) == -1) { - fprintf(stderr, - i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist, - "BScreen::parseMenuFile: [stylesdir/stylesmenu]" - " error, %s does not exist\n"), stylesdir.c_str()); - continue; - } - if (! S_ISDIR(statbuf.st_mode)) { - fprintf(stderr, - i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir, - "BScreen::parseMenuFile:" - " [stylesdir/stylesmenu] error, %s is not a" - " directory\n"), stylesdir.c_str()); - continue; - } - - Rootmenu *stylesmenu; - - if (newmenu) - stylesmenu = new Rootmenu(this); - else - stylesmenu = menu; - - DIR *d = opendir(stylesdir.c_str()); - struct dirent *p; - std::vector ls; - - while((p = readdir(d))) - ls.push_back(p->d_name); - - closedir(d); - - std::sort(ls.begin(), ls.end()); - - std::vector::iterator it = ls.begin(), - end = ls.end(); - for (; it != end; ++it) { - const string& fname = *it; - - //ignore backups and dot files - if (fname[fname.size()-1] == '~' || fname[0] == '.') - continue; - - string style = stylesdir; - style += '/'; - style += fname; - - if (! stat(style.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) - stylesmenu->insert(fname, BScreen::SetStyle, style); - } - - stylesmenu->update(); - - if (newmenu) { - stylesmenu->setLabel(label); - menu->insert(label, stylesmenu); - rootmenuList.push_back(stylesmenu); - } - - blackbox->addMenuTimestamp(stylesdir); - } - break; - - case 1090: { // workspaces - if (! *label) { - fprintf(stderr, - i18n(ScreenSet, ScreenWORKSPACESError, - "BScreen:parseMenuFile: [workspaces] error, " - "no menu label defined\n")); - continue; - } - - menu->insert(label, workspacemenu); - } - break; - } - } - - return ((menu->getCount() == 0) ? True : False); -} - - -void BScreen::shutdown(void) { - XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask); - XSync(blackbox->getXDisplay(), False); - - while(! windowList.empty()) - unmanageWindow(windowList.front(), True); - - while(! desktopWindowList.empty()) { - BlackboxWindow *win = blackbox->searchWindow(desktopWindowList.front()); - assert(win); - unmanageWindow(win, True); - } - - slit->shutdown(); -} - - -void BScreen::showPosition(int x, int y) { - if (! geom_visible) { - XMoveResizeWindow(blackbox->getXDisplay(), geom_window, - (getWidth() - geom_w) / 2, - (getHeight() - geom_h) / 2, geom_w, geom_h); - XMapWindow(blackbox->getXDisplay(), geom_window); - XRaiseWindow(blackbox->getXDisplay(), geom_window); - - geom_visible = True; - } - - char label[1024]; - - sprintf(label, i18n(ScreenSet, ScreenPositionFormat, - "X: %4d x Y: %4d"), x, y); - - XClearWindow(blackbox->getXDisplay(), geom_window); - - resource.wstyle.font->drawString(geom_window, - resource.bevel_width, resource.bevel_width, - resource.wstyle.l_text_focus, - label); -} - - -void BScreen::showGeometry(unsigned int gx, unsigned int gy) { - if (! geom_visible) { - XMoveResizeWindow(blackbox->getXDisplay(), geom_window, - (getWidth() - geom_w) / 2, - (getHeight() - geom_h) / 2, geom_w, geom_h); - XMapWindow(blackbox->getXDisplay(), geom_window); - XRaiseWindow(blackbox->getXDisplay(), geom_window); - - geom_visible = True; - } - - char label[1024]; - - sprintf(label, i18n(ScreenSet, ScreenGeometryFormat, - "W: %4d x H: %4d"), gx, gy); - - XClearWindow(blackbox->getXDisplay(), geom_window); - - resource.wstyle.font->drawString(geom_window, - resource.bevel_width, resource.bevel_width, - resource.wstyle.l_text_focus, - label); -} - - -void BScreen::hideGeometry(void) { - if (geom_visible) { - XUnmapWindow(blackbox->getXDisplay(), geom_window); - geom_visible = False; - } -} - - -void BScreen::addStrut(Strut *strut) { - strutList.push_back(strut); -} - - -void BScreen::removeStrut(Strut *strut) { - strutList.remove(strut); -} - - -const Rect& BScreen::availableArea(void) const { - if (doFullMax()) - return getRect(); // return the full screen - return usableArea; -} - - -#ifdef XINERAMA -const RectList& BScreen::allAvailableAreas(void) const { - assert(isXineramaActive()); - assert(xineramaUsableArea.size() > 0); - fprintf(stderr, "1found x %d y %d w %d h %d\n", - xineramaUsableArea[0].x(), xineramaUsableArea[0].y(), - xineramaUsableArea[0].width(), xineramaUsableArea[0].height()); - return xineramaUsableArea; -} -#endif // XINERAMA - - -void BScreen::updateAvailableArea(void) { - Rect old_area = usableArea; - usableArea = getRect(); // reset to full screen - -#ifdef XINERAMA - // reset to the full areas - if (isXineramaActive()) - xineramaUsableArea = getXineramaAreas(); -#endif // XINERAMA - - /* these values represent offsets from the screen edge - * we look for the biggest offset on each edge and then apply them - * all at once - * do not be confused by the similarity to the names of Rect's members - */ - unsigned int current_left = 0, current_right = 0, current_top = 0, - current_bottom = 0; - - StrutList::const_iterator it = strutList.begin(), end = strutList.end(); - - for(; it != end; ++it) { - Strut *strut = *it; - if (strut->left > current_left) - current_left = strut->left; - if (strut->top > current_top) - current_top = strut->top; - if (strut->right > current_right) - current_right = strut->right; - if (strut->bottom > current_bottom) - current_bottom = strut->bottom; - } - - usableArea.setPos(current_left, current_top); - usableArea.setSize(usableArea.width() - (current_left + current_right), - usableArea.height() - (current_top + current_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 != usableArea) { - BlackboxWindowList::iterator it = windowList.begin(), - end = windowList.end(); - for (; it != end; ++it) - if ((*it)->isMaximized()) (*it)->remaximize(); - } - - updateWorkArea(); -} - - -Workspace* BScreen::getWorkspace(unsigned int index) const { - assert(index < workspacesList.size()); - return workspacesList[index]; -} - - -void BScreen::buttonPressEvent(const XButtonEvent *xbutton) { - if (xbutton->button == 1) { - if (! isRootColormapInstalled()) - image_control->installRootColormap(); - - if (workspacemenu->isVisible()) - workspacemenu->hide(); - - if (rootmenu->isVisible()) - rootmenu->hide(); - // mouse wheel up - } else if ((xbutton->button == 4 && resource.root_scroll == NormalScroll) || - (xbutton->button == 5 && resource.root_scroll == ReverseScroll)) { - if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1) - changeWorkspaceID(0); - else - changeWorkspaceID(getCurrentWorkspaceID() + 1); - // mouse wheel down - } else if ((xbutton->button == 5 && resource.root_scroll == NormalScroll) || - (xbutton->button == 4 && resource.root_scroll == ReverseScroll)) { - if (getCurrentWorkspaceID() == 0) - changeWorkspaceID(getWorkspaceCount() - 1); - else - changeWorkspaceID(getCurrentWorkspaceID() - 1); - } - - if (resource.root_menu_button > 0 && - xbutton->button == resource.root_menu_button) - showRootMenu(xbutton->x_root, xbutton->y_root); - else if (resource.workspace_menu_button > 0 && - xbutton->button == resource.workspace_menu_button) - showWorkspaceMenu(xbutton->x_root, xbutton->y_root); -} - - -void BScreen::showWorkspaceMenu(int x, int y) { - int mx = x - (workspacemenu->getWidth() / 2); - int my = y - (workspacemenu->getTitleHeight() / 2); - - if (mx < 0) mx = 0; - if (my < 0) my = 0; - - if (mx + workspacemenu->getWidth() > getWidth()) - mx = getWidth() - workspacemenu->getWidth() - getBorderWidth(); - - if (my + workspacemenu->getHeight() > getHeight()) - my = getHeight() - workspacemenu->getHeight() - getBorderWidth(); - - workspacemenu->move(mx, my); - - if (! workspacemenu->isVisible()) { - workspacemenu->removeParent(); - workspacemenu->show(); - } -} - - -void BScreen::showRootMenu(int x, int y) { - int mx = x - (rootmenu->getWidth() / 2); - int my = y - (rootmenu->getTitleHeight() / 2); - - if (mx < 0) mx = 0; - if (my < 0) my = 0; - - if (mx + rootmenu->getWidth() > getWidth()) - mx = getWidth() - rootmenu->getWidth() - getBorderWidth(); - - if (my + rootmenu->getHeight() > getHeight()) - my = getHeight() - rootmenu->getHeight() - getBorderWidth(); - - rootmenu->move(mx, my); - - if (! rootmenu->isVisible()) { - blackbox->checkMenu(); - rootmenu->show(); - } -} - - -void BScreen::propertyNotifyEvent(const XPropertyEvent *pe) { - if (pe->atom == xatom->getAtom(XAtom::net_desktop_names)) { - // _NET_WM_DESKTOP_NAMES - WorkspaceList::iterator it = workspacesList.begin(); - const WorkspaceList::iterator end = workspacesList.end(); - for (; it != end; ++it) { - (*it)->readName(); // re-read its name from the window property - workspacemenu->changeWorkspaceLabel((*it)->getID(), (*it)->getName()); - } - workspacemenu->update(); - toolbar->reconfigure(); - saveWorkspaceNames(); - } -} - - -void BScreen::toggleFocusModel(FocusModel model) { - std::for_each(windowList.begin(), windowList.end(), - std::mem_fun(&BlackboxWindow::ungrabButtons)); - - if (model == SloppyFocus) { - saveSloppyFocus(True); - } else { - // we're cheating here to save writing the config file 3 times - resource.auto_raise = False; - resource.click_raise = False; - saveSloppyFocus(False); - } - - std::for_each(windowList.begin(), windowList.end(), - std::mem_fun(&BlackboxWindow::grabButtons)); -} - -#ifdef BITMAPBUTTONS -void BScreen::readDatabaseMask(const string &rname, PixmapMask &pixmapMask, - const Configuration &style) { - string s; - int hx, hy; //ignored - int ret = BitmapOpenFailed; //default to failure. - - if (style.getValue(rname, s)) - { - if (s[0] != '/' && s[0] != '~') - { - std::string xbmFile = std::string("~/.openbox/buttons/") + s; - ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(), - expandTilde(xbmFile).c_str(), &pixmapMask.w, - &pixmapMask.h, &pixmapMask.mask, &hx, &hy); - } else - ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(), - expandTilde(s).c_str(), &pixmapMask.w, - &pixmapMask.h, &pixmapMask.mask, &hx, &hy); - - if (ret == BitmapSuccess) - return; - } - - pixmapMask.mask = None; - pixmapMask.w = pixmapMask.h = 0; -} -#endif // BITMAPSUCCESS - -BTexture BScreen::readDatabaseTexture(const string &rname, - const string &default_color, - const Configuration &style, - bool allowNoTexture) { - BTexture texture; - string s; - - if (style.getValue(rname, s)) - texture = BTexture(s); - else if (allowNoTexture) //no default - texture.setTexture(BTexture::NoTexture); - else - texture.setTexture(BTexture::Solid | BTexture::Flat); - - // associate this texture with this screen - texture.setDisplay(getBaseDisplay(), getScreenNumber()); - texture.setImageControl(image_control); - - if (texture.texture() != BTexture::NoTexture) { - texture.setColor(readDatabaseColor(rname + ".color", default_color, - style)); - texture.setColorTo(readDatabaseColor(rname + ".colorTo", default_color, - style)); - texture.setBorderColor(readDatabaseColor(rname + ".borderColor", - default_color, style)); - } - - return texture; -} - - -BColor BScreen::readDatabaseColor(const string &rname, - const string &default_color, - const Configuration &style) { - BColor color; - string s; - if (style.getValue(rname, s)) - color = BColor(s, getBaseDisplay(), getScreenNumber()); - else - color = BColor(default_color, getBaseDisplay(), getScreenNumber()); - return color; -} - - -BFont *BScreen::readDatabaseFont(const string &rbasename, - const Configuration &style) { - string fontname; - - string s; - -#ifdef XFT - int i; - if (style.getValue(rbasename + "xft.font", s) && - style.getValue(rbasename + "xft.size", i)) { - string family = s; - bool bold = False; - bool italic = False; - bool dropShadow = False; - - if (style.getValue(rbasename + "xft.flags", s)) { - if (s.find("bold") != string::npos) - bold = True; - if (s.find("italic") != string::npos) - italic = True; - if (s.find("shadow") != string::npos) - dropShadow = True; - } - - unsigned char offset = 1; - if (style.getValue(rbasename + "xft.shadow.offset", s)) { - offset = atoi(s.c_str()); //doesn't detect errors - if (offset > CHAR_MAX) - offset = 1; - } - - int tint = 25; - if (style.getValue(rbasename + "xft.shadow.tint", s)) { - tint = atoi(s.c_str()); - } - - if (tint > 100) tint = 100; - if (tint < -100) tint = -100; - - BFont *b = new BFont(blackbox->getXDisplay(), this, family, i, bold, - italic, dropShadow && resource.shadow_fonts, offset, - tint, resource.aa_fonts); - if (b->valid()) - return b; - else - delete b; // fall back to the normal X font stuff - } -#endif // XFT - - style.getValue(rbasename + "font", s); - // if this fails, a blank string will be used, which will cause the fallback - // font to load. - - BFont *b = new BFont(blackbox->getXDisplay(), this, s); - if (! b->valid()) - exit(2); // can't continue without a font - return b; -} diff --git a/src/Screen.hh b/src/Screen.hh deleted file mode 100644 index c6044812..00000000 --- a/src/Screen.hh +++ /dev/null @@ -1,432 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Screen.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Screen_hh -#define __Screen_hh - -extern "C" { -#include - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else // !TIME_WITH_SYS_TIME -# ifdef HAVE_SYS_TIME_H -# include -# else // !HAVE_SYS_TIME_H -# include -# endif // HAVE_SYS_TIME_H -#endif // TIME_WITH_SYS_TIME -} - -#include -#include - -#include "Color.hh" -#include "Texture.hh" -#include "Image.hh" -#include "Configmenu.hh" -#include "Iconmenu.hh" -#include "Netizen.hh" -#include "Rootmenu.hh" -#include "Timer.hh" -#include "Workspace.hh" -#include "Workspacemenu.hh" -#include "blackbox.hh" - -class Slit; // forward reference -class BFont; -class XAtom; -struct Strut; - -enum TextJustify { LeftJustify = 1, RightJustify, CenterJustify }; - -#ifdef BITMAPBUTTONS -struct PixmapMask { - Pixmap mask; - unsigned int w, h; -}; -#endif // BITMAPBUTTONS - -struct WindowStyle { - BColor l_text_focus, l_text_unfocus, b_pic_focus, - b_pic_unfocus; - BTexture f_focus, f_unfocus, t_focus, t_unfocus, l_focus, l_unfocus, - h_focus, h_unfocus, b_focus, b_unfocus, b_pressed, b_pressed_focus, - b_pressed_unfocus, g_focus, g_unfocus; - -#ifdef BITMAPBUTTONS - PixmapMask close_button, max_button, icon_button, stick_button; -#endif // BITMAPBUTTONS - BFont *font; - - TextJustify justify; - - void doJustify(const std::string &text, int &start_pos, - unsigned int max_length, unsigned int modifier) const; -}; - -struct ToolbarStyle { - BColor l_text, w_text, c_text, b_pic; - BTexture toolbar, label, window, button, pressed, clock; - -#ifdef BITMAPBUTTONS - PixmapMask left_button, right_button; -#endif // BITMAPBUTTONS - - BFont *font; - - TextJustify justify; - - void doJustify(const std::string &text, int &start_pos, - unsigned int max_length, unsigned int modifier) const; -}; - -struct MenuStyle { - BColor t_text, f_text, h_text, d_text; - BTexture title, frame, hilite; - -#ifdef BITMAPBUTTONS - PixmapMask bullet_image, tick_image; -#endif // BITMAPBUTTONS - - BFont *t_font, *f_font; - - TextJustify t_justify, f_justify; - int bullet, bullet_pos; -}; - -class BScreen : public ScreenInfo { -private: - bool root_colormap_installed, managed, geom_visible; - GC opGC; - Pixmap geom_pixmap; - Window geom_window; - - Blackbox *blackbox; - BImageControl *image_control; - Configmenu *configmenu; - Iconmenu *iconmenu; - Rootmenu *rootmenu; - Configuration *config; - XAtom *xatom; - - typedef std::list RootmenuList; - RootmenuList rootmenuList; - - typedef std::list NetizenList; - NetizenList netizenList; - BlackboxWindowList iconList, windowList; - - typedef std::vector WindowList; - WindowList specialWindowList, desktopWindowList, systrayWindowList; - - Slit *slit; - Toolbar *toolbar; - Workspace *current_workspace; - Workspacemenu *workspacemenu; - - unsigned int geom_w, geom_h; - unsigned long event_mask; - - Rect usableArea; -#ifdef XINERAMA - RectList xineramaUsableArea; -#endif // XINERAMA - - typedef std::list StrutList; - StrutList strutList; - typedef std::vector WorkspaceList; - WorkspaceList workspacesList; - - struct screen_resource { - WindowStyle wstyle; - ToolbarStyle tstyle; - MenuStyle mstyle; - - bool sloppy_focus, auto_raise, auto_edge_balance, ordered_dither, - opaque_move, full_max, focus_new, focus_last, click_raise, - allow_scroll_lock, hide_toolbar, window_corner_snap, aa_fonts, - ignore_shaded, ignore_maximized, workspace_warping, shadow_fonts; - - int snap_to_windows, snap_to_edges; - unsigned int snap_offset; - - BColor border_color; - - unsigned int workspaces; - int toolbar_placement, toolbar_width_percent, placement_policy, - snap_threshold, row_direction, col_direction, root_scroll, - resistance_size; - - unsigned int handle_width, bevel_width, frame_width, border_width, - resize_zones; - - unsigned int root_menu_button, workspace_menu_button; - -#ifdef HAVE_STRFTIME - std::string strftime_format; -#else // !HAVE_STRFTIME - bool clock24hour; - int date_format; -#endif // HAVE_STRFTIME - - } resource; - std::string screenstr; - - BScreen(const BScreen&); - BScreen& operator=(const BScreen&); - - bool parseMenuFile(FILE *file, Rootmenu *menu); - -#ifdef BITMAPBUTTONS - void readDatabaseMask(const std::string &rname, - PixmapMask &pixmapMask, - const Configuration &style); -#endif // BITMAPBUTTONS - - BTexture readDatabaseTexture(const std::string &rname, - const std::string &default_color, - const Configuration &style, - bool allowNoTexture = false); - BColor readDatabaseColor(const std::string &rname, - const std::string &default_color, - const Configuration &style); - BFont *readDatabaseFont(const std::string &rbasename, - const Configuration &style); - - void InitMenu(void); - void LoadStyle(void); - - void updateWorkArea(void); -public: - enum { WindowNoSnap = 0, WindowSnap, WindowResistance }; - enum { RowSmartPlacement = 1, ColSmartPlacement, CascadePlacement, - UnderMousePlacement, ClickMousePlacement, LeftRight, RightLeft, - TopBottom, BottomTop, IgnoreShaded, IgnoreMaximized }; - enum { RoundBullet = 1, TriangleBullet, SquareBullet, NoBullet }; - enum { Restart = 1, RestartOther, Exit, Shutdown, Execute, Reconfigure, - WindowShade, WindowIconify, WindowMaximize, WindowClose, WindowRaise, - WindowLower, WindowStick, WindowKill, SetStyle }; - enum FocusModel { SloppyFocus, ClickToFocus }; - enum RootScrollDirection { NoScroll = 0, NormalScroll, ReverseScroll }; - - BScreen(Blackbox *bb, unsigned int scrn); - ~BScreen(void); - - inline bool isSloppyFocus(void) const { return resource.sloppy_focus; } - inline bool isRootColormapInstalled(void) const - { return root_colormap_installed; } - inline bool doAutoRaise(void) const { return resource.auto_raise; } - inline bool doClickRaise(void) const { return resource.click_raise; } - inline bool isScreenManaged(void) const { return managed; } - inline bool doShadowFonts(void) const { return resource.shadow_fonts; } - inline bool doAAFonts(void) const { return resource.aa_fonts; } - inline bool doImageDither(void) const { return image_control->doDither(); } - inline bool doOrderedDither(void) const { return resource.ordered_dither; } - inline bool doOpaqueMove(void) const { return resource.opaque_move; } - inline bool doFullMax(void) const { return resource.full_max; } - inline bool doFocusNew(void) const { return resource.focus_new; } - inline bool doFocusLast(void) const { return resource.focus_last; } - inline bool doHideToolbar(void) const { return resource.hide_toolbar; } - inline int getWindowToWindowSnap(void) const - { return resource.snap_to_windows; } - inline int getWindowToEdgeSnap(void) const - { return resource.snap_to_edges; } - inline bool getWindowCornerSnap(void) const - { return resource.window_corner_snap; } - inline bool allowScrollLock(void) const { return resource.allow_scroll_lock; } - inline bool doWorkspaceWarping(void) const - { return resource.workspace_warping; } - inline int rootScrollDirection(void) const { return resource.root_scroll; } - inline unsigned int rootMenuButton(void) const - { return resource.root_menu_button; } - inline unsigned int workspaceMenuButton(void) const - { return resource.workspace_menu_button; } - - inline const GC &getOpGC(void) const { return opGC; } - - inline Blackbox *getBlackbox(void) { return blackbox; } - inline BColor *getBorderColor(void) { return &resource.border_color; } - inline BImageControl *getImageControl(void) { return image_control; } - inline Rootmenu *getRootmenu(void) { return rootmenu; } - - inline Slit *getSlit(void) { return slit; } - inline Toolbar *getToolbar(void) { return toolbar; } - - Workspace *getWorkspace(unsigned int index) const; - - inline Workspace *getCurrentWorkspace(void) { return current_workspace; } - - inline Workspacemenu *getWorkspacemenu(void) { return workspacemenu; } - - inline unsigned int getHandleWidth(void) const - { return resource.handle_width; } - inline unsigned int getBevelWidth(void) const - { return resource.bevel_width; } - inline unsigned int getFrameWidth(void) const - { return resource.frame_width; } - inline unsigned int getBorderWidth(void) const - { return resource.border_width; } - inline unsigned int getResizeZones(void) const - { return resource.resize_zones; } - inline bool getPlaceIgnoreShaded(void) const - { return resource.ignore_shaded; } - inline bool getPlaceIgnoreMaximized(void) const - { return resource.ignore_maximized; } - - inline unsigned int getCurrentWorkspaceID(void) const - { return current_workspace->getID(); } - inline unsigned int getWorkspaceCount(void) const - { return workspacesList.size(); } - inline unsigned int getIconCount(void) const { return iconList.size(); } - inline unsigned int getNumberOfWorkspaces(void) const - { return resource.workspaces; } - inline int getPlacementPolicy(void) const - { return resource.placement_policy; } - inline int getSnapOffset(void) const - { return resource.snap_offset; } - inline int getSnapThreshold(void) const - { return resource.snap_threshold; } - inline int getResistanceSize(void) const - { return resource.resistance_size; } - inline int getRowPlacementDirection(void) const - { return resource.row_direction; } - inline int getColPlacementDirection(void) const - { return resource.col_direction; } - - void changeWorkspaceCount(unsigned int new_count); - - inline void setRootColormapInstalled(bool r) { root_colormap_installed = r; } - void saveSloppyFocus(bool s); - void saveAutoRaise(bool a); - void saveClickRaise(bool c); - void saveWorkspaces(unsigned int w); - void savePlacementPolicy(int p); - void saveRowPlacementDirection(int d); - void saveColPlacementDirection(int d); - void saveSnapThreshold(int t); - void saveSnapOffset(int o); - void saveResistanceSize(int s); - void saveImageDither(bool d); - void saveShadowFonts(bool f); - void saveAAFonts(bool f); - void saveOpaqueMove(bool o); - void saveFullMax(bool f); - void saveFocusNew(bool f); - void saveFocusLast(bool f); - void saveHideToolbar(bool h); - void saveWindowToEdgeSnap(int s); - void saveWindowToWindowSnap(int s); - void saveWindowCornerSnap(bool s); - void saveResizeZones(unsigned int z); - void savePlaceIgnoreShaded(bool i); - void savePlaceIgnoreMaximized(bool i); - void saveAllowScrollLock(bool a); - void saveWorkspaceWarping(bool w); - void saveRootScrollDirection(int d); - void saveRootMenuButton(unsigned int b); - void saveWorkspaceMenuButton(unsigned int b); - inline void iconUpdate(void) { iconmenu->update(); } - -#ifdef HAVE_STRFTIME - inline const char *getStrftimeFormat(void) - { return resource.strftime_format.c_str(); } - void saveStrftimeFormat(const std::string& format); -#else // !HAVE_STRFTIME - inline int getDateFormat(void) { return resource.date_format; } - inline void saveDateFormat(int f); - inline bool isClock24Hour(void) { return resource.clock24hour; } - inline void saveClock24Hour(bool c); -#endif // HAVE_STRFTIME - - inline WindowStyle *getWindowStyle(void) { return &resource.wstyle; } - inline MenuStyle *getMenuStyle(void) { return &resource.mstyle; } - inline ToolbarStyle *getToolbarStyle(void) { return &resource.tstyle; } - - BlackboxWindow *getIcon(unsigned int index); - - // allAvailableAreas should be used whenever possible instead of this function - // as then Xinerama will work correctly. - const Rect& availableArea(void) const; -#ifdef XINERAMA - const RectList& allAvailableAreas(void) const; -#endif // XINERAMA - void updateAvailableArea(void); - void addStrut(Strut *strut); - void removeStrut(Strut *strut); - - unsigned int addWorkspace(void); - unsigned int removeLastWorkspace(void); - void changeWorkspaceID(unsigned int id); - void saveWorkspaceNames(void); - - void addNetizen(Netizen *n); - void removeNetizen(Window w); - - void addSystrayWindow(Window window); - void removeSystrayWindow(Window window); - - void addIcon(BlackboxWindow *w); - void removeIcon(BlackboxWindow *w); - - void updateClientList(void); - void updateStackingList(void); - void manageWindow(Window w); - void unmanageWindow(BlackboxWindow *w, bool remap); - void raiseWindows(Window *workspace_stack, unsigned int num); - void lowerWindows(Window *workspace_stack, unsigned int num); - void reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id, - bool ignore_sticky); - void propagateWindowName(const BlackboxWindow *bw); - void prevFocus(void) const; - void nextFocus(void) const; - void raiseFocus(void) const; - void load_rc(void); - void save_rc(void); - void reconfigure(void); - void toggleFocusModel(FocusModel model); - void rereadMenu(void); - void shutdown(void); - void showPosition(int x, int y); - void showGeometry(unsigned int gx, unsigned int gy); - void hideGeometry(void); - - void showWorkspaceMenu(int x, int y); - void showRootMenu(int x, int y); - - void buttonPressEvent(const XButtonEvent *xbutton); - void propertyNotifyEvent(const XPropertyEvent *pe); - - void updateNetizenCurrentWorkspace(void); - void updateNetizenWorkspaceCount(void); - void updateNetizenWindowFocus(void); - void updateNetizenWindowAdd(Window w, unsigned long p); - void updateNetizenWindowDel(Window w); - void updateNetizenConfigNotify(XEvent *e); - void updateNetizenWindowRaise(Window w); - void updateNetizenWindowLower(Window w); -}; - - -#endif // __Screen_hh diff --git a/src/Slit.cc b/src/Slit.cc deleted file mode 100644 index c15f66c4..00000000 --- a/src/Slit.cc +++ /dev/null @@ -1,915 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Slit.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -} - -#include "i18n.hh" -#include "blackbox.hh" -#include "Image.hh" -#include "Screen.hh" -#include "Slit.hh" -#include "Toolbar.hh" - - -Slit::Slit(BScreen *scr) { - screen = scr; - blackbox = screen->getBlackbox(); - slitstr = "session.screen" + itostring(screen->getScreenNumber()) + ".slit."; - config = blackbox->getConfig(); - - load_rc(); - - display = screen->getBaseDisplay()->getXDisplay(); - frame.window = frame.pixmap = None; - - timer = new BTimer(blackbox, this); - timer->setTimeout(blackbox->getAutoRaiseDelay()); - - slitmenu = new Slitmenu(this); - - XSetWindowAttributes attrib; - unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | - CWColormap | CWOverrideRedirect | CWEventMask; - attrib.background_pixmap = None; - attrib.background_pixel = attrib.border_pixel = - screen->getBorderColor()->pixel(); - attrib.colormap = screen->getColormap(); - attrib.override_redirect = True; - attrib.event_mask = SubstructureRedirectMask | ButtonPressMask | - EnterWindowMask | LeaveWindowMask; - - frame.rect.setSize(1, 1); - - frame.window = - XCreateWindow(display, screen->getRootWindow(), - frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height(), - screen->getBorderWidth(), screen->getDepth(), InputOutput, - screen->getVisual(), create_mask, &attrib); - blackbox->saveSlitSearch(frame.window, this); - - screen->addStrut(&strut); - - reconfigure(); -} - - -Slit::~Slit(void) { - delete timer; - - delete slitmenu; - - screen->removeStrut(&strut); - screen->updateAvailableArea(); - - screen->getImageControl()->removeImage(frame.pixmap); - - blackbox->removeSlitSearch(frame.window); - - XDestroyWindow(display, frame.window); -} - - -void Slit::addClient(Window w) { - if (! blackbox->validateWindow(w)) - return; - - SlitClient *client = new SlitClient; - client->client_window = w; - - XWMHints *wmhints = XGetWMHints(display, w); - - if (wmhints) { - if ((wmhints->flags & IconWindowHint) && - (wmhints->icon_window != None)) { - // some dock apps use separate windows, we need to hide these - XMoveWindow(display, client->client_window, screen->getWidth() + 10, - screen->getHeight() + 10); - XMapWindow(display, client->client_window); - - client->icon_window = wmhints->icon_window; - client->window = client->icon_window; - } else { - client->icon_window = None; - client->window = client->client_window; - } - - XFree(wmhints); - } else { - client->icon_window = None; - client->window = client->client_window; - } - - XWindowAttributes attrib; - if (XGetWindowAttributes(display, client->window, &attrib)) { - client->rect.setSize(attrib.width, attrib.height); - } else { - client->rect.setSize(64, 64); - } - - Atom *proto; - int num_return = 0; - if (XGetWMProtocols(display, client->window, &proto, &num_return)) { - for (int i = 0; i < num_return; ++i) { - if (proto[i] == - blackbox->getXAtom()->getAtom(XAtom::blackbox_structure_messages)) { - screen->addNetizen(new Netizen(screen, client->window)); - } - } - } - - XSetWindowBorderWidth(display, client->window, 0); - - XGrabServer(display); - XSelectInput(display, frame.window, NoEventMask); - XSelectInput(display, client->window, NoEventMask); - XReparentWindow(display, client->window, frame.window, 0, 0); - XMapRaised(display, client->window); - XChangeSaveSet(display, client->window, SetModeInsert); - XSelectInput(display, frame.window, SubstructureRedirectMask | - ButtonPressMask | EnterWindowMask | LeaveWindowMask); - XSelectInput(display, client->window, StructureNotifyMask | - SubstructureNotifyMask | EnterWindowMask); - - XUngrabServer(display); - - clientList.push_back(client); - - blackbox->saveSlitSearch(client->client_window, this); - blackbox->saveSlitSearch(client->icon_window, this); - reconfigure(); -} - - -void Slit::removeClient(SlitClient *client, bool remap) { - blackbox->removeSlitSearch(client->client_window); - blackbox->removeSlitSearch(client->icon_window); - clientList.remove(client); - - screen->removeNetizen(client->window); - - if (remap && blackbox->validateWindow(client->window)) { - XGrabServer(display); - XSelectInput(display, frame.window, NoEventMask); - XSelectInput(display, client->window, NoEventMask); - XReparentWindow(display, client->window, screen->getRootWindow(), - client->rect.x(), client->rect.y()); - XChangeSaveSet(display, client->window, SetModeDelete); - XSelectInput(display, frame.window, SubstructureRedirectMask | - ButtonPressMask | EnterWindowMask | LeaveWindowMask); - XUngrabServer(display); - } - - delete client; - client = (SlitClient *) 0; -} - - -struct SlitClientMatch { - Window window; - SlitClientMatch(Window w): window(w) {} - inline bool operator()(const Slit::SlitClient* client) const { - return (client->window == window); - } -}; - - -void Slit::removeClient(Window w, bool remap) { - SlitClientList::iterator it = clientList.begin(); - const SlitClientList::iterator end = clientList.end(); - - it = std::find_if(it, end, SlitClientMatch(w)); - if (it != end) { - removeClient(*it, remap); - reconfigure(); - } -} - - -void Slit::saveOnTop(bool b) { - on_top = b; - config->setValue(slitstr + "onTop", on_top); -} - -void Slit::saveAutoHide(bool b) { - do_auto_hide = b; - config->setValue(slitstr + "autoHide", do_auto_hide); -} - -void Slit::savePlacement(int p) { - placement = p; - const char *pname; - switch (placement) { - case TopLeft: pname = "TopLeft"; break; - case CenterLeft: pname = "CenterLeft"; break; - case BottomLeft: pname = "BottomLeft"; break; - case TopCenter: pname = "TopCenter"; break; - case BottomCenter: pname = "BottomCenter"; break; - case TopRight: pname = "TopRight"; break; - case BottomRight: pname = "BottomRight"; break; - case CenterRight: default: pname = "CenterRight"; break; - } - config->setValue(slitstr + "placement", pname); -} - -void Slit::saveDirection(int d) { - direction = d; - config->setValue(slitstr + "direction", (direction == Horizontal ? - "Horizontal" : "Vertical")); -} - -void Slit::save_rc(void) { - saveOnTop(on_top); - saveAutoHide(do_auto_hide); - savePlacement(placement); - saveDirection(direction); -} - -void Slit::load_rc(void) { - std::string s; - - if (! config->getValue(slitstr + "onTop", on_top)) - on_top = false; - - if (! config->getValue(slitstr + "autoHide", do_auto_hide)) - do_auto_hide = false; - hidden = do_auto_hide; - - if (config->getValue(slitstr + "direction", s) && s == "Horizontal") - direction = Horizontal; - else - direction = Vertical; - - if (config->getValue(slitstr + "placement", s)) { - if (s == "TopLeft") - placement = TopLeft; - else if (s == "CenterLeft") - placement = CenterLeft; - else if (s == "BottomLeft") - placement = BottomLeft; - else if (s == "TopCenter") - placement = TopCenter; - else if (s == "BottomCenter") - placement = BottomCenter; - else if (s == "TopRight") - placement = TopRight; - else if (s == "BottomRight") - placement = BottomRight; - else //if (s == "CenterRight") - placement = CenterRight; - } else - placement = CenterRight; -} - - -void Slit::reconfigure(void) { - SlitClientList::iterator it = clientList.begin(); - const SlitClientList::iterator end = clientList.end(); - SlitClient *client; - - unsigned int width = 0, height = 0; - - switch (direction) { - case Vertical: - for (; it != end; ++it) { - client = *it; - height += client->rect.height() + screen->getBevelWidth(); - - if (width < client->rect.width()) - width = client->rect.width(); - } - - if (width < 1) - width = 1; - else - width += (screen->getBevelWidth() * 2); - - if (height < 1) - height = 1; - else - height += screen->getBevelWidth(); - - break; - - case Horizontal: - for (; it != end; ++it) { - client = *it; - width += client->rect.width() + screen->getBevelWidth(); - - if (height < client->rect.height()) - height = client->rect.height(); - } - - if (width < 1) - width = 1; - else - width += screen->getBevelWidth(); - - if (height < 1) - height = 1; - else - height += (screen->getBevelWidth() * 2); - - break; - } - frame.rect.setSize(width, height); - - reposition(); - - XSetWindowBorderWidth(display ,frame.window, screen->getBorderWidth()); - XSetWindowBorder(display, frame.window, - screen->getBorderColor()->pixel()); - - if (clientList.empty()) - XUnmapWindow(display, frame.window); - else - XMapWindow(display, frame.window); - - BTexture *texture = &(screen->getToolbarStyle()->toolbar); - frame.pixmap = texture->render(frame.rect.width(), frame.rect.height(), - frame.pixmap); - if (! frame.pixmap) - XSetWindowBackground(display, frame.window, texture->color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap); - - XClearWindow(display, frame.window); - - it = clientList.begin(); - - int x, y; - - switch (direction) { - case Vertical: - x = 0; - y = screen->getBevelWidth(); - - for (; it != end; ++it) { - client = *it; - x = (frame.rect.width() - client->rect.width()) / 2; - - XMoveResizeWindow(display, client->window, x, y, - client->rect.width(), client->rect.height()); - XMapWindow(display, client->window); - - // for ICCCM compliance - client->rect.setPos(x, y); - - XEvent event; - event.type = ConfigureNotify; - - event.xconfigure.display = display; - event.xconfigure.event = client->window; - event.xconfigure.window = client->window; - event.xconfigure.x = x; - event.xconfigure.y = y; - event.xconfigure.width = client->rect.width(); - event.xconfigure.height = client->rect.height(); - event.xconfigure.border_width = 0; - event.xconfigure.above = frame.window; - event.xconfigure.override_redirect = False; - - XSendEvent(display, client->window, False, StructureNotifyMask, &event); - - y += client->rect.height() + screen->getBevelWidth(); - } - - break; - - case Horizontal: - x = screen->getBevelWidth(); - y = 0; - - for (; it != end; ++it) { - client = *it; - y = (frame.rect.height() - client->rect.height()) / 2; - - XMoveResizeWindow(display, client->window, x, y, - client->rect.width(), client->rect.height()); - XMapWindow(display, client->window); - - // for ICCCM compliance - client->rect.setPos(x, y); - - XEvent event; - event.type = ConfigureNotify; - - event.xconfigure.display = display; - event.xconfigure.event = client->window; - event.xconfigure.window = client->window; - event.xconfigure.x = x; - event.xconfigure.y = y; - event.xconfigure.width = client->rect.width(); - event.xconfigure.height = client->rect.height(); - event.xconfigure.border_width = 0; - event.xconfigure.above = frame.window; - event.xconfigure.override_redirect = False; - - XSendEvent(display, client->window, False, StructureNotifyMask, &event); - - x += client->rect.width() + screen->getBevelWidth(); - } - break; - } - - slitmenu->reconfigure(); -} - - -void Slit::updateStrut(void) { - strut.top = strut.bottom = strut.left = strut.right = 0; - - if (! clientList.empty()) { - // when not hidden both borders are in use, when hidden only one is - unsigned int border_width = screen->getBorderWidth(); - if (! do_auto_hide) - border_width *= 2; - - switch (direction) { - case Vertical: - switch (placement) { - case TopCenter: - strut.top = getExposedHeight() + border_width; - break; - case BottomCenter: - strut.bottom = getExposedHeight() + border_width; - break; - case TopLeft: - case CenterLeft: - case BottomLeft: - strut.left = getExposedWidth() + border_width; - break; - case TopRight: - case CenterRight: - case BottomRight: - strut.right = getExposedWidth() + border_width; - break; - } - break; - case Horizontal: - switch (placement) { - case TopCenter: - case TopLeft: - case TopRight: - strut.top = frame.rect.top() + getExposedHeight() + border_width; - break; - case BottomCenter: - case BottomLeft: - case BottomRight: - int pos; - if (do_auto_hide) - pos = frame.y_hidden; - else - pos = frame.rect.y(); - strut.bottom = (screen->getRect().bottom() - pos); - break; - case CenterLeft: - strut.left = getExposedWidth() + border_width; - break; - case CenterRight: - strut.right = getExposedWidth() + border_width; - break; - } - break; - } - } - - // update area with new Strut info - screen->updateAvailableArea(); -} - - -void Slit::reposition(void) { - int x = 0, y = 0; - - switch (placement) { - case TopLeft: - case CenterLeft: - case BottomLeft: - x = 0; - frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth() - - frame.rect.width(); - - if (placement == TopLeft) - y = 0; - else if (placement == CenterLeft) - y = (screen->getHeight() - frame.rect.height()) / 2; - else - y = screen->getHeight() - frame.rect.height() - - (screen->getBorderWidth() * 2); - - break; - - case TopCenter: - case BottomCenter: - x = (screen->getWidth() - frame.rect.width()) / 2; - frame.x_hidden = x; - - if (placement == TopCenter) - y = 0; - else - y = screen->getHeight() - frame.rect.height() - - (screen->getBorderWidth() * 2); - - break; - - case TopRight: - case CenterRight: - case BottomRight: - x = screen->getWidth() - frame.rect.width() - - (screen->getBorderWidth() * 2); - frame.x_hidden = screen->getWidth() - screen->getBevelWidth() - - screen->getBorderWidth(); - - if (placement == TopRight) - y = 0; - else if (placement == CenterRight) - y = (screen->getHeight() - frame.rect.height()) / 2; - else - y = screen->getHeight() - frame.rect.height() - - (screen->getBorderWidth() * 2); - break; - } - - frame.rect.setPos(x, y); - - // we have to add the border to the rect as it is not accounted for - Rect tbar_rect = screen->getToolbar()->getRect(); - tbar_rect.setSize(tbar_rect.width() + (screen->getBorderWidth() * 2), - tbar_rect.height() + (screen->getBorderWidth() * 2)); - Rect slit_rect = frame.rect; - slit_rect.setSize(slit_rect.width() + (screen->getBorderWidth() * 2), - slit_rect.height() + (screen->getBorderWidth() * 2)); - - if (! screen->doHideToolbar() && slit_rect.intersects(tbar_rect)) { - int delta = screen->getToolbar()->getExposedHeight() + - screen->getBorderWidth(); - if (frame.rect.bottom() <= tbar_rect.bottom()) - delta = -delta; - - frame.rect.setY(frame.rect.y() + delta); - } - - if (placement == TopCenter) - frame.y_hidden = 0 - frame.rect.height() + screen->getBorderWidth() - + screen->getBevelWidth(); - else if (placement == BottomCenter) - frame.y_hidden = screen->getHeight() - screen->getBorderWidth() - - screen->getBevelWidth(); - else - frame.y_hidden = frame.rect.y(); - - updateStrut(); - - if (hidden) - XMoveResizeWindow(display, frame.window, - frame.x_hidden, frame.y_hidden, - frame.rect.width(), frame.rect.height()); - else - XMoveResizeWindow(display, frame.window, - frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height()); -} - - -void Slit::shutdown(void) { - while (! clientList.empty()) - removeClient(clientList.front()); -} - - -void Slit::buttonPressEvent(const XButtonEvent *e) { - if (e->window != frame.window) return; - - if (e->button == Button1 && (! on_top)) { - Window w[1] = { frame.window }; - screen->raiseWindows(w, 1); - } else if (e->button == Button2 && (! on_top)) { - XLowerWindow(display, frame.window); - } else if (e->button == Button3) { - if (! slitmenu->isVisible()) { - int x, y; - - x = e->x_root - (slitmenu->getWidth() / 2); - y = e->y_root - (slitmenu->getHeight() / 2); - - if (x < 0) - x = 0; - else if (x + slitmenu->getWidth() > screen->getWidth()) - x = screen->getWidth() - slitmenu->getWidth(); - - if (y < 0) - y = 0; - else if (y + slitmenu->getHeight() > screen->getHeight()) - y = screen->getHeight() - slitmenu->getHeight(); - - slitmenu->move(x, y); - slitmenu->show(); - } else { - slitmenu->hide(); - } - } -} - - -void Slit::enterNotifyEvent(const XCrossingEvent *) { - if (! do_auto_hide) - return; - - if (hidden) { - if (! timer->isTiming()) timer->start(); - } else { - if (timer->isTiming()) timer->stop(); - } -} - - -void Slit::leaveNotifyEvent(const XCrossingEvent *) { - if (! do_auto_hide) - return; - - if (hidden) { - if (timer->isTiming()) timer->stop(); - } else if (! slitmenu->isVisible()) { - if (! timer->isTiming()) timer->start(); - } -} - - -void Slit::configureRequestEvent(const XConfigureRequestEvent *e) { - if (! blackbox->validateWindow(e->window)) - return; - - XWindowChanges xwc; - - xwc.x = e->x; - xwc.y = e->y; - xwc.width = e->width; - xwc.height = e->height; - xwc.border_width = 0; - xwc.sibling = e->above; - xwc.stack_mode = e->detail; - - XConfigureWindow(display, e->window, e->value_mask, &xwc); - - SlitClientList::iterator it = clientList.begin(); - const SlitClientList::iterator end = clientList.end(); - for (; it != end; ++it) { - SlitClient *client = *it; - if (client->window == e->window && - (static_cast(client->rect.width()) != e->width || - static_cast(client->rect.height()) != e->height)) { - client->rect.setSize(e->width, e->height); - - reconfigure(); - return; - } - } -} - - -void Slit::timeout(void) { - hidden = ! hidden; - if (hidden) - XMoveWindow(display, frame.window, frame.x_hidden, frame.y_hidden); - else - XMoveWindow(display, frame.window, frame.rect.x(), frame.rect.y()); -} - - -void Slit::toggleAutoHide(void) { - saveAutoHide(do_auto_hide ? False : True); - - updateStrut(); - - if (do_auto_hide == False && hidden) { - // force the slit to be visible - if (timer->isTiming()) timer->stop(); - timeout(); - } -} - - -void Slit::unmapNotifyEvent(const XUnmapEvent *e) { - removeClient(e->window); -} - - -Slitmenu::Slitmenu(Slit *sl) : Basemenu(sl->screen) { - slit = sl; - - setLabel(i18n(SlitSet, SlitSlitTitle, "Slit")); - setInternalMenu(); - - directionmenu = new Directionmenu(this); - placementmenu = new Placementmenu(this); - - insert(i18n(CommonSet, CommonDirectionTitle, "Direction"), - directionmenu); - insert(i18n(CommonSet, CommonPlacementTitle, "Placement"), - placementmenu); - insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1); - insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2); - - update(); - - if (slit->isOnTop()) setItemSelected(2, True); - if (slit->doAutoHide()) setItemSelected(3, True); -} - - -Slitmenu::~Slitmenu(void) { - delete directionmenu; - delete placementmenu; -} - - -void Slitmenu::itemSelected(int button, unsigned int index) { - if (button != 1) - return; - - BasemenuItem *item = find(index); - if (! item) return; - - switch (item->function()) { - case 1: { // always on top - slit->saveOnTop(! slit->isOnTop()); - setItemSelected(2, slit->isOnTop()); - - if (slit->isOnTop()) slit->screen->raiseWindows((Window *) 0, 0); - break; - } - - case 2: { // auto hide - slit->toggleAutoHide(); - setItemSelected(3, slit->doAutoHide()); - - break; - } - } // switch -} - - -void Slitmenu::internal_hide(void) { - Basemenu::internal_hide(); - if (slit->doAutoHide()) - slit->timeout(); -} - - -void Slitmenu::reconfigure(void) { - directionmenu->reconfigure(); - placementmenu->reconfigure(); - - Basemenu::reconfigure(); -} - - -Slitmenu::Directionmenu::Directionmenu(Slitmenu *sm) - : Basemenu(sm->slit->screen), slit(sm->slit) { - - setLabel(i18n(SlitSet, SlitSlitDirection, "Slit Direction")); - setInternalMenu(); - - insert(i18n(CommonSet, CommonDirectionHoriz, "Horizontal"), - Slit::Horizontal); - insert(i18n(CommonSet, CommonDirectionVert, "Vertical"), - Slit::Vertical); - - update(); - setValues(); -} - - -void Slitmenu::Directionmenu::reconfigure(void) { - setValues(); - Basemenu::reconfigure(); -} - - -void Slitmenu::Directionmenu::setValues(void) { - const bool horiz = slit->getDirection() == Slit::Horizontal; - setItemSelected(0, horiz); - setItemSelected(1, ! horiz); -} - - -void Slitmenu::Directionmenu::itemSelected(int button, unsigned int index) { - if (button != 1) - return; - - BasemenuItem *item = find(index); - if (! item) return; - - slit->saveDirection(item->function()); - hide(); - slit->reconfigure(); -} - - -Slitmenu::Placementmenu::Placementmenu(Slitmenu *sm) - : Basemenu(sm->slit->screen), slit(sm->slit) { - - setLabel(i18n(SlitSet, SlitSlitPlacement, "Slit Placement")); - setMinimumSublevels(3); - setInternalMenu(); - - insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"), - Slit::TopLeft); - insert(i18n(CommonSet, CommonPlacementCenterLeft, "Center Left"), - Slit::CenterLeft); - insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"), - Slit::BottomLeft); - insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"), - Slit::TopCenter); - insert(""); - insert(i18n(CommonSet, CommonPlacementBottomCenter, "Bottom Center"), - Slit::BottomCenter); - insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"), - Slit::TopRight); - insert(i18n(CommonSet, CommonPlacementCenterRight, "Center Right"), - Slit::CenterRight); - insert(i18n(CommonSet, CommonPlacementBottomRight, "Bottom Right"), - Slit::BottomRight); - - update(); - - setValues(); -} - - -void Slitmenu::Placementmenu::reconfigure(void) { - setValues(); - Basemenu::reconfigure(); -} - - -void Slitmenu::Placementmenu::setValues(void) { - int place = 0; - switch (slit->getPlacement()) { - case Slit::BottomRight: - place++; - case Slit::CenterRight: - place++; - case Slit::TopRight: - place++; - case Slit::BottomCenter: - place++; - case Slit::TopCenter: - place++; - case Slit::BottomLeft: - place++; - case Slit::CenterLeft: - place++; - case Slit::TopLeft: - break; - } - setItemSelected(0, 0 == place); - setItemSelected(1, 1 == place); - setItemSelected(2, 2 == place); - setItemSelected(3, 3 == place); - setItemSelected(5, 4 == place); - setItemSelected(6, 5 == place); - setItemSelected(7, 6 == place); - setItemSelected(8, 7 == place); -} - - -void Slitmenu::Placementmenu::itemSelected(int button, unsigned int index) { - if (button != 1) - return; - - BasemenuItem *item = find(index); - if (! (item && item->function())) return; - - slit->savePlacement(item->function()); - hide(); - slit->reconfigure(); -} - diff --git a/src/Slit.hh b/src/Slit.hh deleted file mode 100644 index 798ccb24..00000000 --- a/src/Slit.hh +++ /dev/null @@ -1,205 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Slit.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Slit_hh -#define __Slit_hh - -extern "C" { -#include -#include -} - -#include -#include - -#include "Screen.hh" -#include "Basemenu.hh" - -// forward declaration -class Slit; -class Slitmenu; - -class Slitmenu : public Basemenu { -private: - class Directionmenu : public Basemenu { - private: - Directionmenu(const Directionmenu&); - Directionmenu& operator=(const Directionmenu&); - Slit *slit; - - protected: - virtual void itemSelected(int button, unsigned int index); - virtual void setValues(void); - - public: - Directionmenu(Slitmenu *sm); - virtual void reconfigure(void); - }; - - class Placementmenu : public Basemenu { - private: - Placementmenu(const Placementmenu&); - Placementmenu& operator=(const Placementmenu&); - Slit *slit; - - protected: - virtual void itemSelected(int buton, unsigned int index); - virtual void setValues(void); - - public: - Placementmenu(Slitmenu *sm); - virtual void reconfigure(void); - }; - - Directionmenu *directionmenu; - Placementmenu *placementmenu; - - Slit *slit; - - friend class Directionmenu; - friend class Placementmenu; - friend class Slit; - - Slitmenu(const Slitmenu&); - Slitmenu& operator=(const Slitmenu&); - -protected: - virtual void itemSelected(int button, unsigned int index); - virtual void internal_hide(void); - -public: - Slitmenu(Slit *sl); - virtual ~Slitmenu(void); - - inline Basemenu *getDirectionmenu(void) { return directionmenu; } - inline Basemenu *getPlacementmenu(void) { return placementmenu; } - - void reconfigure(void); -}; - - -class Slit : public TimeoutHandler { -public: - struct SlitClient { - Window window, client_window, icon_window; - - Rect rect; - }; - -private: - typedef std::list SlitClientList; - - bool on_top, hidden, do_auto_hide; - int direction, placement; - std::string slitstr; - Display *display; - - Blackbox *blackbox; - BScreen *screen; - Configuration *config; - BTimer *timer; - Strut strut; - - SlitClientList clientList; - Slitmenu *slitmenu; - - struct SlitFrame { - Pixmap pixmap; - Window window; - - int x_hidden, y_hidden; - Rect rect; - } frame; - - void updateStrut(void); - - friend class Slitmenu; - friend class Slitmenu::Directionmenu; - friend class Slitmenu::Placementmenu; - - Slit(const Slit&); - Slit& operator=(const Slit&); - -public: - Slit(BScreen *scr); - virtual ~Slit(void); - - inline bool isOnTop(void) const { return on_top; } - inline bool isHidden(void) const { return hidden; } - inline bool doAutoHide(void) const { return do_auto_hide; } - inline int getPlacement(void) const { return placement; } - inline int getDirection(void) const { return direction; } - - void saveOnTop(bool); - void saveAutoHide(bool); - void savePlacement(int); - void saveDirection(int); - - inline Slitmenu *getMenu(void) { return slitmenu; } - - inline Window getWindowID(void) const { return frame.window; } - - inline int getX(void) const - { return ((hidden) ? frame.x_hidden : frame.rect.x()); } - inline int getY(void) const - { return ((hidden) ? frame.y_hidden : frame.rect.y()); } - - inline unsigned int getWidth(void) const { return frame.rect.width(); } - inline unsigned int getExposedWidth(void) const { - if (direction == Vertical && do_auto_hide) - return screen->getBevelWidth(); - return frame.rect.width(); - } - inline unsigned int getHeight(void) const { return frame.rect.height(); } - inline unsigned int getExposedHeight(void) const { - if (direction == Horizontal && do_auto_hide) - return screen->getBevelWidth(); - return frame.rect.height(); - } - - void addClient(Window w); - void removeClient(SlitClient *client, bool remap = True); - void removeClient(Window w, bool remap = True); - void load_rc(void); - void save_rc(void); - void reconfigure(void); - void updateSlit(void); - void reposition(void); - void shutdown(void); - void toggleAutoHide(void); - - void buttonPressEvent(const XButtonEvent *e); - void enterNotifyEvent(const XCrossingEvent * /*unused*/); - void leaveNotifyEvent(const XCrossingEvent * /*unused*/); - void configureRequestEvent(const XConfigureRequestEvent *e); - void unmapNotifyEvent(const XUnmapEvent *e); - - virtual void timeout(void); - - enum { Vertical = 1, Horizontal }; - enum { TopLeft = 1, CenterLeft, BottomLeft, TopCenter, BottomCenter, - TopRight, CenterRight, BottomRight }; -}; - - -#endif // __Slit_hh diff --git a/src/Texture.cc b/src/Texture.cc deleted file mode 100644 index 75283a91..00000000 --- a/src/Texture.cc +++ /dev/null @@ -1,204 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Texture.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -#ifdef HAVE_CTYPE_H -#include -#endif -} - -#include - -#include "Texture.hh" -#include "BaseDisplay.hh" -#include "Image.hh" -#include "Screen.hh" -#include "blackbox.hh" - -using std::string; - - -BTexture::BTexture(const BaseDisplay * const _display, - unsigned int _screen, BImageControl* _ctrl) - : c(_display, _screen), ct(_display, _screen), - lc(_display, _screen), sc(_display, _screen), bc(_display, _screen), t(0), - dpy(_display), ctrl(_ctrl), scrn(_screen) { } - - -BTexture::BTexture(const string &d, const BaseDisplay * const _display, - unsigned int _screen, BImageControl* _ctrl) - : c(_display, _screen), ct(_display, _screen), - lc(_display, _screen), sc(_display, _screen), bc(_display, _screen), t(0), - dpy(_display), ctrl(_ctrl), scrn(_screen) { - setDescription(d); -} - - -void BTexture::setColor(const BColor &cc) { - c = cc; - c.setDisplay(display(), screen()); - - unsigned char r, g, b, rr, gg, bb; - - // calculate the light color - r = c.red(); - g = c.green(); - b = c.blue(); - rr = r + (r >> 1); - gg = g + (g >> 1); - bb = b + (b >> 1); - if (rr < r) rr = ~0; - if (gg < g) gg = ~0; - if (bb < b) bb = ~0; - lc = BColor(rr, gg, bb, display(), screen()); - - // calculate the shadow color - r = c.red(); - g = c.green(); - b = c.blue(); - rr = (r >> 2) + (r >> 1); - gg = (g >> 2) + (g >> 1); - bb = (b >> 2) + (b >> 1); - if (rr > r) rr = 0; - if (gg > g) gg = 0; - if (bb > b) bb = 0; - sc = BColor(rr, gg, bb, display(), screen()); -} - - -void BTexture::setDescription(const string &d) { - descr.erase(); - descr.reserve(d.length()); - - string::const_iterator it = d.begin(), end = d.end(); - for (; it != end; ++it) - descr += tolower(*it); - - if (descr.find("parentrelative") != string::npos) { - setTexture(BTexture::Parent_Relative); - } else { - setTexture(0); - - if (descr.find("gradient") != string::npos) { - addTexture(BTexture::Gradient); - if (descr.find("crossdiagonal") != string::npos) - addTexture(BTexture::CrossDiagonal); - else if (descr.find("rectangle") != string::npos) - addTexture(BTexture::Rectangle); - else if (descr.find("pyramid") != string::npos) - addTexture(BTexture::Pyramid); - else if (descr.find("pipecross") != string::npos) - addTexture(BTexture::PipeCross); - else if (descr.find("elliptic") != string::npos) - addTexture(BTexture::Elliptic); - else if (descr.find("horizontal") != string::npos) - addTexture(BTexture::Horizontal); - else if (descr.find("vertical") != string::npos) - addTexture(BTexture::Vertical); - else - addTexture(BTexture::Diagonal); - } else { - addTexture(BTexture::Solid); - } - - if (descr.find("sunken") != string::npos) - addTexture(BTexture::Sunken); - else if (descr.find("flat") != string::npos) - addTexture(BTexture::Flat); - else - addTexture(BTexture::Raised); - - if (texture() & BTexture::Flat) { - if (descr.find("border") != string::npos) - addTexture(BTexture::Border); - } else { - if (descr.find("bevel2") != string::npos) - addTexture(BTexture::Bevel2); - else - addTexture(BTexture::Bevel1); - } - - if (descr.find("interlaced") != string::npos) - addTexture(BTexture::Interlaced); - } -} - -void BTexture::setDisplay(const BaseDisplay * const _display, - const unsigned int _screen) { - if (_display == display() && _screen == screen()) { - // nothing to do - return; - } - - dpy = _display; - scrn = _screen; - c.setDisplay(_display, _screen); - ct.setDisplay(_display, _screen); - lc.setDisplay(_display, _screen); - sc.setDisplay(_display, _screen); - bc.setDisplay(_display, _screen); -} - - -BTexture& BTexture::operator=(const BTexture &tt) { - c = tt.c; - ct = tt.ct; - lc = tt.lc; - sc = tt.sc; - bc = tt.bc; - descr = tt.descr; - t = tt.t; - dpy = tt.dpy; - scrn = tt.scrn; - ctrl = tt.ctrl; - - return *this; -} - - -Pixmap BTexture::render(const unsigned int width, const unsigned int height, - const Pixmap old) { - assert(display() != 0); - assert(texture() != BTexture::NoTexture); - - if (texture() == (BTexture::Flat | BTexture::Solid)) - return None; - if (texture() == BTexture::Parent_Relative) - return ParentRelative; - - if (screen() == ~(0u)) - scrn = DefaultScreen(display()->getXDisplay()); - - assert(ctrl != 0); - Pixmap ret = ctrl->renderImage(width, height, *this); - - if (old) - ctrl->removeImage(old); - - return ret; -} diff --git a/src/Texture.hh b/src/Texture.hh deleted file mode 100644 index fa6c6390..00000000 --- a/src/Texture.hh +++ /dev/null @@ -1,114 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Texture.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef TEXTURE_HH -#define TEXTURE_HH - -#include "Color.hh" -#include "Util.hh" -class BImageControl; - -#include - -class BTexture { -public: - enum Type { - // No texture - NoTexture = (0), - // bevel options - Flat = (1l<<0), - Sunken = (1l<<1), - Raised = (1l<<2), - // textures - Solid = (1l<<3), - Gradient = (1l<<4), - // gradients - Horizontal = (1l<<5), - Vertical = (1l<<6), - Diagonal = (1l<<7), - CrossDiagonal = (1l<<8), - Rectangle = (1l<<9), - Pyramid = (1l<<10), - PipeCross = (1l<<11), - Elliptic = (1l<<12), - // bevel types - Bevel1 = (1l<<13), - Bevel2 = (1l<<14), - // flat border - Border = (1l<<15), - // inverted image - Invert = (1l<<16), - // parent relative image - Parent_Relative = (1l<<17), - // fake interlaced image - Interlaced = (1l<<18) - }; - - BTexture(const BaseDisplay * const _display = 0, - unsigned int _screen = ~(0u), BImageControl* _ctrl = 0); - BTexture(const std::string &_description, - const BaseDisplay * const _display = 0, - unsigned int _screen = ~(0u), BImageControl* _ctrl = 0); - - void setColor(const BColor &_color); - void setColorTo(const BColor &_colorTo) { ct = _colorTo; } - void setBorderColor(const BColor &_borderColor) { bc = _borderColor; } - - const BColor &color(void) const { return c; } - const BColor &colorTo(void) const { return ct; } - const BColor &lightColor(void) const { return lc; } - const BColor &shadowColor(void) const { return sc; } - const BColor &borderColor(void) const { return bc; } - - unsigned long texture(void) const { return t; } - void setTexture(const unsigned long _texture) { t = _texture; } - void addTexture(const unsigned long _texture) { t |= _texture; } - - BTexture &operator=(const BTexture &tt); - inline bool operator==(const BTexture &tt) - { return (c == tt.c && ct == tt.ct && lc == tt.lc && - sc == tt.sc && t == tt.t); } - inline bool operator!=(const BTexture &tt) - { return (! operator==(tt)); } - - const BaseDisplay *display(void) const { return dpy; } - unsigned int screen(void) const { return scrn; } - void setDisplay(const BaseDisplay * const _display, - const unsigned int _screen); - void setImageControl(BImageControl* _ctrl) { ctrl = _ctrl; } - const std::string &description(void) const { return descr; } - void setDescription(const std::string &d); - - Pixmap render(const unsigned int width, const unsigned int height, - const Pixmap old = 0); - -private: - BColor c, ct, lc, sc, bc; - std::string descr; - unsigned long t; - const BaseDisplay *dpy; - BImageControl *ctrl; - unsigned int scrn; -}; - -#endif // TEXTURE_HH diff --git a/src/Timer.cc b/src/Timer.cc deleted file mode 100644 index 99f05ba9..00000000 --- a/src/Timer.cc +++ /dev/null @@ -1,111 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Timer.cc for Blackbox - An X11 Window Manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -#include "BaseDisplay.hh" -#include "Timer.hh" -#include "Util.hh" - -BTimer::BTimer(TimerQueueManager *m, TimeoutHandler *h) { - manager = m; - handler = h; - - recur = timing = False; -} - - -BTimer::~BTimer(void) { - if (timing) stop(); -} - - -void BTimer::setTimeout(long t) { - _timeout.tv_sec = t / 1000; - _timeout.tv_usec = t % 1000; - _timeout.tv_usec *= 1000; -} - - -void BTimer::setTimeout(const timeval &t) { - _timeout.tv_sec = t.tv_sec; - _timeout.tv_usec = t.tv_usec; -} - - -void BTimer::start(void) { - gettimeofday(&_start, 0); - - if (! timing) { - timing = True; - manager->addTimer(this); - } -} - - -void BTimer::stop(void) { - timing = False; - - manager->removeTimer(this); -} - - -void BTimer::halt(void) { - timing = False; -} - - -void BTimer::fireTimeout(void) { - if (handler) - handler->timeout(); -} - - -timeval BTimer::timeRemaining(const timeval &tm) const { - timeval ret = endpoint(); - - ret.tv_sec -= tm.tv_sec; - ret.tv_usec -= tm.tv_usec; - - return normalizeTimeval(ret); -} - - -timeval BTimer::endpoint(void) const { - timeval ret; - - ret.tv_sec = _start.tv_sec + _timeout.tv_sec; - ret.tv_usec = _start.tv_usec + _timeout.tv_usec; - - return normalizeTimeval(ret); -} - - -bool BTimer::shouldFire(const timeval &tm) const { - timeval end = endpoint(); - - return ! ((tm.tv_sec < end.tv_sec) || - (tm.tv_sec == end.tv_sec && tm.tv_usec < end.tv_usec)); -} diff --git a/src/Timer.hh b/src/Timer.hh deleted file mode 100644 index f13ad4dc..00000000 --- a/src/Timer.hh +++ /dev/null @@ -1,131 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Timer.hh for Blackbox - An X11 Window Manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef _BLACKBOX_Timer_hh -#define _BLACKBOX_Timer_hh - -extern "C" { -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else // !TIME_WITH_SYS_TIME -# ifdef HAVE_SYS_TIME_H -# include -# else // !HAVE_SYS_TIME_H -# include -# endif // HAVE_SYS_TIME_H -#endif // TIME_WITH_SYS_TIME -} - -// forward declaration -class TimerQueueManager; - -class TimeoutHandler { -public: - virtual void timeout(void) = 0; -}; - -class BTimer { -private: - TimerQueueManager *manager; - TimeoutHandler *handler; - bool timing, recur; - - timeval _start, _timeout; - - BTimer(const BTimer&); - BTimer& operator=(const BTimer&); - -public: - BTimer(TimerQueueManager *m, TimeoutHandler *h); - virtual ~BTimer(void); - - void fireTimeout(void); - - inline bool isTiming(void) const { return timing; } - inline bool isRecurring(void) const { return recur; } - - inline const timeval &getTimeout(void) const { return _timeout; } - inline const timeval &getStartTime(void) const { return _start; } - - timeval timeRemaining(const timeval &tm) const; - bool shouldFire(const timeval &tm) const; - timeval endpoint(void) const; - - inline void recurring(bool b) { recur = b; } - - void setTimeout(long t); - void setTimeout(const timeval &t); - - void start(void); // manager acquires timer - void stop(void); // manager releases timer - void halt(void); // halts the timer - - bool operator<(const BTimer& other) const - { return shouldFire(other.endpoint()); } -}; - - -#include -#include - -template -class _timer_queue: protected std::priority_queue<_Tp, _Sequence, _Compare> { -public: - typedef std::priority_queue<_Tp, _Sequence, _Compare> _Base; - - _timer_queue(void): _Base() {} - ~_timer_queue(void) {} - - void release(const _Tp& value) { - c.erase(std::remove(c.begin(), c.end(), value), c.end()); - // after removing the item we need to make the heap again - std::make_heap(c.begin(), c.end(), comp); - } - bool empty(void) const { return _Base::empty(); } - size_t size(void) const { return _Base::size(); } - void push(const _Tp& value) { _Base::push(value); } - void pop(void) { _Base::pop(); } - const _Tp& top(void) const { return _Base::top(); } -private: - // no copying! - _timer_queue(const _timer_queue&) {} - _timer_queue& operator=(const _timer_queue&) {} -}; - -struct TimerLessThan { - bool operator()(const BTimer* const l, const BTimer* const r) const { - return *r < *l; - } -}; - -#include -typedef _timer_queue, TimerLessThan> TimerQueue; - -class TimerQueueManager { -public: - virtual void addTimer(BTimer* timer) = 0; - virtual void removeTimer(BTimer* timer) = 0; -}; - -#endif // _BLACKBOX_Timer_hh diff --git a/src/Toolbar.cc b/src/Toolbar.cc deleted file mode 100644 index 587d3fd4..00000000 --- a/src/Toolbar.cc +++ /dev/null @@ -1,1236 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Toolbar.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H - -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else // !TIME_WITH_SYS_TIME -# ifdef HAVE_SYS_TIME_H -# include -# else // !HAVE_SYS_TIME_H -# include -# endif // HAVE_SYS_TIME_H -#endif // TIME_WITH_SYS_TIME -} - -#include -using std::string; - -#include "i18n.hh" -#include "blackbox.hh" -#include "Font.hh" -#include "GCCache.hh" -#include "Image.hh" -#include "Screen.hh" -#include "Toolbar.hh" -#include "Window.hh" -#include "Workspace.hh" -#include "Clientmenu.hh" -#include "Workspacemenu.hh" -#include "Slit.hh" - - -static long aMinuteFromNow(void) { - timeval now; - gettimeofday(&now, 0); - return ((60 - (now.tv_sec % 60)) * 1000); -} - - -Toolbar::Toolbar(BScreen *scrn) { - screen = scrn; - blackbox = screen->getBlackbox(); - toolbarstr = "session.screen" + itostring(screen->getScreenNumber()) + - ".toolbar."; - config = blackbox->getConfig(); - - load_rc(); - - // get the clock updating every minute - clock_timer = new BTimer(blackbox, this); - clock_timer->setTimeout(aMinuteFromNow()); - clock_timer->recurring(True); - clock_timer->start(); - frame.minute = frame.hour = -1; - - hide_handler.toolbar = this; - hide_timer = new BTimer(blackbox, &hide_handler); - hide_timer->setTimeout(blackbox->getAutoRaiseDelay()); - - editing = False; - new_name_pos = 0; - - toolbarmenu = new Toolbarmenu(this); - - display = blackbox->getXDisplay(); - XSetWindowAttributes attrib; - unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | - CWColormap | CWOverrideRedirect | CWEventMask; - attrib.background_pixmap = None; - attrib.background_pixel = attrib.border_pixel = - screen->getBorderColor()->pixel(); - attrib.colormap = screen->getColormap(); - attrib.override_redirect = True; - attrib.event_mask = ButtonPressMask | ButtonReleaseMask | - EnterWindowMask | LeaveWindowMask; - - frame.window = - XCreateWindow(display, screen->getRootWindow(), 0, 0, 1, 1, 0, - screen->getDepth(), InputOutput, screen->getVisual(), - create_mask, &attrib); - blackbox->saveToolbarSearch(frame.window, this); - - attrib.event_mask = ButtonPressMask | ButtonReleaseMask | ExposureMask | - KeyPressMask | EnterWindowMask; - - frame.workspace_label = - XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.workspace_label, this); - - frame.window_label = - XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.window_label, this); - - frame.clock = - XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.clock, this); - - frame.psbutton = - XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.psbutton, this); - - frame.nsbutton = - XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.nsbutton, this); - - frame.pwbutton = - XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.pwbutton, this); - - frame.nwbutton = - XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, &attrib); - blackbox->saveToolbarSearch(frame.nwbutton, this); - - frame.base = frame.label = frame.wlabel = frame.clk = frame.button = - frame.pbutton = None; - - reconfigure(); - mapToolbar(); -} - - -Toolbar::~Toolbar(void) { - unmapToolbar(); - - if (frame.base) screen->getImageControl()->removeImage(frame.base); - if (frame.label) screen->getImageControl()->removeImage(frame.label); - if (frame.wlabel) screen->getImageControl()->removeImage(frame.wlabel); - if (frame.clk) screen->getImageControl()->removeImage(frame.clk); - if (frame.button) screen->getImageControl()->removeImage(frame.button); - if (frame.pbutton) screen->getImageControl()->removeImage(frame.pbutton); - - blackbox->removeToolbarSearch(frame.window); - blackbox->removeToolbarSearch(frame.workspace_label); - blackbox->removeToolbarSearch(frame.window_label); - blackbox->removeToolbarSearch(frame.clock); - blackbox->removeToolbarSearch(frame.psbutton); - blackbox->removeToolbarSearch(frame.nsbutton); - blackbox->removeToolbarSearch(frame.pwbutton); - blackbox->removeToolbarSearch(frame.nwbutton); - - XDestroyWindow(display, frame.workspace_label); - XDestroyWindow(display, frame.window_label); - XDestroyWindow(display, frame.clock); - - XDestroyWindow(display, frame.window); - - delete hide_timer; - delete clock_timer; - delete toolbarmenu; -} - - -void Toolbar::mapToolbar() { - if (!screen->doHideToolbar()) { - //not hidden, so windows should not maximize over the toolbar - XMapSubwindows(display, frame.window); - XMapWindow(display, frame.window); - } - screen->addStrut(&strut); - updateStrut(); -} - - -void Toolbar::unmapToolbar() { - if (toolbarmenu->isVisible()) - toolbarmenu->hide(); - //hidden so we can maximize over the toolbar - screen->removeStrut(&strut); - screen->updateAvailableArea(); - - XUnmapWindow(display, frame.window); - updateStrut(); -} - - -void Toolbar::saveOnTop(bool b) { - on_top = b; - config->setValue(toolbarstr + "onTop", on_top); -} - - -void Toolbar::saveAutoHide(bool b) { - do_auto_hide = b; - config->setValue(toolbarstr + "autoHide", do_auto_hide); -} - - -void Toolbar::saveWidthPercent(unsigned int w) { - width_percent = w; - config->setValue(toolbarstr + "widthPercent", width_percent); -} - - -void Toolbar::savePlacement(int p) { - placement = p; - const char *pname; - switch (placement) { - case TopLeft: pname = "TopLeft"; break; - case BottomLeft: pname = "BottomLeft"; break; - case TopCenter: pname = "TopCenter"; break; - case TopRight: pname = "TopRight"; break; - case BottomRight: pname = "BottomRight"; break; - case BottomCenter: default: pname = "BottomCenter"; break; - } - config->setValue(toolbarstr + "placement", pname); -} - - -void Toolbar::save_rc(void) { - saveOnTop(on_top); - saveAutoHide(do_auto_hide); - saveWidthPercent(width_percent); - savePlacement(placement); -} - - -void Toolbar::load_rc(void) { - string s; - - if (! config->getValue(toolbarstr + "onTop", on_top)) - on_top = false; - - if (! config->getValue(toolbarstr + "autoHide", do_auto_hide)) - do_auto_hide = false; - hidden = do_auto_hide; - - if (! config->getValue(toolbarstr + "widthPercent", width_percent) || - width_percent == 0 || width_percent > 100) - width_percent = 66; - - if (config->getValue(toolbarstr + "placement", s)) { - if (s == "TopLeft") - placement = TopLeft; - else if (s == "BottomLeft") - placement = BottomLeft; - else if (s == "TopCenter") - placement = TopCenter; - else if (s == "TopRight") - placement = TopRight; - else if (s == "BottomRight") - placement = BottomRight; - else //if (s == "BottomCenter") - placement = BottomCenter; - } else - placement = BottomCenter; -} - - -void Toolbar::reconfigure(void) { - unsigned int width, height; - - width = (screen->getWidth() * width_percent) / 100; - height = screen->getToolbarStyle()->font->height(); - - frame.bevel_w = screen->getBevelWidth(); - frame.button_w = height; - height += 2; - frame.label_h = height; - height += (frame.bevel_w * 2); - - frame.rect.setSize(width, height); - - int x, y; - switch (placement) { - case TopLeft: - case TopRight: - case TopCenter: - if (placement == TopLeft) - x = 0; - else if (placement == TopRight) - x = screen->getWidth() - frame.rect.width() - - (screen->getBorderWidth() * 2); - else - x = (screen->getWidth() - frame.rect.width()) / 2; - - y = 0; - - frame.x_hidden = x; - frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() - - frame.rect.height(); - break; - - case BottomLeft: - case BottomRight: - case BottomCenter: - default: - if (placement == BottomLeft) - x = 0; - else if (placement == BottomRight) - x = screen->getWidth() - frame.rect.width() - - (screen->getBorderWidth() * 2); - else - x = (screen->getWidth() - frame.rect.width()) / 2; - - y = screen->getHeight() - frame.rect.height() - - (screen->getBorderWidth() * 2); - - frame.x_hidden = x; - frame.y_hidden = screen->getHeight() - screen->getBevelWidth() - - screen->getBorderWidth(); - break; - } - - frame.rect.setPos(x, y); - - updateStrut(); - -#ifdef HAVE_STRFTIME - time_t ttmp = time(NULL); - - frame.clock_w = 0; - if (ttmp != -1) { - struct tm *tt = localtime(&ttmp); - if (tt) { - char t[1024]; - int len = strftime(t, 1024, screen->getStrftimeFormat(), tt); - if (len == 0) { // invalid time format found - screen->saveStrftimeFormat("%I:%M %p"); // so use the default - strftime(t, 1024, screen->getStrftimeFormat(), tt); - } - // find the length of the rendered string and add room for two extra - // characters to it. This allows for variable width output of the fonts - BFont *font = screen->getToolbarStyle()->font; - frame.clock_w = font->measureString(t) + font->maxCharWidth() * 2; - } - } -#else // !HAVE_STRFTIME - { - string s = i18n(ToolbarSet, ToolbarNoStrftimeLength, "00:00000"); - frame.clock_w = screen->getToolbarStyle()->font->measureString(s); - } -#endif // HAVE_STRFTIME - - frame.workspace_label_w = 0; - - for (unsigned int i = 0; i < screen->getWorkspaceCount(); i++) { - const string& workspace_name = screen->getWorkspace(i)->getName(); - width = screen->getToolbarStyle()->font->measureString(workspace_name); - if (width > frame.workspace_label_w) frame.workspace_label_w = width; - } - - frame.workspace_label_w = frame.clock_w = - std::max(frame.workspace_label_w, frame.clock_w) + (frame.bevel_w * 4); - - // XXX: where'd the +6 come from? - frame.window_label_w = - (frame.rect.width() - (frame.clock_w + (frame.button_w * 4) + - frame.workspace_label_w + (frame.bevel_w * 8) + 6)); - - if (hidden) { - XMoveResizeWindow(display, frame.window, frame.x_hidden, frame.y_hidden, - frame.rect.width(), frame.rect.height()); - } else { - XMoveResizeWindow(display, frame.window, frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height()); - } - - XMoveResizeWindow(display, frame.workspace_label, frame.bevel_w, - frame.bevel_w, frame.workspace_label_w, - frame.label_h); - XMoveResizeWindow(display, frame.psbutton, - ((frame.bevel_w * 2) + frame.workspace_label_w + 1), - frame.bevel_w + 1, frame.button_w, frame.button_w); - XMoveResizeWindow(display, frame.nsbutton, - ((frame.bevel_w * 3) + frame.workspace_label_w + - frame.button_w + 2), frame.bevel_w + 1, frame.button_w, - frame.button_w); - XMoveResizeWindow(display, frame.window_label, - ((frame.bevel_w * 4) + (frame.button_w * 2) + - frame.workspace_label_w + 3), frame.bevel_w, - frame.window_label_w, frame.label_h); - XMoveResizeWindow(display, frame.pwbutton, - ((frame.bevel_w * 5) + (frame.button_w * 2) + - frame.workspace_label_w + frame.window_label_w + 4), - frame.bevel_w + 1, frame.button_w, frame.button_w); - XMoveResizeWindow(display, frame.nwbutton, - ((frame.bevel_w * 6) + (frame.button_w * 3) + - frame.workspace_label_w + frame.window_label_w + 5), - frame.bevel_w + 1, frame.button_w, frame.button_w); - XMoveResizeWindow(display, frame.clock, - frame.rect.width() - frame.clock_w - (frame.bevel_w * 2), - frame.bevel_w, frame.clock_w, frame.label_h); - - ToolbarStyle *style = screen->getToolbarStyle(); - frame.base = style->toolbar.render(frame.rect.width(), frame.rect.height(), - frame.base); - if (! frame.base) - XSetWindowBackground(display, frame.window, - style->toolbar.color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.window, frame.base); - - frame.label = style->window.render(frame.window_label_w, frame.label_h, - frame.label); - if (! frame.label) - XSetWindowBackground(display, frame.window_label, - style->window.color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.window_label, frame.label); - - frame.wlabel = style->label.render(frame.workspace_label_w, frame.label_h, - frame.wlabel); - if (! frame.wlabel) - XSetWindowBackground(display, frame.workspace_label, - style->label.color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel); - - frame.clk = style->clock.render(frame.clock_w, frame.label_h, frame.clk); - if (! frame.clk) - XSetWindowBackground(display, frame.clock, style->clock.color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.clock, frame.clk); - - frame.button = style->button.render(frame.button_w, frame.button_w, - frame.button); - if (! frame.button) { - frame.button_pixel = style->button.color().pixel(); - XSetWindowBackground(display, frame.psbutton, frame.button_pixel); - XSetWindowBackground(display, frame.nsbutton, frame.button_pixel); - XSetWindowBackground(display, frame.pwbutton, frame.button_pixel); - XSetWindowBackground(display, frame.nwbutton, frame.button_pixel); - } else { - XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button); - XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button); - XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button); - XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button); - } - - frame.pbutton = style->pressed.render(frame.button_w, frame.button_w, - frame.pbutton); - if (! frame.pbutton) - frame.pbutton_pixel = style->pressed.color().pixel(); - - XSetWindowBorder(display, frame.window, - screen->getBorderColor()->pixel()); - XSetWindowBorderWidth(display, frame.window, screen->getBorderWidth()); - - XClearWindow(display, frame.window); - XClearWindow(display, frame.workspace_label); - XClearWindow(display, frame.window_label); - XClearWindow(display, frame.clock); - XClearWindow(display, frame.psbutton); - XClearWindow(display, frame.nsbutton); - XClearWindow(display, frame.pwbutton); - XClearWindow(display, frame.nwbutton); - - redrawWindowLabel(); - redrawWorkspaceLabel(); - redrawPrevWorkspaceButton(); - redrawNextWorkspaceButton(); - redrawPrevWindowButton(); - redrawNextWindowButton(); - checkClock(True); - - toolbarmenu->reconfigure(); -} - - -void Toolbar::updateStrut(void) { - // left and right are always 0 - strut.top = strut.bottom = 0; - - // when hidden only one border is visible - unsigned int border_width = screen->getBorderWidth(); - if (! do_auto_hide) - border_width *= 2; - - if (! screen->doHideToolbar()) { - switch(placement) { - case TopLeft: - case TopCenter: - case TopRight: - strut.top = getExposedHeight() + border_width; - break; - default: - strut.bottom = getExposedHeight() + border_width; - } - } - - screen->updateAvailableArea(); -} - - -#ifdef HAVE_STRFTIME -void Toolbar::checkClock(bool redraw) { -#else // !HAVE_STRFTIME -void Toolbar::checkClock(bool redraw, bool date) { -#endif // HAVE_STRFTIME - time_t tmp = 0; - struct tm *tt = 0; - - if ((tmp = time(NULL)) != -1) { - if (! (tt = localtime(&tmp))) return; - if (tt->tm_min != frame.minute || tt->tm_hour != frame.hour) { - frame.hour = tt->tm_hour; - frame.minute = tt->tm_min; - XClearWindow(display, frame.clock); - redraw = True; - } - } - - if (redraw) { -#ifdef HAVE_STRFTIME - char t[1024]; - if (! strftime(t, 1024, screen->getStrftimeFormat(), tt)) - return; -#else // !HAVE_STRFTIME - char t[9]; - if (date) { - // format the date... with special consideration for y2k ;) - if (screen->getDateFormat() == Blackbox::B_EuropeanDate) - sprintf(t, 18n(ToolbarSet, ToolbarNoStrftimeDateFormatEu, - "%02d.%02d.%02d"), - tt->tm_mday, tt->tm_mon + 1, - (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year); - else - sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeDateFormat, - "%02d/%02d/%02d"), - tt->tm_mon + 1, tt->tm_mday, - (tt->tm_year >= 100) ? tt->tm_year - 100 : tt->tm_year); - } else { - if (screen->isClock24Hour()) - sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeTimeFormat24, - " %02d:%02d "), - frame.hour, frame.minute); - else - sprintf(t, i18n(ToolbarSet, ToolbarNoStrftimeTimeFormat12, - "%02d:%02d %sm"), - ((frame.hour > 12) ? frame.hour - 12 : - ((frame.hour == 0) ? 12 : frame.hour)), frame.minute, - ((frame.hour >= 12) ? - i18n(ToolbarSet, ToolbarNoStrftimeTimeFormatP, "p") : - i18n(ToolbarSet, ToolbarNoStrftimeTimeFormatA, "a"))); - } -#endif // HAVE_STRFTIME - - ToolbarStyle *style = screen->getToolbarStyle(); - - int pos = frame.bevel_w * 2; // this is modified by doJustify() - style->doJustify(t, pos, frame.clock_w, frame.bevel_w * 4); - -#ifdef XFT - XClearWindow(display, frame.clock); -#endif // XFT - - style->font->drawString(frame.clock, pos, 1, style->c_text, t); - } -} - - -void Toolbar::redrawWindowLabel(bool redraw) { - BlackboxWindow *foc = screen->getBlackbox()->getFocusedWindow(); - if (! foc) { - XClearWindow(display, frame.window_label); - return; - } - -#ifdef XFT - redraw = true; -#endif // XFT - - if (redraw) - XClearWindow(display, frame.window_label); - - if (foc->getScreen() != screen) return; - - const char *title = foc->getTitle(); - ToolbarStyle *style = screen->getToolbarStyle(); - - int pos = frame.bevel_w * 2; // modified by doJustify() - style->doJustify(title, pos, frame.window_label_w, frame.bevel_w * 4); - style->font->drawString(frame.window_label, pos, 1, style->w_text, title); -} - - -void Toolbar::redrawWorkspaceLabel(bool redraw) { - const string& name = screen->getCurrentWorkspace()->getName(); - -#ifdef XFT - redraw = true; -#endif // XFT - - if (redraw) - XClearWindow(display, frame.workspace_label); - - ToolbarStyle *style = screen->getToolbarStyle(); - - int pos = frame.bevel_w * 2; - style->doJustify(name.c_str(), pos, frame.workspace_label_w, - frame.bevel_w * 4); - style->font->drawString(frame.workspace_label, pos, 1, style->l_text, name); -} - - -void Toolbar::drawArrow(Drawable surface, bool left) const { - ToolbarStyle *style = screen->getToolbarStyle(); - - BPen pen(style->b_pic); - - int hh = frame.button_w / 2, hw = frame.button_w / 2; - XPoint pts[3]; - const int bullet_size = 3; - - - if (left) { -#ifdef BITMAPBUTTONS - if (style->left_button.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), style->left_button.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - style->left_button.w)/2, - (frame.button_w - style->left_button.h)/2); - - XFillRectangle(blackbox->getXDisplay(), surface, pen.gc(), - (frame.button_w - style->left_button.w)/2, - (frame.button_w - style->left_button.h)/2, - style->left_button.w, style->left_button.h); - - XSetClipMask(blackbox->getXDisplay(), pen.gc(), None); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0); - } else { -#endif // BITMAPBUTTONS - pts[0].x = hw - bullet_size; - pts[0].y = hh; - pts[1].x = 2 * bullet_size; - pts[1].y = bullet_size; - pts[2].x = 0; - pts[2].y = -(2 * bullet_size); - XFillPolygon(display, surface, pen.gc(), pts, 3, Convex, - CoordModePrevious); -#ifdef BITMAPBUTTONS - } -#endif // BITMAPBUTTONS - } else { -#ifdef BITMAPBUTTONS - if (style->right_button.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), - style->right_button.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - style->right_button.w)/2, - (frame.button_w - style->right_button.h)/2); - - XFillRectangle(blackbox->getXDisplay(), surface, pen.gc(), - (frame.button_w - style->right_button.w)/2, - (frame.button_w - style->right_button.h)/2, - (frame.button_w + style->right_button.w)/2, - (frame.button_w + style->right_button.h)/2); - - XSetClipMask(blackbox->getXDisplay(), pen.gc(), None); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0); - } else { -#endif // BITMAPBUTTONS - pts[0].x = hw - bullet_size; - pts[0].y = hh - bullet_size; - pts[1].x = (2 * bullet_size); - pts[1].y = bullet_size; - pts[2].x = -(2 * bullet_size); - pts[2].y = bullet_size; - XFillPolygon(display, surface, pen.gc(), pts, 3, Convex, - CoordModePrevious); -#ifdef BITMAPBUTTONS - } -#endif - } -} - - -void Toolbar::redrawPrevWorkspaceButton(bool pressed, bool redraw) { - if (redraw) { - if (pressed) { - if (frame.pbutton) - XSetWindowBackgroundPixmap(display, frame.psbutton, frame.pbutton); - else - XSetWindowBackground(display, frame.psbutton, frame.pbutton_pixel); - } else { - if (frame.button) - XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button); - else - XSetWindowBackground(display, frame.psbutton, frame.button_pixel); - } - XClearWindow(display, frame.psbutton); - } - - drawArrow(frame.psbutton, True); -} - - -void Toolbar::redrawNextWorkspaceButton(bool pressed, bool redraw) { - if (redraw) { - if (pressed) { - if (frame.pbutton) - XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.pbutton); - else - XSetWindowBackground(display, frame.nsbutton, frame.pbutton_pixel); - } else { - if (frame.button) - XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button); - else - XSetWindowBackground(display, frame.nsbutton, frame.button_pixel); - } - XClearWindow(display, frame.nsbutton); - } - - drawArrow(frame.nsbutton, False); -} - - -void Toolbar::redrawPrevWindowButton(bool pressed, bool redraw) { - if (redraw) { - if (pressed) { - if (frame.pbutton) - XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.pbutton); - else - XSetWindowBackground(display, frame.pwbutton, frame.pbutton_pixel); - } else { - if (frame.button) - XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button); - else - XSetWindowBackground(display, frame.pwbutton, frame.button_pixel); - } - XClearWindow(display, frame.pwbutton); - } - - drawArrow(frame.pwbutton, True); -} - - -void Toolbar::redrawNextWindowButton(bool pressed, bool redraw) { - if (redraw) { - if (pressed) { - if (frame.pbutton) - XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.pbutton); - else - XSetWindowBackground(display, frame.nwbutton, frame.pbutton_pixel); - } else { - if (frame.button) - XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button); - else - XSetWindowBackground(display, frame.nwbutton, frame.button_pixel); - } - XClearWindow(display, frame.nwbutton); - } - - drawArrow(frame.nwbutton, False); -} - - -void Toolbar::edit(void) { - Window window; - int foo; - - editing = True; - XGetInputFocus(display, &window, &foo); - if (window == frame.workspace_label) - return; - - XSetInputFocus(display, frame.workspace_label, - RevertToPointerRoot, CurrentTime); - XClearWindow(display, frame.workspace_label); - - blackbox->setNoFocus(True); - if (blackbox->getFocusedWindow()) - blackbox->getFocusedWindow()->setFocusFlag(False); - - ToolbarStyle *style = screen->getToolbarStyle(); - BPen pen(style->l_text); - XDrawRectangle(display, frame.workspace_label, pen.gc(), - frame.workspace_label_w / 2, 0, 1, - frame.label_h - 1); - // change the background of the window to that of an active window label - BTexture *texture = &(screen->getWindowStyle()->l_focus); - frame.wlabel = texture->render(frame.workspace_label_w, frame.label_h, - frame.wlabel); - if (! frame.wlabel) - XSetWindowBackground(display, frame.workspace_label, - texture->color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel); -} - - -void Toolbar::buttonPressEvent(const XButtonEvent *be) { - if (be->button == 1) { - if (be->window == frame.psbutton) - redrawPrevWorkspaceButton(True, True); - else if (be->window == frame.nsbutton) - redrawNextWorkspaceButton(True, True); - else if (be->window == frame.pwbutton) - redrawPrevWindowButton(True, True); - else if (be->window == frame.nwbutton) - redrawNextWindowButton(True, True); -#ifndef HAVE_STRFTIME - else if (be->window == frame.clock) { - XClearWindow(display, frame.clock); - checkClock(True, True); - } -#endif // HAVE_STRFTIME - else if (! on_top) { - Window w[1] = { frame.window }; - screen->raiseWindows(w, 1); - } - } else if (be->button == 2 && (! on_top)) { - XLowerWindow(display, frame.window); - } else if (be->button == 3) { - if (toolbarmenu->isVisible()) { - toolbarmenu->hide(); - } else { - int x, y; - - x = be->x_root - (toolbarmenu->getWidth() / 2); - y = be->y_root - (toolbarmenu->getHeight() / 2); - - if (x < 0) - x = 0; - else if (x + toolbarmenu->getWidth() > screen->getWidth()) - x = screen->getWidth() - toolbarmenu->getWidth(); - - if (y < 0) - y = 0; - else if (y + toolbarmenu->getHeight() > screen->getHeight()) - y = screen->getHeight() - toolbarmenu->getHeight(); - - toolbarmenu->move(x, y); - toolbarmenu->show(); - } - } -} - - - -void Toolbar::buttonReleaseEvent(const XButtonEvent *re) { - if (re->button == 1) { - if (re->window == frame.psbutton) { - redrawPrevWorkspaceButton(False, True); - - if (re->x >= 0 && re->x < static_cast(frame.button_w) && - re->y >= 0 && re->y < static_cast(frame.button_w)) - if (screen->getCurrentWorkspace()->getID() > 0) - screen->changeWorkspaceID(screen->getCurrentWorkspace()-> - getID() - 1); - else - screen->changeWorkspaceID(screen->getWorkspaceCount() - 1); - } else if (re->window == frame.nsbutton) { - redrawNextWorkspaceButton(False, True); - - if (re->x >= 0 && re->x < static_cast(frame.button_w) && - re->y >= 0 && re->y < static_cast(frame.button_w)) - if (screen->getCurrentWorkspace()->getID() < - (screen->getWorkspaceCount() - 1)) - screen->changeWorkspaceID(screen->getCurrentWorkspace()-> - getID() + 1); - else - screen->changeWorkspaceID(0); - } else if (re->window == frame.pwbutton) { - redrawPrevWindowButton(False, True); - - if (re->x >= 0 && re->x < static_cast(frame.button_w) && - re->y >= 0 && re->y < static_cast(frame.button_w)) - screen->prevFocus(); - } else if (re->window == frame.nwbutton) { - redrawNextWindowButton(False, True); - - if (re->x >= 0 && re->x < static_cast(frame.button_w) && - re->y >= 0 && re->y < static_cast(frame.button_w)) - screen->nextFocus(); - } else if (re->window == frame.window_label) - screen->raiseFocus(); -#ifndef HAVE_STRFTIME - else if (re->window == frame.clock) { - XClearWindow(display, frame.clock); - checkClock(True); - } -#endif // HAVE_STRFTIME - } -} - - -void Toolbar::enterNotifyEvent(const XCrossingEvent *) { - if (! do_auto_hide) - return; - - if (hidden) { - if (! hide_timer->isTiming()) hide_timer->start(); - } else { - if (hide_timer->isTiming()) hide_timer->stop(); - } -} - -void Toolbar::leaveNotifyEvent(const XCrossingEvent *) { - if (! do_auto_hide) - return; - - if (hidden) { - if (hide_timer->isTiming()) hide_timer->stop(); - } else if (! toolbarmenu->isVisible()) { - if (! hide_timer->isTiming()) hide_timer->start(); - } -} - - -void Toolbar::exposeEvent(const XExposeEvent *ee) { - if (ee->window == frame.clock) checkClock(True); - else if (ee->window == frame.workspace_label && (! editing)) - redrawWorkspaceLabel(); - else if (ee->window == frame.window_label) redrawWindowLabel(); - else if (ee->window == frame.psbutton) redrawPrevWorkspaceButton(); - else if (ee->window == frame.nsbutton) redrawNextWorkspaceButton(); - else if (ee->window == frame.pwbutton) redrawPrevWindowButton(); - else if (ee->window == frame.nwbutton) redrawNextWindowButton(); -} - - -void Toolbar::keyPressEvent(const XKeyEvent *ke) { - if (ke->window == frame.workspace_label && editing) { - if (new_workspace_name.empty()) { - new_name_pos = 0; - } - - KeySym ks; - char keychar[1]; - XLookupString(const_cast(ke), keychar, 1, &ks, 0); - - // either we are told to end with a return or we hit 127 chars - if (ks == XK_Return || new_name_pos == 127) { - editing = False; - - blackbox->setNoFocus(False); - if (blackbox->getFocusedWindow()) - blackbox->getFocusedWindow()->setInputFocus(); - else - blackbox->setFocusedWindow(0); - - // the toolbar will be reconfigured when the change to the workspace name - // gets caught in the PropertyNotify event handler - screen->getCurrentWorkspace()->setName(new_workspace_name); - - new_workspace_name.erase(); - new_name_pos = 0; - - // reset the background to that of the workspace label (its normal - // setting) - BTexture *texture = &(screen->getToolbarStyle()->label); - frame.wlabel = texture->render(frame.workspace_label_w, frame.label_h, - frame.wlabel); - if (! frame.wlabel) - XSetWindowBackground(display, frame.workspace_label, - texture->color().pixel()); - else - XSetWindowBackgroundPixmap(display, frame.workspace_label, - frame.wlabel); - } else if (! (ks == XK_Shift_L || ks == XK_Shift_R || - ks == XK_Control_L || ks == XK_Control_R || - ks == XK_Caps_Lock || ks == XK_Shift_Lock || - ks == XK_Meta_L || ks == XK_Meta_R || - ks == XK_Alt_L || ks == XK_Alt_R || - ks == XK_Super_L || ks == XK_Super_R || - ks == XK_Hyper_L || ks == XK_Hyper_R)) { - if (ks == XK_BackSpace) { - if (new_name_pos > 0) { - --new_name_pos; - new_workspace_name.erase(new_name_pos); - } else { - new_workspace_name.resize(0); - } - } else { - new_workspace_name += (*keychar); - ++new_name_pos; - } - - XClearWindow(display, frame.workspace_label); - unsigned int tw, x; - - tw = screen->getToolbarStyle()->font->measureString(new_workspace_name); - x = (frame.workspace_label_w - tw) / 2; - - if (x < frame.bevel_w) x = frame.bevel_w; - - ToolbarStyle *style = screen->getToolbarStyle(); - style->font->drawString(frame.workspace_label, x, 1, style->l_text, - new_workspace_name); - BPen pen(style->l_text); - XDrawRectangle(display, frame.workspace_label, pen.gc(), x + tw, 0, 1, - frame.label_h - 1); - } - } -} - - -void Toolbar::timeout(void) { - checkClock(True); - - clock_timer->setTimeout(aMinuteFromNow()); -} - - -void Toolbar::HideHandler::timeout(void) { - toolbar->hidden = ! toolbar->hidden; - if (toolbar->hidden) - XMoveWindow(toolbar->display, toolbar->frame.window, - toolbar->frame.x_hidden, toolbar->frame.y_hidden); - else - XMoveWindow(toolbar->display, toolbar->frame.window, - toolbar->frame.rect.x(), toolbar->frame.rect.y()); -} - - -void Toolbar::toggleAutoHide(void) { - saveAutoHide(! doAutoHide()); - - updateStrut(); - screen->getSlit()->reposition(); - - if (do_auto_hide == False && hidden) { - // force the slit to be visible - if (hide_timer->isTiming()) hide_timer->stop(); - hide_handler.timeout(); - } -} - - -Toolbarmenu::Toolbarmenu(Toolbar *tb) : Basemenu(tb->screen) { - toolbar = tb; - - setLabel(i18n(ToolbarSet, ToolbarToolbarTitle, "Toolbar")); - setInternalMenu(); - - placementmenu = new Placementmenu(this); - - insert(i18n(CommonSet, CommonPlacementTitle, "Placement"), - placementmenu); - insert(i18n(CommonSet, CommonAlwaysOnTop, "Always on top"), 1); - insert(i18n(CommonSet, CommonAutoHide, "Auto hide"), 2); - insert(i18n(ToolbarSet, ToolbarEditWkspcName, - "Edit current workspace name"), 3); - - update(); - setValues(); -} - - -void Toolbarmenu::setValues() { - setItemSelected(1, toolbar->isOnTop()); - setItemSelected(2, toolbar->doAutoHide()); -} - - -Toolbarmenu::~Toolbarmenu(void) { - delete placementmenu; -} - - -void Toolbarmenu::itemSelected(int button, unsigned int index) { - if (button != 1) - return; - - BasemenuItem *item = find(index); - if (! item) return; - - switch (item->function()) { - case 1: { // always on top - toolbar->saveOnTop(! toolbar->isOnTop()); - setItemSelected(1, toolbar->isOnTop()); - - if (toolbar->isOnTop()) getScreen()->raiseWindows((Window *) 0, 0); - break; - } - - case 2: { // auto hide - toolbar->toggleAutoHide(); - setItemSelected(2, toolbar->doAutoHide()); - - break; - } - - case 3: { // edit current workspace name - toolbar->edit(); - hide(); - - break; - } - } // switch -} - - -void Toolbarmenu::internal_hide(void) { - Basemenu::internal_hide(); - if (toolbar->doAutoHide() && ! toolbar->isEditing()) - toolbar->hide_handler.timeout(); -} - - -void Toolbarmenu::reconfigure(void) { - setValues(); - placementmenu->reconfigure(); - - Basemenu::reconfigure(); -} - - -Toolbarmenu::Placementmenu::Placementmenu(Toolbarmenu *tm) - : Basemenu(tm->toolbar->screen), toolbar(tm->toolbar) { - setLabel(i18n(ToolbarSet, ToolbarToolbarPlacement, "Toolbar Placement")); - setInternalMenu(); - setMinimumSublevels(3); - - insert(i18n(CommonSet, CommonPlacementTopLeft, "Top Left"), - Toolbar::TopLeft); - insert(i18n(CommonSet, CommonPlacementBottomLeft, "Bottom Left"), - Toolbar::BottomLeft); - insert(i18n(CommonSet, CommonPlacementTopCenter, "Top Center"), - Toolbar::TopCenter); - insert(i18n(CommonSet, CommonPlacementBottomCenter, "Bottom Center"), - Toolbar::BottomCenter); - insert(i18n(CommonSet, CommonPlacementTopRight, "Top Right"), - Toolbar::TopRight); - insert(i18n(CommonSet, CommonPlacementBottomRight, "Bottom Right"), - Toolbar::BottomRight); - update(); - setValues(); -} - - -void Toolbarmenu::Placementmenu::setValues(void) { - int place = 0; - switch (toolbar->getPlacement()) { - case Toolbar::BottomRight: - place++; - case Toolbar::TopRight: - place++; - case Toolbar::BottomCenter: - place++; - case Toolbar::TopCenter: - place++; - case Toolbar::BottomLeft: - place++; - case Toolbar::TopLeft: - break; - } - setItemSelected(0, 0 == place); - setItemSelected(1, 1 == place); - setItemSelected(2, 2 == place); - setItemSelected(3, 3 == place); - setItemSelected(4, 4 == place); - setItemSelected(5, 5 == place); -} - - -void Toolbarmenu::Placementmenu::reconfigure(void) { - setValues(); - Basemenu::reconfigure(); -} - - -void Toolbarmenu::Placementmenu::itemSelected(int button, unsigned int index) { - if (button != 1) - return; - - BasemenuItem *item = find(index); - if (! item) return; - - toolbar->savePlacement(item->function()); - hide(); - toolbar->reconfigure(); - - // reposition the slit as well to make sure it doesn't intersect the - // toolbar - getScreen()->getSlit()->reposition(); -} - - -void ToolbarStyle::doJustify(const std::string &text, int &start_pos, - unsigned int max_length, - unsigned int modifier) const { - size_t text_len = text.size(); - unsigned int length; - - do { - length = font->measureString(string(text, 0, text_len)) + modifier; - } while (length > max_length && text_len-- > 0); - - switch (justify) { - case RightJustify: - start_pos += max_length - length; - break; - - case CenterJustify: - start_pos += (max_length - length) / 2; - break; - - case LeftJustify: - default: - break; - } -} diff --git a/src/Toolbar.hh b/src/Toolbar.hh deleted file mode 100644 index 45464e77..00000000 --- a/src/Toolbar.hh +++ /dev/null @@ -1,197 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// Toolbar.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Toolbar_hh -#define __Toolbar_hh - -extern "C" { -#include -} - -#include "Screen.hh" -#include "Basemenu.hh" -#include "Timer.hh" - -// forward declaration -class Toolbar; - -class Toolbarmenu : public Basemenu { -private: - class Placementmenu : public Basemenu { - private: - Placementmenu(const Placementmenu&); - Placementmenu& operator=(const Placementmenu&); - Toolbar *toolbar; - - protected: - virtual void itemSelected(int button, unsigned int index); - virtual void setValues(void); - - public: - Placementmenu(Toolbarmenu *tm); - virtual void reconfigure(void); - }; - - Toolbar *toolbar; - Placementmenu *placementmenu; - - friend class Placementmenu; - friend class Toolbar; - - Toolbarmenu(const Toolbarmenu&); - Toolbarmenu& operator=(const Toolbarmenu&); - -protected: - virtual void itemSelected(int button, unsigned int index); - virtual void internal_hide(void); - virtual void setValues(void); - -public: - Toolbarmenu(Toolbar *tb); - ~Toolbarmenu(void); - - inline Basemenu *getPlacementmenu(void) { return placementmenu; } - - virtual void reconfigure(void); -}; - - -class Toolbar : public TimeoutHandler { -private: - bool on_top, editing, hidden, do_auto_hide; - unsigned int width_percent; - int placement; - std::string toolbarstr; - Display *display; - - struct ToolbarFrame { - unsigned long button_pixel, pbutton_pixel; - Pixmap base, label, wlabel, clk, button, pbutton; - Window window, workspace_label, window_label, clock, psbutton, nsbutton, - pwbutton, nwbutton; - - int x_hidden, y_hidden, hour, minute; - unsigned int window_label_w, workspace_label_w, clock_w, - button_w, bevel_w, label_h; - - Rect rect; - } frame; - - class HideHandler : public TimeoutHandler { - public: - Toolbar *toolbar; - - virtual void timeout(void); - } hide_handler; - - Blackbox *blackbox; - BScreen *screen; - Configuration *config; - BTimer *clock_timer, *hide_timer; - Toolbarmenu *toolbarmenu; - Strut strut; - - std::string new_workspace_name; - size_t new_name_pos; - - friend class HideHandler; - friend class Toolbarmenu; - friend class Toolbarmenu::Placementmenu; - - void drawArrow(Drawable surface, bool left) const; - void redrawPrevWorkspaceButton(bool pressed = False, bool redraw = False); - void redrawNextWorkspaceButton(bool pressed = False, bool redraw = False); - void redrawPrevWindowButton(bool preseed = False, bool redraw = False); - void redrawNextWindowButton(bool preseed = False, bool redraw = False); - - void updateStrut(void); - -#ifdef HAVE_STRFTIME - void checkClock(bool redraw = False); -#else // HAVE_STRFTIME - void checkClock(bool redraw = False, bool date = False); -#endif // HAVE_STRFTIME - - Toolbar(const Toolbar&); - Toolbar& operator=(const Toolbar&); - -public: - Toolbar(BScreen *scrn); - virtual ~Toolbar(void); - - inline Toolbarmenu *getMenu(void) { return toolbarmenu; } - - inline bool isEditing(void) const { return editing; } - inline bool isOnTop(void) const { return on_top; } - inline bool isHidden(void) const { return hidden; } - inline bool doAutoHide(void) const { return do_auto_hide; } - inline unsigned int getWidthPercent(void) const { return width_percent; } - inline int getPlacement(void) const { return placement; } - - void saveOnTop(bool); - void saveAutoHide(bool); - void saveWidthPercent(unsigned int); - void savePlacement(int); - - void save_rc(void); - void load_rc(void); - - void mapToolbar(void); - void unmapToolbar(void); - - inline Window getWindowID(void) const { return frame.window; } - - inline const Rect& getRect(void) const { return frame.rect; } - inline unsigned int getWidth(void) const { return frame.rect.width(); } - inline unsigned int getHeight(void) const { return frame.rect.height(); } - inline unsigned int getExposedHeight(void) const - { return (screen->doHideToolbar() ? 0 : - ((do_auto_hide) ? frame.bevel_w : - frame.rect.height())); } - inline int getX(void) const - { return ((hidden) ? frame.x_hidden : frame.rect.x()); } - inline int getY(void) const - { return ((hidden) ? frame.y_hidden : frame.rect.y()); } - - void buttonPressEvent(const XButtonEvent *be); - void buttonReleaseEvent(const XButtonEvent *re); - void enterNotifyEvent(const XCrossingEvent * /*unused*/); - void leaveNotifyEvent(const XCrossingEvent * /*unused*/); - void exposeEvent(const XExposeEvent *ee); - void keyPressEvent(const XKeyEvent *ke); - - void edit(void); - void reconfigure(void); - void toggleAutoHide(void); - - void redrawWindowLabel(bool redraw = False); - void redrawWorkspaceLabel(bool redraw = False); - - virtual void timeout(void); - - enum { TopLeft = 1, BottomLeft, TopCenter, - BottomCenter, TopRight, BottomRight }; -}; - - -#endif // __Toolbar_hh diff --git a/src/Util.cc b/src/Util.cc deleted file mode 100644 index 90135447..00000000 --- a/src/Util.cc +++ /dev/null @@ -1,254 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Util.cc for Blackbox - an X11 Window manager -// Copyright (c) 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include - -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else // !TIME_WITH_SYS_TIME -# ifdef HAVE_SYS_TIME_H -# include -# else // !HAVE_SYS_TIME_H -# include -# endif // HAVE_SYS_TIME_H -#endif // TIME_WITH_SYS_TIME -#ifdef HAVE_UNISTD_H -#include -#endif // HAVE_UNISTD_H -#if defined(HAVE_PROCESS_H) && defined(__EMX__) -# include -#endif // HAVE_PROCESS_H __EMX__ - -#include -} - -#include - -#include "Util.hh" - -using std::string; - - -void Rect::setX(int x) { - _x2 += x - _x1; - _x1 = x; -} - - -void Rect::setY(int y) -{ - _y2 += y - _y1; - _y1 = y; -} - - -void Rect::setPos(int x, int y) { - _x2 += x - _x1; - _x1 = x; - _y2 += y - _y1; - _y1 = y; -} - - -void Rect::setWidth(unsigned int w) { - _x2 = w + _x1 - 1; -} - - -void Rect::setHeight(unsigned int h) { - _y2 = h + _y1 - 1; -} - - -void Rect::setSize(unsigned int w, unsigned int h) { - _x2 = w + _x1 - 1; - _y2 = h + _y1 - 1; -} - - -void Rect::setRect(int x, int y, unsigned int w, unsigned int h) { - *this = Rect(x, y, w, h); -} - - -void Rect::setCoords(int l, int t, int r, int b) { - _x1 = l; - _y1 = t; - _x2 = r; - _y2 = b; -} - - -Rect Rect::operator|(const Rect &a) const { - Rect b; - - b._x1 = std::min(_x1, a._x1); - b._y1 = std::min(_y1, a._y1); - b._x2 = std::max(_x2, a._x2); - b._y2 = std::max(_y2, a._y2); - - return b; -} - - -Rect Rect::operator&(const Rect &a) const { - Rect b; - - b._x1 = std::max(_x1, a._x1); - b._y1 = std::max(_y1, a._y1); - b._x2 = std::min(_x2, a._x2); - b._y2 = std::min(_y2, a._y2); - - return b; -} - - -bool Rect::intersects(const Rect &a) const { - return std::max(_x1, a._x1) <= std::min(_x2, a._x2) && - std::max(_y1, a._y1) <= std::min(_y2, a._y2); -} - - -bool Rect::contains(int x, int y) const { - return x >= _x1 && x <= _x2 && - y >= _y1 && y <= _y2; -} - - -bool Rect::contains(const Rect& a) const { - return a._x1 >= _x1 && a._x2 <= _x2 && - a._y1 >= _y1 && a._y2 <= _y2; -} - - -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(); - int ret = putenv(const_cast(displaystring.c_str())); - assert(ret != -1); - 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__ -} - - -#ifndef HAVE_BASENAME -string basename (const string& path) { - string::size_type slash = path.rfind('/'); - if (slash == string::npos) - return path; - return path.substr(slash+1); -} -#endif // HAVE_BASENAME - - -string textPropertyToString(Display *display, XTextProperty& text_prop) { - string ret; - - if (text_prop.value && text_prop.nitems > 0) { - if (text_prop.encoding == XA_STRING) { - ret = (char *) text_prop.value; - } else { - text_prop.nitems = strlen((char *) text_prop.value); - - char **list; - int num; - if (XmbTextPropertyToTextList(display, &text_prop, - &list, &num) == Success && - num > 0 && *list) { - ret = *list; - XFreeStringList(list); - } - } - } - - return ret; -} - - -timeval normalizeTimeval(const timeval &tm) { - timeval ret = tm; - - while (ret.tv_usec < 0) { - if (ret.tv_sec > 0) { - --ret.tv_sec; - ret.tv_usec += 1000000; - } else { - ret.tv_usec = 0; - } - } - - if (ret.tv_usec >= 1000000) { - ret.tv_sec += ret.tv_usec / 1000000; - ret.tv_usec %= 1000000; - } - - if (ret.tv_sec < 0) ret.tv_sec = 0; - - return ret; -} - - -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; -} diff --git a/src/Util.hh b/src/Util.hh deleted file mode 100644 index 40a2254a..00000000 --- a/src/Util.hh +++ /dev/null @@ -1,120 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Util.cc for Blackbox - an X11 Window manager -// Copyright (c) 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef _BLACKBOX_UTIL_HH -#define _BLACKBOX_UTIL_HH - -#include -#include - -#include -#include - -class Rect { -public: - inline Rect(void) : _x1(0), _y1(0), _x2(0), _y2(0) { } - inline Rect(int __x, int __y, unsigned int __w, unsigned int __h) - : _x1(__x), _y1(__y), _x2(__w + __x - 1), _y2(__h + __y - 1) { } - inline explicit Rect(const XRectangle& xrect) - : _x1(xrect.x), _y1(xrect.y), _x2(xrect.width + xrect.x - 1), - _y2(xrect.height + xrect.y - 1) { } - - inline int left(void) const { return _x1; } - inline int top(void) const { return _y1; } - inline int right(void) const { return _x2; } - inline int bottom(void) const { return _y2; } - - inline int x(void) const { return _x1; } - inline int y(void) const { return _y1; } - void setX(int __x); - void setY(int __y); - void setPos(int __x, int __y); - - inline unsigned int width(void) const { return _x2 - _x1 + 1; } - inline unsigned int height(void) const { return _y2 - _y1 + 1; } - void setWidth(unsigned int __w); - void setHeight(unsigned int __h); - void setSize(unsigned int __w, unsigned int __h); - - void setRect(int __x, int __y, unsigned int __w, unsigned int __h); - - void setCoords(int __l, int __t, int __r, int __b); - - inline bool operator==(const Rect &a) - { return _x1 == a._x1 && _y1 == a._y1 && _x2 == a._x2 && _y2 == a._y2; } - inline bool operator!=(const Rect &a) { return ! operator==(a); } - - Rect operator|(const Rect &a) const; - Rect operator&(const Rect &a) const; - inline Rect &operator|=(const Rect &a) { *this = *this | a; return *this; } - inline Rect &operator&=(const Rect &a) { *this = *this & a; return *this; } - - inline bool valid(void) const { return _x2 > _x1 && _y2 > _y1; } - - bool intersects(const Rect &a) const; - bool contains(int __x, int __y) const; - bool contains(const Rect &a) const; - -private: - int _x1, _y1, _x2, _y2; -}; - -typedef std::vector RectList; - -struct Strut { - unsigned int top, bottom, left, right; - - Strut(void): top(0), bottom(0), left(0), right(0) {} -}; - -/* XXX: this needs autoconf help */ -const unsigned int BSENTINEL = 65535; - -std::string expandTilde(const std::string& s); - -void bexec(const std::string& command, const std::string& displaystring); - -#ifndef HAVE_BASENAME -std::string basename(const std::string& path); -#endif - -std::string textPropertyToString(Display *display, XTextProperty& text_prop); - -struct timeval; // forward declare to avoid the header -timeval normalizeTimeval(const timeval &tm); - -struct PointerAssassin { - template - inline void operator()(const T ptr) const { - delete ptr; - } -}; - -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); } - -#endif diff --git a/src/Window.cc b/src/Window.cc deleted file mode 100644 index 680943e2..00000000 --- a/src/Window.cc +++ /dev/null @@ -1,4357 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Window.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000, 2002 Brad Hughes -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -#include - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H - -#ifdef DEBUG -# ifdef HAVE_STDIO_H -# include -# endif // HAVE_STDIO_H -#endif // DEBUG - -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H -} - -#include "i18n.hh" -#include "blackbox.hh" -#include "Clientmenu.hh" -#include "Font.hh" -#include "GCCache.hh" -#include "Iconmenu.hh" -#include "Image.hh" -#include "Screen.hh" -#include "Toolbar.hh" -#include "Util.hh" -#include "Window.hh" -#include "Windowmenu.hh" -#include "Workspace.hh" -#include "Slit.hh" - -using std::string; -using std::abs; - -/* - * Initializes the class with default values/the window's set initial values. - */ -BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { - // fprintf(stderr, "BlackboxWindow size: %d bytes\n", - // sizeof(BlackboxWindow)); - -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w); -#endif // DEBUG - - /* - set timer to zero... it is initialized properly later, so we check - if timer is zero in the destructor, and assume that the window is not - fully constructed if timer is zero... - */ - timer = 0; - blackbox = b; - client.window = w; - screen = s; - xatom = blackbox->getXAtom(); - - if (! validateClient()) { - delete this; - return; - } - - // fetch client size and placement - XWindowAttributes wattrib; - if (! XGetWindowAttributes(blackbox->getXDisplay(), - client.window, &wattrib) || - ! wattrib.screen || wattrib.override_redirect) { -#ifdef DEBUG - fprintf(stderr, - "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n"); -#endif // DEBUG - - delete this; - return; - } - - // set the eventmask early in the game so that we make sure we get - // all the events we are interested in - XSetWindowAttributes attrib_set; - attrib_set.event_mask = PropertyChangeMask | FocusChangeMask | - StructureNotifyMask; - attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask; - XChangeWindowAttributes(blackbox->getXDisplay(), client.window, - CWEventMask|CWDontPropagate, &attrib_set); - - flags.moving = flags.resizing = flags.shaded = flags.visible = - flags.iconic = flags.focused = flags.stuck = flags.modal = - flags.send_focus_message = flags.shaped = flags.skip_taskbar = - flags.skip_pager = flags.fullscreen = False; - flags.maximized = 0; - - blackbox_attrib.workspace = window_number = BSENTINEL; - - blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l; - blackbox_attrib.decoration = DecorNormal; - blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; - blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; - - frame.border_w = 1; - frame.window = frame.plate = frame.title = frame.handle = None; - frame.close_button = frame.iconify_button = frame.maximize_button = - frame.stick_button = None; - frame.right_grip = frame.left_grip = None; - - frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel = - frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel = - frame.ubutton_pixel = frame.fbutton_pixel = frame.uborder_pixel = - frame.fborder_pixel = frame.ugrip_pixel = frame.fgrip_pixel = 0; - frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None; - frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None; - frame.ugrip = frame.fgrip = None; - - functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize; - mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border | - Decor_Iconify | Decor_Maximize; - - client.normal_hint_flags = 0; - client.window_group = None; - client.transient_for = 0; - - current_state = NormalState; - - windowmenu = 0; - - /* - set the initial size and location of client window (relative to the - _root window_). This position is the reference point used with the - window's gravity to find the window's initial position. - */ - client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height); - client.old_bw = wattrib.border_width; - - lastButtonPressTime = 0; - - timer = new BTimer(blackbox, this); - timer->setTimeout(blackbox->getAutoRaiseDelay()); - - // get size, aspect, minimum/maximum size and other hints set by the - // client - - if (! getBlackboxHints()) - getNetWMHints(); - - getWMProtocols(); - getWMHints(); - getWMNormalHints(); - - frame.window = createToplevelWindow(); - - blackbox->saveWindowSearch(frame.window, this); - - frame.plate = createChildWindow(frame.window, ExposureMask); - blackbox->saveWindowSearch(frame.plate, this); - - // determine if this is a transient window - getTransientInfo(); - - // determine the window's type, so we can decide its decorations and - // functionality, or if we should not manage it at all - if (getWindowType()) { - // adjust the window decorations/behavior based on the window type - switch (window_type) { - case Type_Desktop: - case Type_Dock: - case Type_Menu: - blackbox_attrib.workspace = 0; // we do need to belong to a workspace - flags.stuck = True; // we show up on all workspaces - case Type_Splash: - // none of these windows are manipulated by the window manager - functions = 0; - break; - - case Type_Toolbar: - case Type_Utility: - // these windows get less functionality - functions &= ~(Func_Maximize | Func_Resize | Func_Iconify); - break; - - case Type_Dialog: - // dialogs cannot be maximized - functions &= ~Func_Maximize; - break; - - case Type_Normal: - // normal windows retain all of the possible decorations and - // functionality - break; - } - } else { - getMWMHints(); - } - - // further adjeust the window's decorations/behavior based on window sizes - if ((client.normal_hint_flags & PMinSize) && - (client.normal_hint_flags & PMaxSize) && - client.max_width <= client.min_width && - client.max_height <= client.min_height) { - functions &= ~(Func_Resize | Func_Maximize); - } - - setAllowedActions(); - - setupDecor(); - - if (decorations & Decor_Titlebar) - createTitlebar(); - - if (decorations & Decor_Handle) - createHandle(); - - // apply the size and gravity hint to the frame - - upsize(); - - bool place_window = True; - if (blackbox->isStartup() || isTransient() || - client.normal_hint_flags & (PPosition|USPosition)) { - applyGravity(frame.rect); - - if (blackbox->isStartup() || client.rect.intersects(screen->getRect())) - place_window = False; - } - - // add the window's strut. note this is done *after* placing the window. - screen->addStrut(&client.strut); - updateStrut(); - - /* - the server needs to be grabbed here to prevent client's from sending - events while we are in the process of configuring their window. - We hold the grab until after we are done moving the window around. - */ - - XGrabServer(blackbox->getXDisplay()); - - associateClientWindow(); - - blackbox->saveWindowSearch(client.window, this); - - if (blackbox_attrib.workspace >= screen->getWorkspaceCount()) - screen->getCurrentWorkspace()->addWindow(this, place_window); - else - screen->getWorkspace(blackbox_attrib.workspace)-> - addWindow(this, place_window); - - if (! place_window) { - // don't need to call configure if we are letting the workspace - // place the window - configure(frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height()); - - } - - positionWindows(); - - XUngrabServer(blackbox->getXDisplay()); - -#ifdef SHAPE - if (blackbox->hasShapeExtensions() && flags.shaped) - configureShape(); -#endif // SHAPE - - // now that we know where to put the window and what it should look like - // we apply the decorations - decorate(); - - grabButtons(); - - XMapSubwindows(blackbox->getXDisplay(), frame.window); - - // this ensures the title, buttons, and other decor are properly displayed - redrawWindowFrame(); - - // preserve the window's initial state on first map, and its current state - // across a restart - unsigned long initial_state = current_state; - if (! getState()) - current_state = initial_state; - - // get sticky state from our parent window if we've got one - if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul && - client.transient_for->isStuck() != flags.stuck) - flags.stuck = True; - - if (flags.shaded) { - flags.shaded = False; - initial_state = current_state; - shade(); - - /* - At this point in the life of a window, current_state should only be set - to IconicState if the window was an *icon*, not if it was shaded. - */ - if (initial_state != IconicState) - current_state = NormalState; - } - - if (flags.stuck) { - flags.stuck = False; - stick(); - } - - if (flags.maximized && (functions & Func_Maximize)) - remaximize(); - - // create this last so it only needs to be configured once - windowmenu = new Windowmenu(this); -} - - -BlackboxWindow::~BlackboxWindow(void) { -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n", - client.window); -#endif // DEBUG - - if (! timer) // window not managed... - return; - - if (flags.moving) - endMove(); - - screen->removeStrut(&client.strut); - screen->updateAvailableArea(); - - // We don't need to worry about resizing because resizing always grabs the X - // server. This should only ever happen if using opaque moving. - if (flags.moving) - endMove(); - - delete timer; - - delete windowmenu; - - if (client.window_group) { - BWindowGroup *group = blackbox->searchGroup(client.window_group); - if (group) group->removeWindow(this); - } - - // remove ourselves from our transient_for - if (isTransient()) { - if (client.transient_for != (BlackboxWindow *) ~0ul) - client.transient_for->client.transientList.remove(this); - client.transient_for = (BlackboxWindow*) 0; - } - - if (client.transientList.size() > 0) { - // reset transient_for for all transients - BlackboxWindowList::iterator it, end = client.transientList.end(); - for (it = client.transientList.begin(); it != end; ++it) - (*it)->client.transient_for = (BlackboxWindow*) 0; - } - - if (frame.title) - destroyTitlebar(); - - if (frame.handle) - destroyHandle(); - - if (frame.plate) { - blackbox->removeWindowSearch(frame.plate); - XDestroyWindow(blackbox->getXDisplay(), frame.plate); - } - - if (frame.window) { - blackbox->removeWindowSearch(frame.window); - XDestroyWindow(blackbox->getXDisplay(), frame.window); - } - - blackbox->removeWindowSearch(client.window); -} - - -void BlackboxWindow::enableDecor(bool enable) { - blackbox_attrib.flags |= AttribDecoration; - blackbox_attrib.decoration = enable ? DecorNormal : DecorNone; - setupDecor(); - - // we can not be shaded if we lack a titlebar - if (! (decorations & Decor_Titlebar) && flags.shaded) - shade(); - - if (flags.visible && frame.window) { - XMapSubwindows(blackbox->getXDisplay(), frame.window); - XMapWindow(blackbox->getXDisplay(), frame.window); - } - - reconfigure(); - setState(current_state); -} - - -void BlackboxWindow::setupDecor() { - if (blackbox_attrib.decoration != DecorNone) { - // start with everything on - decorations = Decor_Close | - (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) | - (mwm_decorations & Decor_Border ? Decor_Border : 0) | - (mwm_decorations & Decor_Handle ? Decor_Handle : 0) | - (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) | - (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0); - - if (! (functions & Func_Close)) decorations &= ~Decor_Close; - if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize; - if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify; - if (! (functions & Func_Resize)) decorations &= ~Decor_Handle; - - switch (window_type) { - case Type_Desktop: - case Type_Dock: - case Type_Menu: - case Type_Splash: - // none of these windows are decorated by the window manager at all - decorations = 0; - break; - - case Type_Toolbar: - case Type_Utility: - decorations &= ~(Decor_Border); - break; - - case Type_Dialog: - decorations &= ~Decor_Handle; - break; - - case Type_Normal: - break; - } - } else { - decorations = 0; - } -} - -/* - * Creates a new top level window, with a given location, size, and border - * width. - * Returns: the newly created window - */ -Window BlackboxWindow::createToplevelWindow(void) { - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap | - CWOverrideRedirect | CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.colormap = screen->getColormap(); - attrib_create.override_redirect = True; - attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | - ButtonPress; - /* - We catch button presses because other wise they get passed down to the - root window, which will then cause root menus to show when you click the - window's frame. - */ - - return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(), - 0, 0, 1, 1, frame.border_w, screen->getDepth(), - InputOutput, screen->getVisual(), create_mask, - &attrib_create); -} - - -/* - * Creates a child window, and optionally associates a given cursor with - * the new window. - */ -Window BlackboxWindow::createChildWindow(Window parent, - unsigned long event_mask, - Cursor cursor) { - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | - CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.event_mask = event_mask; - - if (cursor) { - create_mask |= CWCursor; - attrib_create.cursor = cursor; - } - - return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0, - screen->getDepth(), InputOutput, screen->getVisual(), - create_mask, &attrib_create); -} - - -void BlackboxWindow::associateClientWindow(void) { - XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0); - getWMName(); - getWMIconName(); - - XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert); - - XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask); - - /* - note we used to grab around this call to XReparentWindow however the - server is now grabbed before this method is called - */ - unsigned long event_mask = PropertyChangeMask | FocusChangeMask | - StructureNotifyMask; - XSelectInput(blackbox->getXDisplay(), client.window, - event_mask & ~StructureNotifyMask); - XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0); - XSelectInput(blackbox->getXDisplay(), client.window, event_mask); - - XRaiseWindow(blackbox->getXDisplay(), frame.plate); - XMapSubwindows(blackbox->getXDisplay(), frame.plate); - -#ifdef SHAPE - if (blackbox->hasShapeExtensions()) { - XShapeSelectInput(blackbox->getXDisplay(), client.window, - ShapeNotifyMask); - - Bool shaped = False; - int foo; - unsigned int ufoo; - - XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped, - &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo, - &ufoo, &ufoo); - flags.shaped = shaped; - } -#endif // SHAPE -} - - -void BlackboxWindow::decorate(void) { - BTexture* texture; - - texture = &(screen->getWindowStyle()->b_focus); - frame.fbutton = texture->render(frame.button_w, frame.button_w, - frame.fbutton); - if (! frame.fbutton) - frame.fbutton_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->b_unfocus); - frame.ubutton = texture->render(frame.button_w, frame.button_w, - frame.ubutton); - if (! frame.ubutton) - frame.ubutton_pixel = texture->color().pixel(); - - unsigned char needsPressed = 0; - - texture = &(screen->getWindowStyle()->b_pressed_focus); - - if (texture->texture() != BTexture::NoTexture) { - frame.pfbutton = texture->render(frame.button_w, frame.button_w, - frame.pfbutton); - if (! frame.pfbutton) - frame.pfbutton_pixel = texture->color().pixel(); - } else { - needsPressed = 0x1; - } - - texture = &(screen->getWindowStyle()->b_pressed_unfocus); - - if (texture->texture() != BTexture::NoTexture) { - frame.pubutton = texture->render(frame.button_w, frame.button_w, - frame.pubutton); - if (! frame.pubutton) - frame.pubutton = texture->color().pixel(); - } else { - needsPressed |= 0x2; - } - - // if we either pressed unfocused, or pressed focused were undefined, - // make them inherit from the old resource. It's a hack for sure, but - // it allows for some backwards and forwards compatibility. - if (needsPressed) { - texture = &(screen->getWindowStyle()->b_pressed); - - if (needsPressed & 0x1) { - frame.pfbutton = texture->render(frame.button_w, frame.button_w, - frame.pfbutton); - if (! frame.pfbutton) - frame.pfbutton_pixel = texture->color().pixel(); - } - if (needsPressed & 0x2) { - frame.pubutton = texture->render(frame.button_w, frame.button_w, - frame.pubutton); - if (! frame.pubutton) - frame.pubutton = texture->color().pixel(); - } - - } - - if (decorations & Decor_Titlebar) { - texture = &(screen->getWindowStyle()->t_focus); - frame.ftitle = texture->render(frame.inside_w, frame.title_h, - frame.ftitle); - if (! frame.ftitle) - frame.ftitle_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->t_unfocus); - frame.utitle = texture->render(frame.inside_w, frame.title_h, - frame.utitle); - if (! frame.utitle) - frame.utitle_pixel = texture->color().pixel(); - - XSetWindowBorder(blackbox->getXDisplay(), frame.title, - screen->getBorderColor()->pixel()); - - decorateLabel(); - } - - if (decorations & Decor_Border) { - frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel(); - frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel(); - } - - if (decorations & Decor_Handle) { - texture = &(screen->getWindowStyle()->h_focus); - frame.fhandle = texture->render(frame.inside_w, frame.handle_h, - frame.fhandle); - if (! frame.fhandle) - frame.fhandle_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->h_unfocus); - frame.uhandle = texture->render(frame.inside_w, frame.handle_h, - frame.uhandle); - if (! frame.uhandle) - frame.uhandle_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->g_focus); - frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip); - if (! frame.fgrip) - frame.fgrip_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->g_unfocus); - frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip); - if (! frame.ugrip) - frame.ugrip_pixel = texture->color().pixel(); - - XSetWindowBorder(blackbox->getXDisplay(), frame.handle, - screen->getBorderColor()->pixel()); - XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip, - screen->getBorderColor()->pixel()); - XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip, - screen->getBorderColor()->pixel()); - } - - XSetWindowBorder(blackbox->getXDisplay(), frame.window, - screen->getBorderColor()->pixel()); -} - - -void BlackboxWindow::decorateLabel(void) { - BTexture *texture; - - texture = &(screen->getWindowStyle()->l_focus); - frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel); - if (! frame.flabel) - frame.flabel_pixel = texture->color().pixel(); - - texture = &(screen->getWindowStyle()->l_unfocus); - frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel); - if (! frame.ulabel) - frame.ulabel_pixel = texture->color().pixel(); -} - - -void BlackboxWindow::createHandle(void) { - frame.handle = createChildWindow(frame.window, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.handle, this); - - frame.left_grip = - createChildWindow(frame.handle, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask, - blackbox->getLowerLeftAngleCursor()); - blackbox->saveWindowSearch(frame.left_grip, this); - - frame.right_grip = - createChildWindow(frame.handle, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask, - blackbox->getLowerRightAngleCursor()); - blackbox->saveWindowSearch(frame.right_grip, this); -} - - -void BlackboxWindow::destroyHandle(void) { - if (frame.fhandle) - screen->getImageControl()->removeImage(frame.fhandle); - - if (frame.uhandle) - screen->getImageControl()->removeImage(frame.uhandle); - - if (frame.fgrip) - screen->getImageControl()->removeImage(frame.fgrip); - - if (frame.ugrip) - screen->getImageControl()->removeImage(frame.ugrip); - - blackbox->removeWindowSearch(frame.left_grip); - blackbox->removeWindowSearch(frame.right_grip); - - XDestroyWindow(blackbox->getXDisplay(), frame.left_grip); - XDestroyWindow(blackbox->getXDisplay(), frame.right_grip); - frame.left_grip = frame.right_grip = None; - - blackbox->removeWindowSearch(frame.handle); - XDestroyWindow(blackbox->getXDisplay(), frame.handle); - frame.handle = None; -} - - -void BlackboxWindow::createTitlebar(void) { - frame.title = createChildWindow(frame.window, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - frame.label = createChildWindow(frame.title, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.title, this); - blackbox->saveWindowSearch(frame.label, this); - - if (decorations & Decor_Iconify) createIconifyButton(); - if (decorations & Decor_Maximize) createMaximizeButton(); - if (decorations & Decor_Close) createCloseButton(); -} - - -void BlackboxWindow::destroyTitlebar(void) { - if (frame.close_button) - destroyCloseButton(); - - if (frame.iconify_button) - destroyIconifyButton(); - - if (frame.maximize_button) - destroyMaximizeButton(); - - if (frame.stick_button) - destroyStickyButton(); - - if (frame.ftitle) - screen->getImageControl()->removeImage(frame.ftitle); - - if (frame.utitle) - screen->getImageControl()->removeImage(frame.utitle); - - if (frame.flabel) - screen->getImageControl()->removeImage(frame.flabel); - - if( frame.ulabel) - screen->getImageControl()->removeImage(frame.ulabel); - - if (frame.fbutton) - screen->getImageControl()->removeImage(frame.fbutton); - - if (frame.ubutton) - screen->getImageControl()->removeImage(frame.ubutton); - - blackbox->removeWindowSearch(frame.title); - blackbox->removeWindowSearch(frame.label); - - XDestroyWindow(blackbox->getXDisplay(), frame.label); - XDestroyWindow(blackbox->getXDisplay(), frame.title); - frame.title = frame.label = None; -} - - -void BlackboxWindow::createCloseButton(void) { - if (frame.title != None) { - frame.close_button = createChildWindow(frame.title, - ButtonPressMask | - ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.close_button, this); - } -} - - -void BlackboxWindow::destroyCloseButton(void) { - blackbox->removeWindowSearch(frame.close_button); - XDestroyWindow(blackbox->getXDisplay(), frame.close_button); - frame.close_button = None; -} - - -void BlackboxWindow::createIconifyButton(void) { - if (frame.title != None) { - frame.iconify_button = createChildWindow(frame.title, - ButtonPressMask | - ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.iconify_button, this); - } -} - - -void BlackboxWindow::destroyIconifyButton(void) { - blackbox->removeWindowSearch(frame.iconify_button); - XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button); - frame.iconify_button = None; -} - - -void BlackboxWindow::createMaximizeButton(void) { - if (frame.title != None) { - frame.maximize_button = createChildWindow(frame.title, - ButtonPressMask | - ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.maximize_button, this); - } -} - - -void BlackboxWindow::destroyMaximizeButton(void) { - blackbox->removeWindowSearch(frame.maximize_button); - XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button); - frame.maximize_button = None; -} - -void BlackboxWindow::createStickyButton(void) { - if (frame.title != None) { - frame.stick_button = createChildWindow(frame.title, - ButtonPressMask | - ButtonReleaseMask | - ButtonMotionMask | ExposureMask); - blackbox->saveWindowSearch(frame.stick_button, this); - } -} - -void BlackboxWindow::destroyStickyButton(void) { - blackbox->removeWindowSearch(frame.stick_button); - XDestroyWindow(blackbox->getXDisplay(), frame.stick_button); - frame.stick_button = None; -} - -void BlackboxWindow::positionButtons(bool redecorate_label) { - string layout = blackbox->getTitlebarLayout(); - string parsed; - - bool hasclose, hasiconify, hasmaximize, haslabel, hasstick; - hasclose = hasiconify = hasmaximize = haslabel = hasstick = false; - - string::const_iterator it, end; - for (it = layout.begin(), end = layout.end(); it != end; ++it) { - switch(*it) { - case 'C': - if (! hasclose && (decorations & Decor_Close)) { - hasclose = true; - parsed += *it; - } - break; - case 'I': - if (! hasiconify && (decorations & Decor_Iconify)) { - hasiconify = true; - parsed += *it; - } - break; - case 'S': - if (!hasstick) { - hasstick = true; - parsed += *it; - } - break; - case 'M': - if (! hasmaximize && (decorations & Decor_Maximize)) { - hasmaximize = true; - parsed += *it; - } - break; - case 'L': - if (! haslabel) { - haslabel = true; - parsed += *it; - } - break; - } - } - - if (! hasclose && frame.close_button) - destroyCloseButton(); - if (! hasiconify && frame.iconify_button) - destroyIconifyButton(); - if (! hasmaximize && frame.maximize_button) - destroyMaximizeButton(); - if (! hasstick && frame.stick_button) - destroyStickyButton(); - if (! haslabel) - parsed += 'L'; // require that the label be in the layout - - const unsigned int bsep = frame.bevel_w + 1; // separation between elements - const unsigned int by = frame.bevel_w + 1; - const unsigned int ty = frame.bevel_w; - - frame.label_w = frame.inside_w - bsep * 2 - - (frame.button_w + bsep) * (parsed.size() - 1); - - unsigned int x = bsep; - for (it = parsed.begin(), end = parsed.end(); it != end; ++it) { - switch(*it) { - case 'C': - if (! frame.close_button) createCloseButton(); - XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by, - frame.button_w, frame.button_w); - x += frame.button_w + bsep; - break; - case 'I': - if (! frame.iconify_button) createIconifyButton(); - XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by, - frame.button_w, frame.button_w); - x += frame.button_w + bsep; - break; - case 'S': - if (! frame.stick_button) createStickyButton(); - XMoveResizeWindow(blackbox->getXDisplay(), frame.stick_button, x, by, - frame.button_w, frame.button_w); - x += frame.button_w + bsep; - break; - case 'M': - if (! frame.maximize_button) createMaximizeButton(); - XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by, - frame.button_w, frame.button_w); - x += frame.button_w + bsep; - break; - case 'L': - XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty, - frame.label_w, frame.label_h); - x += frame.label_w + bsep; - break; - } - } - - if (redecorate_label) decorateLabel(); - redrawLabel(); - redrawAllButtons(); -} - - -void BlackboxWindow::reconfigure(void) { - restoreGravity(client.rect); - upsize(); - applyGravity(frame.rect); - positionWindows(); - decorate(); - redrawWindowFrame(); - - ungrabButtons(); - grabButtons(); - - if (windowmenu) { - windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h); - windowmenu->reconfigure(); - } -} - - -void BlackboxWindow::grabButtons(void) { - mod_mask = blackbox->getMouseModMask(); - - if (! screen->isSloppyFocus() || screen->doClickRaise()) - // grab button 1 for changing focus/raising - blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, - GrabModeSync, GrabModeSync, frame.plate, None, - screen->allowScrollLock()); - - if (functions & Func_Move) - blackbox->grabButton(Button1, mod_mask, frame.window, True, - ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, - GrabModeAsync, frame.window, None, - screen->allowScrollLock()); - if (functions & Func_Resize) - blackbox->grabButton(Button3, mod_mask, frame.window, True, - ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, - GrabModeAsync, frame.window, None, - screen->allowScrollLock()); - // alt+middle lowers the window - blackbox->grabButton(Button2, mod_mask, frame.window, True, - ButtonReleaseMask, GrabModeAsync, GrabModeAsync, - frame.window, None, screen->allowScrollLock()); -} - - -void BlackboxWindow::ungrabButtons(void) { - blackbox->ungrabButton(Button1, 0, frame.plate); - blackbox->ungrabButton(Button1, mod_mask, frame.window); - blackbox->ungrabButton(Button2, mod_mask, frame.window); - blackbox->ungrabButton(Button3, mod_mask, frame.window); -} - - -void BlackboxWindow::positionWindows(void) { - XMoveResizeWindow(blackbox->getXDisplay(), frame.window, - frame.rect.x(), frame.rect.y(), frame.inside_w, - (flags.shaded) ? frame.title_h : frame.inside_h); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window, - frame.border_w); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate, - frame.mwm_border_w); - XMoveResizeWindow(blackbox->getXDisplay(), frame.plate, - frame.margin.left - frame.mwm_border_w - frame.border_w, - frame.margin.top - frame.mwm_border_w - frame.border_w, - client.rect.width(), client.rect.height()); - XMoveResizeWindow(blackbox->getXDisplay(), client.window, - 0, 0, client.rect.width(), client.rect.height()); - // ensure client.rect contains the real location - client.rect.setPos(frame.rect.left() + frame.margin.left, - frame.rect.top() + frame.margin.top); - - if (decorations & Decor_Titlebar) { - if (frame.title == None) createTitlebar(); - - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title, - frame.border_w); - XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w, - -frame.border_w, frame.inside_w, frame.title_h); - - positionButtons(); - XMapSubwindows(blackbox->getXDisplay(), frame.title); - XMapWindow(blackbox->getXDisplay(), frame.title); - } else if (frame.title) { - destroyTitlebar(); - } - if (decorations & Decor_Handle) { - if (frame.handle == None) createHandle(); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle, - frame.border_w); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip, - frame.border_w); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip, - frame.border_w); - - // use client.rect here so the value is correct even if shaded - XMoveResizeWindow(blackbox->getXDisplay(), frame.handle, - -frame.border_w, - client.rect.height() + frame.margin.top + - frame.mwm_border_w - frame.border_w, - frame.inside_w, frame.handle_h); - XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip, - -frame.border_w, -frame.border_w, - frame.grip_w, frame.handle_h); - XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip, - frame.inside_w - frame.grip_w - frame.border_w, - -frame.border_w, frame.grip_w, frame.handle_h); - - XMapSubwindows(blackbox->getXDisplay(), frame.handle); - XMapWindow(blackbox->getXDisplay(), frame.handle); - } else if (frame.handle) { - destroyHandle(); - } - XSync(blackbox->getXDisplay(), False); -} - - -void BlackboxWindow::updateStrut(void) { - unsigned long num = 4; - unsigned long *data; - if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal, - num, &data)) - return; - - if (num == 4) { - client.strut.left = data[0]; - client.strut.right = data[1]; - client.strut.top = data[2]; - client.strut.bottom = data[3]; - - screen->updateAvailableArea(); - } - - delete [] data; -} - - -bool BlackboxWindow::getWindowType(void) { - window_type = (WindowType) -1; - - unsigned long *val; - unsigned long num = (unsigned) -1; - if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom, - num, &val)) { - for (unsigned long i = 0; i < num; ++i) { - if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop)) - window_type = Type_Desktop; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock)) - window_type = Type_Dock; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar)) - window_type = Type_Toolbar; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu)) - window_type = Type_Menu; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility)) - window_type = Type_Utility; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash)) - window_type = Type_Splash; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog)) - window_type = Type_Dialog; - else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal)) - window_type = Type_Normal; - else if (val[i] == - xatom->getAtom(XAtom::kde_net_wm_window_type_override)) - mwm_decorations = 0; // prevent this window from getting any decor - } - delete val; - } - - if (window_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 (isTransient()) - window_type = Type_Dialog; - else - window_type = Type_Normal; - - return False; - } - - return True; -} - - -void BlackboxWindow::getWMName(void) { - if (xatom->getValue(client.window, XAtom::net_wm_name, - XAtom::utf8, client.title) && - !client.title.empty()) { - xatom->eraseValue(client.window, XAtom::net_wm_visible_name); - return; - } - //fall through to using WM_NAME - if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title) - && !client.title.empty()) { - xatom->eraseValue(client.window, XAtom::net_wm_visible_name); - return; - } - // fall back to an internal default - client.title = i18n(WindowSet, WindowUnnamed, "Unnamed"); - xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8, - client.title); - -#ifdef DEBUG_WITH_ID - // the 16 is the 8 chars of the debug text plus the number - char *tmp = new char[client.title.length() + 16]; - sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window); - client.title = tmp; - delete tmp; -#endif -} - - -void BlackboxWindow::getWMIconName(void) { - if (xatom->getValue(client.window, XAtom::net_wm_icon_name, - XAtom::utf8, client.icon_title) && - !client.icon_title.empty()) { - xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name); - return; - } - //fall through to using WM_ICON_NAME - if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi, - client.icon_title) && - !client.icon_title.empty()) { - xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name); - return; - } - // fall back to using the main name - client.icon_title = client.title; - xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8, - client.icon_title); -} - - -/* - * Retrieve which WM Protocols are supported by the client window. - * If the WM_DELETE_WINDOW protocol is supported, add the close button to the - * window's decorations and allow the close behavior. - * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates - * this. - */ -void BlackboxWindow::getWMProtocols(void) { - Atom *proto; - int num_return = 0; - - if (XGetWMProtocols(blackbox->getXDisplay(), client.window, - &proto, &num_return)) { - for (int i = 0; i < num_return; ++i) { - if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) { - decorations |= Decor_Close; - functions |= Func_Close; - } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus)) - flags.send_focus_message = True; - else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages)) - screen->addNetizen(new Netizen(screen, client.window)); - } - - XFree(proto); - } -} - - -/* - * Gets the value of the WM_HINTS property. - * If the property is not set, then use a set of default values. - */ -void BlackboxWindow::getWMHints(void) { - focus_mode = F_Passive; - - // remove from current window group - if (client.window_group) { - BWindowGroup *group = blackbox->searchGroup(client.window_group); - if (group) group->removeWindow(this); - } - client.window_group = None; - - XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window); - if (! wmhint) { - return; - } - - if (wmhint->flags & InputHint) { - if (wmhint->input == True) { - if (flags.send_focus_message) - focus_mode = F_LocallyActive; - } else { - if (flags.send_focus_message) - focus_mode = F_GloballyActive; - else - focus_mode = F_NoInput; - } - } - - if (wmhint->flags & StateHint) - current_state = wmhint->initial_state; - - if (wmhint->flags & WindowGroupHint) { - client.window_group = wmhint->window_group; - - // add window to the appropriate group - BWindowGroup *group = blackbox->searchGroup(client.window_group); - if (! group) { // no group found, create it! - new BWindowGroup(blackbox, client.window_group); - group = blackbox->searchGroup(client.window_group); - } - if (group) - group->addWindow(this); - } - - XFree(wmhint); -} - - -/* - * Gets the value of the WM_NORMAL_HINTS property. - * If the property is not set, then use a set of default values. - */ -void BlackboxWindow::getWMNormalHints(void) { - long icccm_mask; - XSizeHints sizehint; - - client.min_width = client.min_height = - client.width_inc = client.height_inc = 1; - client.base_width = client.base_height = 0; - client.win_gravity = NorthWestGravity; -#if 0 - client.min_aspect_x = client.min_aspect_y = - client.max_aspect_x = client.max_aspect_y = 1; -#endif - - // don't limit the size of a window, the default max width is the biggest - // possible - client.max_width = (unsigned) -1; - client.max_height = (unsigned) -1; - - - if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window, - &sizehint, &icccm_mask)) - return; - - client.normal_hint_flags = sizehint.flags; - - if (sizehint.flags & PMinSize) { - if (sizehint.min_width >= 0) - client.min_width = sizehint.min_width; - if (sizehint.min_height >= 0) - client.min_height = sizehint.min_height; - } - - if (sizehint.flags & PMaxSize) { - if (sizehint.max_width > static_cast(client.min_width)) - client.max_width = sizehint.max_width; - else - client.max_width = client.min_width; - - if (sizehint.max_height > static_cast(client.min_height)) - client.max_height = sizehint.max_height; - else - client.max_height = client.min_height; - } - - if (sizehint.flags & PResizeInc) { - client.width_inc = sizehint.width_inc; - client.height_inc = sizehint.height_inc; - } - -#if 0 // we do not support this at the moment - if (sizehint.flags & PAspect) { - client.min_aspect_x = sizehint.min_aspect.x; - client.min_aspect_y = sizehint.min_aspect.y; - client.max_aspect_x = sizehint.max_aspect.x; - client.max_aspect_y = sizehint.max_aspect.y; - } -#endif - - if (sizehint.flags & PBaseSize) { - client.base_width = sizehint.base_width; - client.base_height = sizehint.base_height; - } - - if (sizehint.flags & PWinGravity) - client.win_gravity = sizehint.win_gravity; -} - - -/* - * Gets the NETWM hints for the class' contained window. - */ -void BlackboxWindow::getNetWMHints(void) { - unsigned long workspace; - - if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, - workspace)) { - if (workspace == 0xffffffff) - flags.stuck = True; - else - blackbox_attrib.workspace = workspace; - } - - unsigned long *state; - unsigned long num = (unsigned) -1; - if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom, - num, &state)) { - bool vert = False, - horz = False; - for (unsigned long i = 0; i < num; ++i) { - if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) - flags.modal = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded)) - flags.shaded = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) - flags.skip_taskbar = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager)) - flags.skip_pager = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen)) - flags.fullscreen = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden)) - setState(IconicState); - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert)) - vert = True; - else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz)) - horz = True; - } - if (vert && horz) - flags.maximized = 1; - else if (vert) - flags.maximized = 2; - else if (horz) - flags.maximized = 3; - - delete [] state; - } -} - - -/* - * Gets the MWM hints for the class' contained window. - * This is used while initializing the window to its first state, and not - * thereafter. - * Returns: true if the MWM hints are successfully retreived and applied; - * false if they are not. - */ -void BlackboxWindow::getMWMHints(void) { - unsigned long num; - MwmHints *mwm_hint; - - num = PropMwmHintsElements; - if (! xatom->getValue(client.window, XAtom::motif_wm_hints, - XAtom::motif_wm_hints, num, - (unsigned long **)&mwm_hint)) - return; - if (num < PropMwmHintsElements) { - delete [] mwm_hint; - return; - } - - if (mwm_hint->flags & MwmHintsDecorations) { - if (mwm_hint->decorations & MwmDecorAll) { - mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border | - Decor_Iconify | Decor_Maximize; - } else { - mwm_decorations = 0; - - if (mwm_hint->decorations & MwmDecorBorder) - mwm_decorations |= Decor_Border; - if (mwm_hint->decorations & MwmDecorHandle) - mwm_decorations |= Decor_Handle; - if (mwm_hint->decorations & MwmDecorTitle) - mwm_decorations |= Decor_Titlebar; - if (mwm_hint->decorations & MwmDecorIconify) - mwm_decorations |= Decor_Iconify; - if (mwm_hint->decorations & MwmDecorMaximize) - mwm_decorations |= Decor_Maximize; - } - } - - if (mwm_hint->flags & MwmHintsFunctions) { - if (mwm_hint->functions & MwmFuncAll) { - functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize | - Func_Close; - } else { - functions = 0; - - if (mwm_hint->functions & MwmFuncResize) - functions |= Func_Resize; - if (mwm_hint->functions & MwmFuncMove) - functions |= Func_Move; - if (mwm_hint->functions & MwmFuncIconify) - functions |= Func_Iconify; - if (mwm_hint->functions & MwmFuncMaximize) - functions |= Func_Maximize; - if (mwm_hint->functions & MwmFuncClose) - functions |= Func_Close; - } - } - delete [] mwm_hint; -} - - -/* - * Gets the blackbox hints from the class' contained window. - * This is used while initializing the window to its first state, and not - * thereafter. - * Returns: true if the hints are successfully retreived and applied; false if - * they are not. - */ -bool BlackboxWindow::getBlackboxHints(void) { - unsigned long num; - BlackboxHints *blackbox_hint; - - num = PropBlackboxHintsElements; - if (! xatom->getValue(client.window, XAtom::blackbox_hints, - XAtom::blackbox_hints, num, - (unsigned long **)&blackbox_hint)) - return False; - if (num < PropBlackboxHintsElements) { - delete [] blackbox_hint; - return False; - } - - if (blackbox_hint->flags & AttribShaded) - flags.shaded = (blackbox_hint->attrib & AttribShaded); - - if ((blackbox_hint->flags & AttribMaxHoriz) && - (blackbox_hint->flags & AttribMaxVert)) - flags.maximized = (blackbox_hint->attrib & - (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; - else if (blackbox_hint->flags & AttribMaxVert) - flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0; - else if (blackbox_hint->flags & AttribMaxHoriz) - flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0; - - if (blackbox_hint->flags & AttribOmnipresent) - flags.stuck = (blackbox_hint->attrib & AttribOmnipresent); - - if (blackbox_hint->flags & AttribWorkspace) - blackbox_attrib.workspace = blackbox_hint->workspace; - - // if (blackbox_hint->flags & AttribStack) - // don't yet have always on top/bottom for blackbox yet... working - // on that - - if (blackbox_hint->flags & AttribDecoration) { - switch (blackbox_hint->decoration) { - case DecorNone: - blackbox_attrib.decoration = DecorNone; - break; - - case DecorTiny: - case DecorTool: - case DecorNormal: - default: - // blackbox_attrib.decoration defaults to DecorNormal - break; - } - } - - delete [] blackbox_hint; - - return True; -} - - -void BlackboxWindow::getTransientInfo(void) { - if (client.transient_for && - client.transient_for != (BlackboxWindow *) ~0ul) { - // reset transient_for in preparation of looking for a new owner - client.transient_for->client.transientList.remove(this); - } - - // we have no transient_for until we find a new one - client.transient_for = (BlackboxWindow *) 0; - - Window trans_for; - if (! XGetTransientForHint(blackbox->getXDisplay(), client.window, - &trans_for)) { - // transient_for hint not set - return; - } - - if (trans_for == client.window) { - // wierd client... treat this window as a normal window - return; - } - - if (trans_for == None || trans_for == screen->getRootWindow()) { - // this is an undocumented interpretation of the ICCCM. a transient - // associated with None/Root/itself is assumed to be a modal root - // transient. we don't support the concept of a global transient, - // so we just associate this transient with nothing, and perhaps - // we will add support later for global modality. - client.transient_for = (BlackboxWindow *) ~0ul; - flags.modal = True; - return; - } - - client.transient_for = blackbox->searchWindow(trans_for); - if (! client.transient_for && - client.window_group && trans_for == client.window_group) { - // no direct transient_for, perhaps this is a group transient? - BWindowGroup *group = blackbox->searchGroup(client.window_group); - if (group) client.transient_for = group->find(screen); - } - - if (! client.transient_for || client.transient_for == this) { - // no transient_for found, or we have a wierd client that wants to be - // a transient for itself, so we treat this window as a normal window - client.transient_for = (BlackboxWindow*) 0; - return; - } - - // Check for a circular transient state: this can lock up Blackbox - // when it tries to find the non-transient window for a transient. - BlackboxWindow *w = this; - while(w->client.transient_for && - w->client.transient_for != (BlackboxWindow *) ~0ul) { - if(w->client.transient_for == this) { - client.transient_for = (BlackboxWindow*) 0; - break; - } - w = w->client.transient_for; - } - - if (client.transient_for && - client.transient_for != (BlackboxWindow *) ~0ul) { - // register ourselves with our new transient_for - client.transient_for->client.transientList.push_back(this); - flags.stuck = client.transient_for->flags.stuck; - } -} - - -BlackboxWindow *BlackboxWindow::getTransientFor(void) const { - if (client.transient_for && - client.transient_for != (BlackboxWindow*) ~0ul) - return client.transient_for; - return 0; -} - - -/* - * This function is responsible for updating both the client and the frame - * rectangles. - * According to the ICCCM a client message is not sent for a resize, only a - * move. - */ -void BlackboxWindow::configure(int dx, int dy, - unsigned int dw, unsigned int dh) { - bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) && - ! flags.moving); - - if (dw != frame.rect.width() || dh != frame.rect.height()) { - frame.rect.setRect(dx, dy, dw, dh); - frame.inside_w = frame.rect.width() - (frame.border_w * 2); - frame.inside_h = frame.rect.height() - (frame.border_w * 2); - - if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0) - frame.rect.setPos(0, 0); - - client.rect.setCoords(frame.rect.left() + frame.margin.left, - frame.rect.top() + frame.margin.top, - frame.rect.right() - frame.margin.right, - frame.rect.bottom() - frame.margin.bottom); - -#ifdef SHAPE - if (blackbox->hasShapeExtensions() && flags.shaped) { - configureShape(); - } -#endif // SHAPE - - positionWindows(); - decorate(); - redrawWindowFrame(); - } else { - frame.rect.setPos(dx, dy); - - XMoveWindow(blackbox->getXDisplay(), frame.window, - frame.rect.x(), frame.rect.y()); - /* - we may have been called just after an opaque window move, so even though - the old coords match the new ones no ConfigureNotify has been sent yet. - There are likely other times when this will be relevant as well. - */ - if (! flags.moving) send_event = True; - } - - if (send_event) { - // if moving, the update and event will occur when the move finishes - client.rect.setPos(frame.rect.left() + frame.margin.left, - frame.rect.top() + frame.margin.top); - - XEvent event; - event.type = ConfigureNotify; - - event.xconfigure.display = blackbox->getXDisplay(); - event.xconfigure.event = client.window; - event.xconfigure.window = client.window; - event.xconfigure.x = client.rect.x(); - event.xconfigure.y = client.rect.y(); - event.xconfigure.width = client.rect.width(); - event.xconfigure.height = client.rect.height(); - event.xconfigure.border_width = client.old_bw; - event.xconfigure.above = frame.window; - event.xconfigure.override_redirect = False; - - XSendEvent(blackbox->getXDisplay(), client.window, False, - StructureNotifyMask, &event); - screen->updateNetizenConfigNotify(&event); - XFlush(blackbox->getXDisplay()); - } -} - - -#ifdef SHAPE -void BlackboxWindow::configureShape(void) { - XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding, - frame.margin.left - frame.border_w, - frame.margin.top - frame.border_w, - client.window, ShapeBounding, ShapeSet); - - int num = 0; - XRectangle xrect[2]; - - if (decorations & Decor_Titlebar) { - xrect[0].x = xrect[0].y = -frame.border_w; - xrect[0].width = frame.rect.width(); - xrect[0].height = frame.title_h + (frame.border_w * 2); - ++num; - } - - if (decorations & Decor_Handle) { - xrect[1].x = -frame.border_w; - xrect[1].y = frame.rect.height() - frame.margin.bottom + - frame.mwm_border_w - frame.border_w; - xrect[1].width = frame.rect.width(); - xrect[1].height = frame.handle_h + (frame.border_w * 2); - ++num; - } - - XShapeCombineRectangles(blackbox->getXDisplay(), frame.window, - ShapeBounding, 0, 0, xrect, num, - ShapeUnion, Unsorted); -} - - -void BlackboxWindow::clearShape(void) { - XShapeCombineMask(blackbox->getXDisplay(), frame.window, ShapeBounding, - frame.margin.left - frame.border_w, - frame.margin.top - frame.border_w, - None, ShapeSet); -} -#endif // SHAPE - - -bool BlackboxWindow::setInputFocus(void) { - if (flags.focused) return True; - - assert(flags.stuck || // window must be on the current workspace or sticky - blackbox_attrib.workspace == screen->getCurrentWorkspaceID()); - - /* - We only do this check for normal windows and dialogs because other windows - do this on purpose, such as kde's kicker, and we don't want to go moving - it. - */ - if (window_type == Type_Normal || window_type == Type_Dialog) - if (! frame.rect.intersects(screen->getRect())) { - // client is outside the screen, move it to the center - configure((screen->getWidth() - frame.rect.width()) / 2, - (screen->getHeight() - frame.rect.height()) / 2, - frame.rect.width(), frame.rect.height()); - } - - if (client.transientList.size() > 0) { - // transfer focus to any modal transients - BlackboxWindowList::iterator it, end = client.transientList.end(); - for (it = client.transientList.begin(); it != end; ++it) - if ((*it)->flags.modal) return (*it)->setInputFocus(); - } - - bool ret = True; - if (focus_mode == F_LocallyActive || focus_mode == F_Passive) { - XSetInputFocus(blackbox->getXDisplay(), client.window, - RevertToPointerRoot, CurrentTime); - } else { - /* we could set the focus to none, since the window doesn't accept focus, - * but we shouldn't set focus to nothing since this would surely make - * someone angry - */ - ret = False; - } - - if (flags.send_focus_message) { - XEvent ce; - ce.xclient.type = ClientMessage; - ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols); - ce.xclient.display = blackbox->getXDisplay(); - ce.xclient.window = client.window; - ce.xclient.format = 32; - ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus); - ce.xclient.data.l[1] = blackbox->getLastTime(); - ce.xclient.data.l[2] = 0l; - ce.xclient.data.l[3] = 0l; - ce.xclient.data.l[4] = 0l; - XSendEvent(blackbox->getXDisplay(), client.window, False, - NoEventMask, &ce); - XFlush(blackbox->getXDisplay()); - } - - return ret; -} - - -void BlackboxWindow::iconify(void) { - if (flags.iconic || ! (functions & Func_Iconify)) return; - - // We don't need to worry about resizing because resizing always grabs the X - // server. This should only ever happen if using opaque moving. - if (flags.moving) - endMove(); - - if (windowmenu) windowmenu->hide(); - - /* - * we don't want this XUnmapWindow call to generate an UnmapNotify event, so - * we need to clear the event mask on client.window for a split second. - * HOWEVER, since X11 is asynchronous, the window could be destroyed in that - * split second, leaving us with a ghost window... so, we need to do this - * while the X server is grabbed - */ - unsigned long event_mask = PropertyChangeMask | FocusChangeMask | - StructureNotifyMask; - XGrabServer(blackbox->getXDisplay()); - XSelectInput(blackbox->getXDisplay(), client.window, - event_mask & ~StructureNotifyMask); - XUnmapWindow(blackbox->getXDisplay(), client.window); - XSelectInput(blackbox->getXDisplay(), client.window, event_mask); - XUngrabServer(blackbox->getXDisplay()); - - XUnmapWindow(blackbox->getXDisplay(), frame.window); - flags.visible = False; - flags.iconic = True; - - setState(IconicState); - - screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this); - if (flags.stuck) { - for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) - if (i != blackbox_attrib.workspace) - screen->getWorkspace(i)->removeWindow(this, True); - } - - if (isTransient()) { - if (client.transient_for != (BlackboxWindow *) ~0ul && - ! client.transient_for->flags.iconic) { - // iconify our transient_for - client.transient_for->iconify(); - } - } - - screen->addIcon(this); - - if (client.transientList.size() > 0) { - // iconify all transients - BlackboxWindowList::iterator it, end = client.transientList.end(); - for (it = client.transientList.begin(); it != end; ++it) { - if (! (*it)->flags.iconic) (*it)->iconify(); - } - } - screen->updateStackingList(); -} - - -void BlackboxWindow::show(void) { - flags.visible = True; - flags.iconic = False; - - current_state = (flags.shaded) ? IconicState : NormalState; - setState(current_state); - - XMapWindow(blackbox->getXDisplay(), client.window); - XMapSubwindows(blackbox->getXDisplay(), frame.window); - XMapWindow(blackbox->getXDisplay(), frame.window); - -#if 0 - int real_x, real_y; - Window child; - XTranslateCoordinates(blackbox->getXDisplay(), client.window, - screen->getRootWindow(), - 0, 0, &real_x, &real_y, &child); - fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(), - client.rect.left(), client.rect.top(), real_x, real_y); - assert(client.rect.left() == real_x && client.rect.top() == real_y); -#endif -} - - -void BlackboxWindow::deiconify(bool reassoc, bool raise) { - if (flags.iconic || reassoc) - screen->reassociateWindow(this, BSENTINEL, False); - else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) - return; - - show(); - - // reassociate and deiconify all transients - if (reassoc && client.transientList.size() > 0) { - BlackboxWindowList::iterator it, end = client.transientList.end(); - for (it = client.transientList.begin(); it != end; ++it) - (*it)->deiconify(True, False); - } - - if (raise) - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); -} - - -void BlackboxWindow::close(void) { - if (! (functions & Func_Close)) return; - - XEvent ce; - ce.xclient.type = ClientMessage; - ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols); - ce.xclient.display = blackbox->getXDisplay(); - ce.xclient.window = client.window; - ce.xclient.format = 32; - ce.xclient.data.l[0] = xatom->getAtom(XAtom::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(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce); - XFlush(blackbox->getXDisplay()); -} - - -void BlackboxWindow::withdraw(void) { - // We don't need to worry about resizing because resizing always grabs the X - // server. This should only ever happen if using opaque moving. - if (flags.moving) - endMove(); - - flags.visible = False; - flags.iconic = False; - - setState(current_state); - - XUnmapWindow(blackbox->getXDisplay(), frame.window); - - XGrabServer(blackbox->getXDisplay()); - - unsigned long event_mask = PropertyChangeMask | FocusChangeMask | - StructureNotifyMask; - XSelectInput(blackbox->getXDisplay(), client.window, - event_mask & ~StructureNotifyMask); - XUnmapWindow(blackbox->getXDisplay(), client.window); - XSelectInput(blackbox->getXDisplay(), client.window, event_mask); - - XUngrabServer(blackbox->getXDisplay()); - - if (windowmenu) windowmenu->hide(); -} - - -void BlackboxWindow::maximize(unsigned int button) { - if (! (functions & Func_Maximize)) return; - - // We don't need to worry about resizing because resizing always grabs the X - // server. This should only ever happen if using opaque moving. - if (flags.moving) - endMove(); - - // handle case where menu is open then the max button is used instead - if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); - - if (flags.maximized) { - flags.maximized = 0; - - blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert); - blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert); - - /* - when a resize finishes, maximize(0) is called to clear any maximization - flags currently set. Otherwise it still thinks it is maximized. - so we do not need to call configure() because resizing will handle it - */ - if (! flags.resizing) - configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y, - blackbox_attrib.premax_w, blackbox_attrib.premax_h); - - blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; - blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; - - redrawAllButtons(); // in case it is not called in configure() - setState(current_state); - return; - } - - blackbox_attrib.premax_x = frame.rect.x(); - blackbox_attrib.premax_y = frame.rect.y(); - blackbox_attrib.premax_w = frame.rect.width(); - // use client.rect so that clients can be restored even if shaded - blackbox_attrib.premax_h = - client.rect.height() + frame.margin.top + frame.margin.bottom; - -#ifdef XINERAMA - if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) { - // find the area to use - RectList availableAreas = screen->allAvailableAreas(); - RectList::iterator it, end = availableAreas.end(); - - for (it = availableAreas.begin(); it != end; ++it) - if (it->intersects(frame.rect)) break; - if (it == end) // the window isn't inside an area - it = availableAreas.begin(); // so just default to the first one - - frame.changing = *it; - } else -#endif // XINERAMA - frame.changing = screen->availableArea(); - - switch(button) { - case 1: - blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert; - blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert; - break; - - case 2: - blackbox_attrib.flags |= AttribMaxVert; - blackbox_attrib.attrib |= AttribMaxVert; - - frame.changing.setX(frame.rect.x()); - frame.changing.setWidth(frame.rect.width()); - break; - - case 3: - blackbox_attrib.flags |= AttribMaxHoriz; - blackbox_attrib.attrib |= AttribMaxHoriz; - - frame.changing.setY(frame.rect.y()); - frame.changing.setHeight(frame.rect.height()); - break; - } - - constrain(TopLeft); - - if (flags.shaded) { - blackbox_attrib.flags ^= AttribShaded; - blackbox_attrib.attrib ^= AttribShaded; - flags.shaded = False; - } - - flags.maximized = button; - - configure(frame.changing.x(), frame.changing.y(), - frame.changing.width(), frame.changing.height()); - if (flags.focused) - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - redrawAllButtons(); // in case it is not called in configure() - setState(current_state); -} - - -// re-maximizes the window to take into account availableArea changes -void BlackboxWindow::remaximize(void) { - if (flags.shaded) { - // we only update the window's attributes otherwise we lose the shade bit - switch(flags.maximized) { - case 1: - blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert; - blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert; - break; - - case 2: - blackbox_attrib.flags |= AttribMaxVert; - blackbox_attrib.attrib |= AttribMaxVert; - break; - - case 3: - blackbox_attrib.flags |= AttribMaxHoriz; - blackbox_attrib.attrib |= AttribMaxHoriz; - break; - } - return; - } - - // save the original dimensions because maximize will wipe them out - int premax_x = blackbox_attrib.premax_x, - premax_y = blackbox_attrib.premax_y, - premax_w = blackbox_attrib.premax_w, - premax_h = blackbox_attrib.premax_h; - - unsigned int button = flags.maximized; - flags.maximized = 0; // trick maximize() into working - maximize(button); - - // restore saved values - blackbox_attrib.premax_x = premax_x; - blackbox_attrib.premax_y = premax_y; - blackbox_attrib.premax_w = premax_w; - blackbox_attrib.premax_h = premax_h; -} - - -void BlackboxWindow::setWorkspace(unsigned int n) { - blackbox_attrib.flags |= AttribWorkspace; - blackbox_attrib.workspace = n; - if (n == BSENTINEL) { // iconified window - /* - we set the workspace to 'all workspaces' so that taskbars will show the - window. otherwise, it made uniconifying a window imposible without the - blackbox workspace menu - */ - n = 0xffffffff; - } - xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n); -} - - -void BlackboxWindow::shade(void) { - if (flags.shaded) { - XResizeWindow(blackbox->getXDisplay(), frame.window, - frame.inside_w, frame.inside_h); - flags.shaded = False; - blackbox_attrib.flags ^= AttribShaded; - blackbox_attrib.attrib ^= AttribShaded; - - setState(NormalState); - - // set the frame rect to the normal size - frame.rect.setHeight(client.rect.height() + frame.margin.top + - frame.margin.bottom); - } else { - if (! (decorations & Decor_Titlebar)) - return; // can't shade it without a titlebar! - - XResizeWindow(blackbox->getXDisplay(), frame.window, - frame.inside_w, frame.title_h); - flags.shaded = True; - blackbox_attrib.flags |= AttribShaded; - blackbox_attrib.attrib |= AttribShaded; - - setState(IconicState); - - // set the frame rect to the shaded size - frame.rect.setHeight(frame.title_h + (frame.border_w * 2)); - } -} - - -/* - * (Un)Sticks a window and its relatives. - */ -void BlackboxWindow::stick(void) { - if (flags.stuck) { - blackbox_attrib.flags ^= AttribOmnipresent; - blackbox_attrib.attrib ^= AttribOmnipresent; - - flags.stuck = False; - - for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) - if (i != blackbox_attrib.workspace) - screen->getWorkspace(i)->removeWindow(this, True); - - if (! flags.iconic) - screen->reassociateWindow(this, BSENTINEL, True); - // temporary fix since sticky windows suck. set the hint to what we - // actually hold in our data. - xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, - blackbox_attrib.workspace); - - setState(current_state); - } else { - flags.stuck = True; - - blackbox_attrib.flags |= AttribOmnipresent; - blackbox_attrib.attrib |= AttribOmnipresent; - - // temporary fix since sticky windows suck. set the hint to a different - // value than that contained in the class' data. - xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, - 0xffffffff); - - for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) - if (i != blackbox_attrib.workspace) - screen->getWorkspace(i)->addWindow(this, False, True); - - setState(current_state); - } - - redrawAllButtons(); - - // go up the chain - if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul && - client.transient_for->isStuck() != flags.stuck) - client.transient_for->stick(); - // go down the chain - BlackboxWindowList::iterator it; - const BlackboxWindowList::iterator end = client.transientList.end(); - for (it = client.transientList.begin(); it != end; ++it) - if ((*it)->isStuck() != flags.stuck) - (*it)->stick(); -} - - -void BlackboxWindow::redrawWindowFrame(void) const { - if (decorations & Decor_Titlebar) { - if (flags.focused) { - if (frame.ftitle) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.title, frame.ftitle); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.title, frame.ftitle_pixel); - } else { - if (frame.utitle) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.title, frame.utitle); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.title, frame.utitle_pixel); - } - XClearWindow(blackbox->getXDisplay(), frame.title); - - redrawLabel(); - redrawAllButtons(); - } - - if (decorations & Decor_Handle) { - if (flags.focused) { - if (frame.fhandle) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.handle, frame.fhandle); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.handle, frame.fhandle_pixel); - - if (frame.fgrip) { - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.left_grip, frame.fgrip); - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.right_grip, frame.fgrip); - } else { - XSetWindowBackground(blackbox->getXDisplay(), - frame.left_grip, frame.fgrip_pixel); - XSetWindowBackground(blackbox->getXDisplay(), - frame.right_grip, frame.fgrip_pixel); - } - } else { - if (frame.uhandle) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.handle, frame.uhandle); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.handle, frame.uhandle_pixel); - - if (frame.ugrip) { - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.left_grip, frame.ugrip); - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.right_grip, frame.ugrip); - } else { - XSetWindowBackground(blackbox->getXDisplay(), - frame.left_grip, frame.ugrip_pixel); - XSetWindowBackground(blackbox->getXDisplay(), - frame.right_grip, frame.ugrip_pixel); - } - } - XClearWindow(blackbox->getXDisplay(), frame.handle); - XClearWindow(blackbox->getXDisplay(), frame.left_grip); - XClearWindow(blackbox->getXDisplay(), frame.right_grip); - } - - if (decorations & Decor_Border) { - if (flags.focused) - XSetWindowBorder(blackbox->getXDisplay(), - frame.plate, frame.fborder_pixel); - else - XSetWindowBorder(blackbox->getXDisplay(), - frame.plate, frame.uborder_pixel); - } -} - - -void BlackboxWindow::setFocusFlag(bool focus) { - // only focus a window if it is visible - if (focus && ! flags.visible) - return; - - flags.focused = focus; - - redrawWindowFrame(); - - if (flags.focused) - blackbox->setFocusedWindow(this); - - if (! flags.iconic) { - // iconic windows arent in a workspace menu! - if (flags.stuck) - screen->getCurrentWorkspace()->setFocused(this, isFocused()); - else - screen->getWorkspace(blackbox_attrib.workspace)-> - setFocused(this, flags.focused); - } -} - - -void BlackboxWindow::installColormap(bool install) { - int i = 0, ncmap = 0; - Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(), - client.window, &ncmap); - if (cmaps) { - XWindowAttributes wattrib; - if (XGetWindowAttributes(blackbox->getXDisplay(), - client.window, &wattrib)) { - if (install) { - // install the window's colormap - for (i = 0; i < ncmap; i++) { - if (*(cmaps + i) == wattrib.colormap) - // this window is using an installed color map... do not install - install = False; - } - // otherwise, install the window's colormap - if (install) - XInstallColormap(blackbox->getXDisplay(), wattrib.colormap); - } else { - // uninstall the window's colormap - for (i = 0; i < ncmap; i++) { - if (*(cmaps + i) == wattrib.colormap) - // we found the colormap to uninstall - XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap); - } - } - } - - XFree(cmaps); - } -} - - -void BlackboxWindow::setAllowedActions(void) { - Atom actions[7]; - int num = 0; - - actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade); - actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop); - actions[num++] = xatom->getAtom(XAtom::net_wm_action_close); - - if (functions & Func_Move) - actions[num++] = xatom->getAtom(XAtom::net_wm_action_move); - if (functions & Func_Resize) - actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize); - if (functions & Func_Maximize) { - actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz); - actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert); - } - - xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom, - actions, num); -} - - -void BlackboxWindow::setState(unsigned long new_state) { - current_state = new_state; - - unsigned long state[2]; - state[0] = current_state; - state[1] = None; - xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2); - - xatom->setValue(client.window, XAtom::blackbox_attributes, - XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib, - PropBlackboxAttributesElements); - - Atom netstate[8]; - int num = 0; - if (flags.modal) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal); - if (flags.shaded) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded); - if (flags.iconic) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden); - if (flags.skip_taskbar) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar); - if (flags.skip_pager) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager); - if (flags.fullscreen) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen); - if (flags.maximized == 1 || flags.maximized == 2) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert); - if (flags.maximized == 1 || flags.maximized == 3) - netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz); - xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom, - netstate, num); -} - - -bool BlackboxWindow::getState(void) { - bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state, - current_state); - if (! ret) current_state = 0; - return ret; -} - - -void BlackboxWindow::restoreAttributes(void) { - unsigned long num = PropBlackboxAttributesElements; - BlackboxAttributes *net; - if (! xatom->getValue(client.window, XAtom::blackbox_attributes, - XAtom::blackbox_attributes, num, - (unsigned long **)&net)) - return; - if (num < PropBlackboxAttributesElements) { - delete [] net; - return; - } - - if (net->flags & AttribShaded && net->attrib & AttribShaded) { - flags.shaded = False; - unsigned long orig_state = current_state; - shade(); - - /* - At this point in the life of a window, current_state should only be set - to IconicState if the window was an *icon*, not if it was shaded. - */ - if (orig_state != IconicState) - current_state = WithdrawnState; - } - - if (net->workspace != screen->getCurrentWorkspaceID() && - net->workspace < screen->getWorkspaceCount()) - screen->reassociateWindow(this, net->workspace, True); - - if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) && - (blackbox_attrib.workspace < screen->getWorkspaceCount())) { - // set to WithdrawnState so it will be mapped on the new workspace - if (current_state == NormalState) current_state = WithdrawnState; - } else if (current_state == WithdrawnState) { - // the window is on this workspace and is Withdrawn, so it is waiting to - // be mapped - current_state = NormalState; - } - - if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent && - ! flags.stuck) { - stick(); - - // if the window was on another workspace, it was going to be hidden. this - // specifies that the window should be mapped since it is sticky. - if (current_state == WithdrawnState) current_state = NormalState; - } - - if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) { - int x = net->premax_x, y = net->premax_y; - unsigned int w = net->premax_w, h = net->premax_h; - flags.maximized = 0; - - unsigned int m = 0; - if ((net->flags & AttribMaxHoriz) && - (net->flags & AttribMaxVert)) - m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; - else if (net->flags & AttribMaxVert) - m = (net->attrib & AttribMaxVert) ? 2 : 0; - else if (net->flags & AttribMaxHoriz) - m = (net->attrib & AttribMaxHoriz) ? 3 : 0; - - if (m) maximize(m); - - blackbox_attrib.premax_x = x; - blackbox_attrib.premax_y = y; - blackbox_attrib.premax_w = w; - blackbox_attrib.premax_h = h; - } - - if (net->flags & AttribDecoration) { - switch (net->decoration) { - case DecorNone: - enableDecor(False); - break; - - /* since tools only let you toggle this anyways, we'll just make that all - it supports for now. - */ - default: - case DecorNormal: - case DecorTiny: - case DecorTool: - enableDecor(True); - break; - } - } - - // with the state set it will then be the map event's job to read the - // window's state and behave accordingly - - delete [] net; -} - - -/* - * Positions the Rect r according the the client window position and - * window gravity. - */ -void BlackboxWindow::applyGravity(Rect &r) { - // apply horizontal window gravity - switch (client.win_gravity) { - default: - case NorthWestGravity: - case SouthWestGravity: - case WestGravity: - r.setX(client.rect.x()); - break; - - case NorthGravity: - case SouthGravity: - case CenterGravity: - r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2); - break; - - case NorthEastGravity: - case SouthEastGravity: - case EastGravity: - r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2); - break; - - case ForgetGravity: - case StaticGravity: - r.setX(client.rect.x() - frame.margin.left); - break; - } - - // apply vertical window gravity - switch (client.win_gravity) { - default: - case NorthWestGravity: - case NorthEastGravity: - case NorthGravity: - r.setY(client.rect.y()); - break; - - case CenterGravity: - case EastGravity: - case WestGravity: - r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2); - break; - - case SouthWestGravity: - case SouthEastGravity: - case SouthGravity: - r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2); - break; - - case ForgetGravity: - case StaticGravity: - r.setY(client.rect.y() - frame.margin.top); - break; - } -} - - -/* - * The reverse of the applyGravity function. - * - * Positions the Rect r according to the frame window position and - * window gravity. - */ -void BlackboxWindow::restoreGravity(Rect &r) { - // restore horizontal window gravity - switch (client.win_gravity) { - default: - case NorthWestGravity: - case SouthWestGravity: - case WestGravity: - r.setX(frame.rect.x()); - break; - - case NorthGravity: - case SouthGravity: - case CenterGravity: - r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2); - break; - - case NorthEastGravity: - case SouthEastGravity: - case EastGravity: - r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2); - break; - - case ForgetGravity: - case StaticGravity: - r.setX(frame.rect.x() + frame.margin.left); - break; - } - - // restore vertical window gravity - switch (client.win_gravity) { - default: - case NorthWestGravity: - case NorthEastGravity: - case NorthGravity: - r.setY(frame.rect.y()); - break; - - case CenterGravity: - case EastGravity: - case WestGravity: - r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2); - break; - - case SouthWestGravity: - case SouthEastGravity: - case SouthGravity: - r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2); - break; - - case ForgetGravity: - case StaticGravity: - r.setY(frame.rect.y() + frame.margin.top); - break; - } -} - - -void BlackboxWindow::redrawLabel(void) const { - if (flags.focused) { - if (frame.flabel) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.label, frame.flabel); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.label, frame.flabel_pixel); - } else { - if (frame.ulabel) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), - frame.label, frame.ulabel); - else - XSetWindowBackground(blackbox->getXDisplay(), - frame.label, frame.ulabel_pixel); - } - XClearWindow(blackbox->getXDisplay(), frame.label); - - WindowStyle *style = screen->getWindowStyle(); - - int pos = frame.bevel_w * 2; - style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4); - style->font->drawString(frame.label, pos, 1, - (flags.focused ? style->l_text_focus : - style->l_text_unfocus), - client.title); -} - - -void BlackboxWindow::redrawAllButtons(void) const { - if (frame.iconify_button) redrawIconifyButton(False); - if (frame.maximize_button) redrawMaximizeButton(flags.maximized); - if (frame.close_button) redrawCloseButton(False); - if (frame.stick_button) redrawStickyButton(flags.stuck); -} - - -void BlackboxWindow::redrawButton(bool pressed, Window win, - Pixmap fppix, unsigned long fppixel, - Pixmap uppix, unsigned long uppixel, - Pixmap fpix, unsigned long fpixel, - Pixmap upix, unsigned long upixel) const { - Pixmap p; - unsigned long pix; - - if (pressed) { - if (flags.focused) { - p = fppix; - pix = fppixel; - } else { - p = uppix; - pix = uppixel; - } - } else { - if (flags.focused) { - p = fpix; - pix = fpixel; - } else { - p = upix; - pix = upixel; - } - } - - if (p) - XSetWindowBackgroundPixmap(blackbox->getXDisplay(), win, p); - else - XSetWindowBackground(blackbox->getXDisplay(), win, pix); - -} - -void BlackboxWindow::redrawIconifyButton(bool pressed) const { - redrawButton(pressed, frame.iconify_button, - frame.pfbutton, frame.pfbutton_pixel, - frame.pubutton, frame.pubutton_pixel, - frame.fbutton, frame.fbutton_pixel, - frame.ubutton, frame.ubutton_pixel); - - XClearWindow(blackbox->getXDisplay(), frame.iconify_button); - BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : - screen->getWindowStyle()->b_pic_unfocus); - -#ifdef BITMAPBUTTONS - PixmapMask pm = screen->getWindowStyle()->icon_button; - - if (screen->getWindowStyle()->icon_button.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); - - XFillRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, - (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); - - XSetClipMask(blackbox->getXDisplay(), pen.gc(), None); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0); - } else { -#endif // BITMAPBUTTONS - XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(), - 2, (frame.button_w - 5), (frame.button_w - 5), 2); -#ifdef BITMAPBUTTONS - } -#endif // BITMAPBUTTONS -} - - -void BlackboxWindow::redrawMaximizeButton(bool pressed) const { - redrawButton(pressed, frame.maximize_button, - frame.pfbutton, frame.pfbutton_pixel, - frame.pubutton, frame.pubutton_pixel, - frame.fbutton, frame.fbutton_pixel, - frame.ubutton, frame.ubutton_pixel); - - XClearWindow(blackbox->getXDisplay(), frame.maximize_button); - - BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : - screen->getWindowStyle()->b_pic_unfocus); - -#ifdef BITMAPBUTTONS - PixmapMask pm = screen->getWindowStyle()->max_button; - - if (pm.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); - - XFillRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, - (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); - - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); - XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); - } else { -#endif // BITMAPBUTTONS - XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), - 2, 2, (frame.button_w - 5), (frame.button_w - 5)); - XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), - 2, 3, (frame.button_w - 3), 3); -#ifdef BITMAPBUTTONS - } -#endif // BITMAPBUTTONS -} - - -void BlackboxWindow::redrawCloseButton(bool pressed) const { - redrawButton(pressed, frame.close_button, - frame.pfbutton, frame.pfbutton_pixel, - frame.pubutton, frame.pubutton_pixel, - frame.fbutton, frame.fbutton_pixel, - frame.ubutton, frame.ubutton_pixel); - - XClearWindow(blackbox->getXDisplay(), frame.close_button); - - BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : - screen->getWindowStyle()->b_pic_unfocus); - -#ifdef BITMAPBUTTONS - PixmapMask pm = screen->getWindowStyle()->close_button; - - if (pm.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); - - XFillRectangle(blackbox->getXDisplay(), frame.close_button, pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, - (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); - - - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); - XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); - } else { -#endif // BITMAPBUTTONS - XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(), - 2, 2, (frame.button_w - 3), (frame.button_w - 3)); - XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(), - 2, (frame.button_w - 3), (frame.button_w - 3), 2); -#ifdef BITMAPBUTTONS - } -#endif // BITMAPBUTTONS -} - -void BlackboxWindow::redrawStickyButton(bool pressed) const { - redrawButton(pressed, frame.stick_button, - frame.pfbutton, frame.pfbutton_pixel, - frame.pubutton, frame.pubutton_pixel, - frame.fbutton, frame.fbutton_pixel, - frame.ubutton, frame.ubutton_pixel); - - XClearWindow(blackbox->getXDisplay(), frame.stick_button); - - BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : - screen->getWindowStyle()->b_pic_unfocus); - -#ifdef BITMAPBUTTONS - PixmapMask pm = screen->getWindowStyle()->stick_button; - - if (pm.mask != None) { - XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); - - XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(), - (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, - (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); - - - XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); - XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); - } else { -#endif // BITMAPBUTTONS - XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(), - frame.button_w/2 - 1, frame.button_w/2 -1, 2, 2 ); -#ifdef BITMAPBUTTONS - } -#endif -} - -void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { - if (re->window != client.window) - return; - -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n", - client.window); -#endif // DEBUG - - /* - Even though the window wants to be shown, if it is not on the current - workspace, then it isn't going to be shown right now. - */ - if (! flags.stuck && - blackbox_attrib.workspace != screen->getCurrentWorkspaceID() && - blackbox_attrib.workspace < screen->getWorkspaceCount()) - if (current_state == NormalState) current_state = WithdrawnState; - - switch (current_state) { - case IconicState: - iconify(); - break; - - case WithdrawnState: - withdraw(); - break; - - case NormalState: - case InactiveState: - case ZoomState: - default: - show(); - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - if (isNormal()) { - if (! blackbox->isStartup()) { - XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped - if (screen->doFocusNew() || (isTransient() && getTransientFor() && - getTransientFor()->isFocused())) { - setInputFocus(); - } - if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) { - int x, y, rx, ry; - Window c, r; - unsigned int m; - XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(), - &r, &c, &rx, &ry, &x, &y, &m); - beginMove(rx, ry); - } - } - } - break; - } -} - - -void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) { - if (ue->window != client.window) - return; - -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n", - client.window); -#endif // DEBUG - - screen->unmanageWindow(this, False); -} - - -void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) { - if (de->window != client.window) - return; - -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n", - client.window); -#endif // DEBUG - - screen->unmanageWindow(this, False); -} - - -void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) { - if (re->window != client.window || re->parent == frame.plate) - return; - -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to " - "0x%lx.\n", client.window, re->parent); -#endif // DEBUG - - XEvent ev; - ev.xreparent = *re; - XPutBackEvent(blackbox->getXDisplay(), &ev); - screen->unmanageWindow(this, True); -} - - -void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { - if (pe->state == PropertyDelete || ! validateClient()) - return; - -#if 0 - fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n", - client.window); -#endif - - switch(pe->atom) { - case XA_WM_CLASS: - case XA_WM_CLIENT_MACHINE: - case XA_WM_COMMAND: - break; - - case XA_WM_TRANSIENT_FOR: { - bool s = flags.stuck; - - // determine if this is a transient window - getTransientInfo(); - - if (flags.stuck != s) stick(); - - // adjust the window decorations based on transience - if (isTransient()) { - functions &= ~Func_Maximize; - setAllowedActions(); - setupDecor(); - } - - reconfigure(); - } - break; - - case XA_WM_HINTS: - getWMHints(); - break; - - case XA_WM_ICON_NAME: - getWMIconName(); - if (flags.iconic) screen->propagateWindowName(this); - break; - - case XAtom::net_wm_name: - case XA_WM_NAME: - getWMName(); - - if (decorations & Decor_Titlebar) - redrawLabel(); - - screen->propagateWindowName(this); - break; - - case XA_WM_NORMAL_HINTS: { - getWMNormalHints(); - - if ((client.normal_hint_flags & PMinSize) && - (client.normal_hint_flags & PMaxSize)) { - // the window now can/can't resize itself, so the buttons need to be - // regrabbed. - ungrabButtons(); - if (client.max_width <= client.min_width && - client.max_height <= client.min_height) { - functions &= ~(Func_Resize | Func_Maximize); - } else { - if (! isTransient()) - functions |= Func_Maximize; - functions |= Func_Resize; - } - grabButtons(); - setAllowedActions(); - setupDecor(); - } - - Rect old_rect = frame.rect; - - upsize(); - - if (old_rect != frame.rect) - reconfigure(); - - break; - } - - default: - if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) { - getWMProtocols(); - - if ((decorations & Decor_Close) && (! frame.close_button)) { - createCloseButton(); - if (decorations & Decor_Titlebar) { - positionButtons(True); - XMapSubwindows(blackbox->getXDisplay(), frame.title); - } - if (windowmenu) windowmenu->reconfigure(); - } - } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) { - updateStrut(); - } - - break; - } -} - - -void BlackboxWindow::exposeEvent(const XExposeEvent *ee) { -#if 0 - fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window); -#endif - - if (frame.label == ee->window && (decorations & Decor_Titlebar)) - redrawLabel(); - else if (frame.close_button == ee->window) - redrawCloseButton(False); - else if (frame.maximize_button == ee->window) - redrawMaximizeButton(flags.maximized); - else if (frame.iconify_button == ee->window) - redrawIconifyButton(False); - else if (frame.stick_button == ee->window) - redrawStickyButton(flags.stuck); -} - - -void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { - if (cr->window != client.window || flags.iconic) - return; - - if (cr->value_mask & CWBorderWidth) - client.old_bw = cr->border_width; - - if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) { - frame.changing = frame.rect; - - if (cr->value_mask & (CWX | CWY)) { - if (cr->value_mask & CWX) - client.rect.setX(cr->x); - if (cr->value_mask & CWY) - client.rect.setY(cr->y); - - applyGravity(frame.changing); - } - - if (cr->value_mask & (CWWidth | CWHeight)) { - if (cr->value_mask & CWWidth) - frame.changing.setWidth(cr->width + - frame.margin.left + frame.margin.right); - - if (cr->value_mask & CWHeight) - frame.changing.setHeight(cr->height + - frame.margin.top + frame.margin.bottom); - - /* - if a position change has been specified, then that position will be - used instead of determining a position based on the window's gravity. - */ - if (! (cr->value_mask & (CWX | CWY))) { - Corner corner; - switch (client.win_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; - } - constrain(corner); - } - } - - configure(frame.changing.x(), frame.changing.y(), - frame.changing.width(), frame.changing.height()); - } - - if (cr->value_mask & CWStackMode && !isDesktop()) { - switch (cr->detail) { - case Below: - case BottomIf: - screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this); - break; - - case Above: - case TopIf: - default: - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - break; - } - } -} - - -void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n", - client.window); -#endif - - if (frame.maximize_button == be->window && be->button <= 3) { - redrawMaximizeButton(True); - } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) { - if (! flags.focused) - setInputFocus(); - - if (frame.iconify_button == be->window) { - redrawIconifyButton(True); - } else if (frame.close_button == be->window) { - redrawCloseButton(True); - } else if (frame.stick_button == be->window) { - redrawStickyButton(True); - } else if (frame.plate == be->window) { - if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); - - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - - XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time); - } else { - if (frame.title == be->window || frame.label == be->window) { - if (((be->time - lastButtonPressTime) <= - blackbox->getDoubleClickInterval()) || - (be->state == ControlMask)) { - lastButtonPressTime = 0; - shade(); - } else { - lastButtonPressTime = be->time; - } - } - - if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); - - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - } - } else if (be->button == 2 && (be->window != frame.iconify_button) && - (be->window != frame.close_button) && - (be->window != frame.stick_button)) { - screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this); - } else if (windowmenu && be->button == 3 && - (frame.title == be->window || frame.label == be->window || - frame.handle == be->window || frame.window == be->window)) { - if (windowmenu->isVisible()) { - windowmenu->hide(); - } else { - int mx = be->x_root - windowmenu->getWidth() / 2, - my = be->y_root - windowmenu->getHeight() / 2; - - // snap the window menu into a corner/side if necessary - int left_edge, right_edge, top_edge, bottom_edge; - - /* - the " + (frame.border_w * 2) - 1" bits are to get the proper width - and height of the menu, as the sizes returned by it do not include - the borders. - */ - left_edge = frame.rect.x(); - right_edge = frame.rect.right() - - (windowmenu->getWidth() + (frame.border_w * 2) - 1); - top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w); - bottom_edge = client.rect.bottom() - - (windowmenu->getHeight() + (frame.border_w * 2) - 1) + - (frame.border_w + frame.mwm_border_w); - - if (mx < left_edge) - mx = left_edge; - else if (mx > right_edge) - mx = right_edge; - if (my < top_edge) - my = top_edge; - else if (my > bottom_edge) - my = bottom_edge; - - if (my + windowmenu->getHeight() > screen->getHeight()) - my = screen->getHeight() - windowmenu->getHeight() - - (screen->getBorderWidth() * 2); - - windowmenu->move(mx, my); - windowmenu->show(); - XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID()); - XRaiseWindow(blackbox->getXDisplay(), - windowmenu->getSendToMenu()->getWindowID()); - } - // mouse wheel up - } else if (be->button == 4) { - if ((be->window == frame.label || - be->window == frame.title || - be->window == frame.maximize_button || - be->window == frame.iconify_button || - be->window == frame.close_button || - be->window == frame.stick_button) && - ! flags.shaded) - shade(); - // mouse wheel down - } else if (be->button == 5) { - if ((be->window == frame.label || - be->window == frame.title || - be->window == frame.maximize_button || - be->window == frame.iconify_button || - be->window == frame.close_button || - be->window == frame.stick_button) && - flags.shaded) - shade(); - } -} - - -void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { -#ifdef DEBUG - fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n", - client.window); -#endif - - if (re->window == frame.maximize_button && - re->button >= 1 && re->button <= 3) { - if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && - (re->y >= 0 && re->y <= static_cast(frame.button_w))) { - maximize(re->button); - } else { - redrawMaximizeButton(flags.maximized); - } - } else if (re->window == frame.iconify_button && re->button == 1) { - if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && - (re->y >= 0 && re->y <= static_cast(frame.button_w))) { - iconify(); - } else { - redrawIconifyButton(False); - } - } else if (re->window == frame.stick_button && re->button == 1) { - if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && - (re->y >= 0 && re->y <= static_cast(frame.button_w))) { - stick(); - } else { - redrawStickyButton(False); - } - } else if (re->window == frame.close_button & re->button == 1) { - if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && - (re->y >= 0 && re->y <= static_cast(frame.button_w))) - close(); - redrawCloseButton(False); - } else if (flags.moving) { - endMove(); - } else if (flags.resizing) { - endResize(); - } else if (re->window == frame.window) { - if (re->button == 2 && re->state == mod_mask) - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - } -} - - - -void BlackboxWindow::beginMove(int x_root, int y_root) { - if (! (functions & Func_Move)) return; - - assert(! (flags.resizing || flags.moving)); - - /* - Only one window can be moved/resized at a time. If another window is already - being moved or resized, then stop it before whating to work with this one. - */ - BlackboxWindow *changing = blackbox->getChangingWindow(); - if (changing && changing != this) { - if (changing->flags.moving) - changing->endMove(); - else // if (changing->flags.resizing) - changing->endResize(); - } - - XGrabPointer(blackbox->getXDisplay(), frame.window, False, - PointerMotionMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, - None, blackbox->getMoveCursor(), CurrentTime); - - if (windowmenu && windowmenu->isVisible()) - windowmenu->hide(); - - flags.moving = True; - blackbox->setChangingWindow(this); - - if (! screen->doOpaqueMove()) { - XGrabServer(blackbox->getXDisplay()); - - frame.changing = frame.rect; - screen->showPosition(frame.changing.x(), frame.changing.y()); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), - frame.changing.x(), - frame.changing.y(), - frame.changing.width() - 1, - frame.changing.height() - 1); - } - - frame.grab_x = x_root - frame.rect.x() - frame.border_w; - frame.grab_y = y_root - frame.rect.y() - frame.border_w; -} - - -void BlackboxWindow::doMove(int x_root, int y_root) { - assert(flags.moving); - assert(blackbox->getChangingWindow() == this); - - int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y; - dx -= frame.border_w; - dy -= frame.border_w; - - doWindowSnapping(dx, dy); - - if (screen->doOpaqueMove()) { - if (screen->doWorkspaceWarping()) - doWorkspaceWarping(x_root, y_root, dx); - - configure(dx, dy, frame.rect.width(), frame.rect.height()); - } else { - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), - frame.changing.x(), - frame.changing.y(), - frame.changing.width() - 1, - frame.changing.height() - 1); - - if (screen->doWorkspaceWarping()) - doWorkspaceWarping(x_root, y_root, dx); - - frame.changing.setPos(dx, dy); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), - frame.changing.x(), - frame.changing.y(), - frame.changing.width() - 1, - frame.changing.height() - 1); - } - - screen->showPosition(dx, dy); -} - - -void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) { - // workspace warping - bool warp = False; - unsigned int dest = screen->getCurrentWorkspaceID(); - if (x_root <= 0) { - warp = True; - - if (dest > 0) dest--; - else dest = screen->getNumberOfWorkspaces() - 1; - - } else if (x_root >= screen->getRect().right()) { - warp = True; - - if (dest < screen->getNumberOfWorkspaces() - 1) dest++; - else dest = 0; - } - if (! warp) - return; - - bool focus = flags.focused; // had focus while moving? - - int dest_x = x_root; - if (x_root <= 0) { - dest_x += screen->getRect().width() - 1; - dx += screen->getRect().width() - 1; - } else { - dest_x -= screen->getRect().width() - 1; - dx -= screen->getRect().width() - 1; - } - - if (! flags.stuck) - screen->reassociateWindow(this, dest, False); - screen->changeWorkspaceID(dest); - - if (screen->doOpaqueMove()) - XGrabServer(blackbox->getXDisplay()); - - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - XWarpPointer(blackbox->getXDisplay(), None, - screen->getRootWindow(), 0, 0, 0, 0, - dest_x, y_root); - XGrabPointer(blackbox->getXDisplay(), frame.window, False, - PointerMotionMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, - None, blackbox->getMoveCursor(), CurrentTime); - - if (screen->doOpaqueMove()) - XUngrabServer(blackbox->getXDisplay()); - - if (focus) - setInputFocus(); - -} - - -void BlackboxWindow::doWindowSnapping(int &dx, int &dy) { - // how much resistance to edges to provide - const int resistance_size = screen->getResistanceSize(); - - // how far away to snap - const int snap_distance = screen->getSnapThreshold(); - - // how to snap windows - const int snap_to_windows = screen->getWindowToWindowSnap(); - const int snap_to_edges = screen->getWindowToEdgeSnap(); - // the amount of space away from the edge to provide resistance/snap - const int snap_offset = screen->getSnapOffset(); - - // find the geomeetery where the moving window currently is - const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing; - - // window corners - const int wleft = dx, - wright = dx + frame.rect.width() - 1, - wtop = dy, - wbottom = dy + frame.rect.height() - 1; - - if (snap_to_windows) { - RectList rectlist; - - Workspace *w = screen->getWorkspace(getWorkspaceNumber()); - assert(w); - - // add windows on the workspace to the rect list - const BlackboxWindowList& stack_list = w->getStackingList(); - BlackboxWindowList::const_iterator st_it, st_end = stack_list.end(); - for (st_it = stack_list.begin(); st_it != st_end; ++st_it) - if (*st_it != this) // don't snap to ourself - rectlist.push_back( (*st_it)->frameRect() ); - - // add the toolbar and the slit to the rect list. - // (only if they are not hidden) - Toolbar *tbar = screen->getToolbar(); - Slit *slit = screen->getSlit(); - Rect tbar_rect, slit_rect; - unsigned int bwidth = screen->getBorderWidth() * 2; - - if (! (screen->doHideToolbar() || tbar->isHidden())) { - tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth, - tbar->getHeight() + bwidth); - rectlist.push_back(tbar_rect); - } - - if (! slit->isHidden()) { - slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth, - slit->getHeight() + bwidth); - rectlist.push_back(slit_rect); - } - - RectList::const_iterator it, end = rectlist.end(); - for (it = rectlist.begin(); it != end; ++it) { - bool snapped = False; - const Rect &winrect = *it; - Rect offsetrect; - offsetrect.setCoords(winrect.left() - snap_offset, - winrect.top() - snap_offset, - winrect.right() + snap_offset, - winrect.bottom() + snap_offset); - - if (snap_to_windows == BScreen::WindowResistance) - // if the window is already over top of this snap target, then - // resistance is futile, so just ignore it - if (winrect.intersects(moving)) - continue; - - int dleft, dright, dtop, dbottom; - - // if the windows are in the same plane vertically - if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) && - wtop < (signed)(winrect.y() + winrect.height() - 1)) { - - if (snap_to_windows == BScreen::WindowResistance) { - dleft = wright - offsetrect.left(); - dright = offsetrect.right() - wleft; - - // snap left of other window? - if (dleft >= 0 && dleft < resistance_size && - dleft < (wright - wleft)) { - dx = offsetrect.left() - frame.rect.width(); - snapped = True; - } - // snap right of other window? - else if (dright >= 0 && dright < resistance_size && - dright < (wright - wleft)) { - dx = offsetrect.right() + 1; - snapped = True; - } - } else { // BScreen::WindowSnap - dleft = abs(wright - offsetrect.left()); - dright = abs(wleft - offsetrect.right()); - - // snap left of other window? - if (dleft < snap_distance && dleft <= dright) { - dx = offsetrect.left() - frame.rect.width(); - snapped = True; - } - // snap right of other window? - else if (dright < snap_distance) { - dx = offsetrect.right() + 1; - snapped = True; - } - } - - if (snapped) { - if (screen->getWindowCornerSnap()) { - // try corner-snap to its other sides - if (snap_to_windows == BScreen::WindowResistance) { - dtop = winrect.top() - wtop; - dbottom = wbottom - winrect.bottom(); - if (dtop > 0 && dtop < resistance_size) { - // if we're already past the top edge, then don't provide - // resistance - if (moving.top() >= winrect.top()) - dy = winrect.top(); - } else if (dbottom > 0 && dbottom < resistance_size) { - // if we're already past the bottom edge, then don't provide - // resistance - if (moving.bottom() <= winrect.bottom()) - dy = winrect.bottom() - frame.rect.height() + 1; - } - } else { // BScreen::WindowSnap - dtop = abs(wtop - winrect.top()); - dbottom = abs(wbottom - winrect.bottom()); - if (dtop < snap_distance && dtop <= dbottom) - dy = winrect.top(); - else if (dbottom < snap_distance) - dy = winrect.bottom() - frame.rect.height() + 1; - } - } - - continue; - } - } - - // if the windows are on the same plane horizontally - if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) && - wleft < (signed)(winrect.x() + winrect.width() - 1)) { - - if (snap_to_windows == BScreen::WindowResistance) { - dtop = wbottom - offsetrect.top(); - dbottom = offsetrect.bottom() - wtop; - - // snap top of other window? - if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) { - dy = offsetrect.top() - frame.rect.height(); - snapped = True; - } - // snap bottom of other window? - else if (dbottom >= 0 && dbottom < resistance_size && - dbottom < (wbottom - wtop)) { - dy = offsetrect.bottom() + 1; - snapped = True; - } - } else { // BScreen::WindowSnap - dtop = abs(wbottom - offsetrect.top()); - dbottom = abs(wtop - offsetrect.bottom()); - - // snap top of other window? - if (dtop < snap_distance && dtop <= dbottom) { - dy = offsetrect.top() - frame.rect.height(); - snapped = True; - } - // snap bottom of other window? - else if (dbottom < snap_distance) { - dy = offsetrect.bottom() + 1; - snapped = True; - } - - } - - if (snapped) { - if (screen->getWindowCornerSnap()) { - // try corner-snap to its other sides - if (snap_to_windows == BScreen::WindowResistance) { - dleft = winrect.left() - wleft; - dright = wright - winrect.right(); - if (dleft > 0 && dleft < resistance_size) { - // if we're already past the left edge, then don't provide - // resistance - if (moving.left() >= winrect.left()) - dx = winrect.left(); - } else if (dright > 0 && dright < resistance_size) { - // if we're already past the right edge, then don't provide - // resistance - if (moving.right() <= winrect.right()) - dx = winrect.right() - frame.rect.width() + 1; - } - } else { // BScreen::WindowSnap - dleft = abs(wleft - winrect.left()); - dright = abs(wright - winrect.right()); - if (dleft < snap_distance && dleft <= dright) - dx = winrect.left(); - else if (dright < snap_distance) - dx = winrect.right() - frame.rect.width() + 1; - } - } - - continue; - } - } - } - } - - if (snap_to_edges) { - RectList rectlist; - - // snap to the screen edges (and screen boundaries for xinerama) -#ifdef XINERAMA - if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) { - rectlist.insert(rectlist.begin(), - screen->getXineramaAreas().begin(), - screen->getXineramaAreas().end()); - } else -#endif // XINERAMA - rectlist.push_back(screen->getRect()); - - RectList::const_iterator it, end = rectlist.end(); - for (it = rectlist.begin(); it != end; ++it) { - const Rect &srect = *it; - Rect offsetrect; - offsetrect.setCoords(srect.left() + snap_offset, - srect.top() + snap_offset, - srect.right() - snap_offset, - srect.bottom() - snap_offset); - - if (snap_to_edges == BScreen::WindowResistance) { - // if we're not in the rectangle then don't snap to it. - if (! srect.contains(moving)) - continue; - } else { // BScreen::WindowSnap - // if we're not in the rectangle then don't snap to it. - if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(), - frame.rect.height()))) - continue; - } - - if (snap_to_edges == BScreen::WindowResistance) { - int dleft = offsetrect.left() - wleft, - dright = wright - offsetrect.right(), - dtop = offsetrect.top() - wtop, - dbottom = wbottom - offsetrect.bottom(); - - // snap left? - if (dleft > 0 && dleft < resistance_size) - dx = offsetrect.left(); - // snap right? - else if (dright > 0 && dright < resistance_size) - dx = offsetrect.right() - frame.rect.width() + 1; - - // snap top? - if (dtop > 0 && dtop < resistance_size) - dy = offsetrect.top(); - // snap bottom? - else if (dbottom > 0 && dbottom < resistance_size) - dy = offsetrect.bottom() - frame.rect.height() + 1; - } else { // BScreen::WindowSnap - int dleft = abs(wleft - offsetrect.left()), - dright = abs(wright - offsetrect.right()), - dtop = abs(wtop - offsetrect.top()), - dbottom = abs(wbottom - offsetrect.bottom()); - - // snap left? - if (dleft < snap_distance && dleft <= dright) - dx = offsetrect.left(); - // snap right? - else if (dright < snap_distance) - dx = offsetrect.right() - frame.rect.width() + 1; - - // snap top? - if (dtop < snap_distance && dtop <= dbottom) - dy = offsetrect.top(); - // snap bottom? - else if (dbottom < snap_distance) - dy = offsetrect.bottom() - frame.rect.height() + 1; - } - } - } -} - - -void BlackboxWindow::endMove(void) { - assert(flags.moving); - assert(blackbox->getChangingWindow() == this); - - flags.moving = False; - blackbox->setChangingWindow(0); - - if (! screen->doOpaqueMove()) { - /* when drawing the rubber band, we need to make sure we only draw inside - * the frame... frame.changing_* contain the new coords for the window, - * so we need to subtract 1 from changing_w/changing_h every where we - * draw the rubber band (for both moving and resizing) - */ - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), frame.changing.x(), frame.changing.y(), - frame.changing.width() - 1, frame.changing.height() - 1); - XUngrabServer(blackbox->getXDisplay()); - - configure(frame.changing.x(), frame.changing.y(), - frame.changing.width(), frame.changing.height()); - } else { - configure(frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height()); - } - screen->hideGeometry(); - - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - - // if there are any left over motions from the move, drop them now - XSync(blackbox->getXDisplay(), false); // make sure we don't miss any - XEvent e; - while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window, - MotionNotify, &e)); -} - - -void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) { - if (! (functions & Func_Resize)) return; - - assert(! (flags.resizing || flags.moving)); - - /* - Only one window can be moved/resized at a time. If another window is - already being moved or resized, then stop it before whating to work with - this one. - */ - BlackboxWindow *changing = blackbox->getChangingWindow(); - if (changing && changing != this) { - if (changing->flags.moving) - changing->endMove(); - else // if (changing->flags.resizing) - changing->endResize(); - } - - resize_dir = dir; - - Cursor cursor; - Corner anchor; - - switch (resize_dir) { - case BottomLeft: - anchor = TopRight; - cursor = blackbox->getLowerLeftAngleCursor(); - break; - - case BottomRight: - anchor = TopLeft; - cursor = blackbox->getLowerRightAngleCursor(); - break; - - case TopLeft: - anchor = BottomRight; - cursor = blackbox->getUpperLeftAngleCursor(); - break; - - case TopRight: - anchor = BottomLeft; - cursor = blackbox->getUpperRightAngleCursor(); - break; - - default: - assert(false); // unhandled Corner - return; // unreachable, for the compiler - } - - XGrabServer(blackbox->getXDisplay()); - XGrabPointer(blackbox->getXDisplay(), frame.window, False, - PointerMotionMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); - - flags.resizing = True; - blackbox->setChangingWindow(this); - - unsigned int gw, gh; - frame.changing = frame.rect; - - constrain(anchor, &gw, &gh); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), frame.changing.x(), frame.changing.y(), - frame.changing.width() - 1, frame.changing.height() - 1); - - screen->showGeometry(gw, gh); - - frame.grab_x = x_root; - frame.grab_y = y_root; -} - - -void BlackboxWindow::doResize(int x_root, int y_root) { - assert(flags.resizing); - assert(blackbox->getChangingWindow() == this); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), frame.changing.x(), frame.changing.y(), - frame.changing.width() - 1, frame.changing.height() - 1); - - unsigned int gw, gh; - Corner anchor; - int dx, dy; // the amount of change in the size of the window - - switch (resize_dir) { - case BottomLeft: - anchor = TopRight; - dx = - (x_root - frame.grab_x); - dy = + (y_root - frame.grab_y); - break; - case BottomRight: - anchor = TopLeft; - dx = + (x_root - frame.grab_x); - dy = + (y_root - frame.grab_y); - break; - case TopLeft: - anchor = BottomRight; - dx = - (x_root - frame.grab_x); - dy = - (y_root - frame.grab_y); - break; - case TopRight: - anchor = BottomLeft; - dx = + (x_root - frame.grab_x); - dy = - (y_root - frame.grab_y); - break; - - default: - assert(false); // unhandled Corner - return; // unreachable, for the compiler - } - - // make sure the user cant resize the window smaller than 0, which makes it - // wrap around and become huge - if (dx < -(signed)client.rect.width()) dx = -(signed)client.rect.width(); - if (dy < -(signed)client.rect.height()) dy = -(signed)client.rect.height(); - - frame.changing.setSize(frame.rect.width() + dx, frame.rect.height() + dy); - - constrain(anchor, &gw, &gh); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), frame.changing.x(), frame.changing.y(), - frame.changing.width() - 1, frame.changing.height() - 1); - - screen->showGeometry(gw, gh); -} - - -void BlackboxWindow::endResize(void) { - assert(flags.resizing); - assert(blackbox->getChangingWindow() == this); - - XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), - screen->getOpGC(), frame.changing.x(), frame.changing.y(), - frame.changing.width() - 1, frame.changing.height() - 1); - XUngrabServer(blackbox->getXDisplay()); - - // unset maximized state after resized when fully maximized - if (flags.maximized == 1) - maximize(0); - - flags.resizing = False; - blackbox->setChangingWindow(0); - - configure(frame.changing.x(), frame.changing.y(), - frame.changing.width(), frame.changing.height()); - screen->hideGeometry(); - - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - - // if there are any left over motions from the resize, drop them now - XSync(blackbox->getXDisplay(), false); // make sure we don't miss any - XEvent e; - while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window, - MotionNotify, &e)); -} - - -void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { -#if 0 - fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n", - client.window); -#endif - - if (flags.moving) { - doMove(me->x_root, me->y_root); - } else if (flags.resizing) { - doResize(me->x_root, me->y_root); - } else { - if ((functions & Func_Move) && - (me->state & Button1Mask) && - (frame.title == me->window || frame.label == me->window || - frame.handle == me->window || frame.window == me->window)) { - beginMove(me->x_root, me->y_root); - } else if ((functions & Func_Resize) && - ((me->state & Button1Mask) && - (me->window == frame.right_grip || - me->window == frame.left_grip)) || - ((me->state & Button3Mask) && (me->state & mod_mask) && - (frame.title == me->window || frame.label == me->window || - frame.handle == me->window || frame.window == me->window || - frame.right_grip == me->window || - frame.left_grip == me->window))) { - unsigned int zones = screen->getResizeZones(); - Corner corner; - - if (me->window == frame.left_grip) { - corner = BottomLeft; - } else if (me->window == frame.right_grip || zones == 1) { - corner = BottomRight; - } else { - bool top; - bool left = (me->x_root - frame.rect.x() <= - static_cast(frame.rect.width() / 2)); - if (zones == 2) - top = False; - else // (zones == 4) - top = (me->y_root - frame.rect.y() <= - static_cast(frame.rect.height() / 2)); - corner = (top ? (left ? TopLeft : TopRight) : - (left ? BottomLeft : BottomRight)); - } - - beginResize(me->x_root, me->y_root, corner); - } - } -} - - -void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) { - if (! (screen->isSloppyFocus() && isVisible() && isNormal())) - return; - - XEvent e; - bool leave = False, inferior = False; - - while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window, - LeaveNotify, &e)) { - if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) { - leave = True; - inferior = (e.xcrossing.detail == NotifyInferior); - } - } - - if (! leave || inferior) { - if (! isFocused()) { - bool success = setInputFocus(); - if (success) // if focus succeeded install the colormap - installColormap(True); // XXX: shouldnt we honour no install? - - /* - We only auto-raise when the window wasn't focused because otherwise - we run into problems with gtk+ drop-down lists. The window ends up - raising over the list. - */ - if (screen->doAutoRaise()) - timer->start(); - } - } -} - - -void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) { - if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal())) - return; - - installColormap(False); - - if (timer->isTiming()) - timer->stop(); -} - - -#ifdef SHAPE -void BlackboxWindow::shapeEvent(XShapeEvent *e) { - if (blackbox->hasShapeExtensions()) { - if (! e->shaped && flags.shaped) { - clearShape(); - flags.shaped = False; - } else if (e->shaped) { - configureShape(); - flags.shaped = True; - } - } -} -#endif // SHAPE - - -bool BlackboxWindow::validateClient(void) const { - XSync(blackbox->getXDisplay(), False); - - XEvent e; - if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, - DestroyNotify, &e) || - XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, - UnmapNotify, &e)) { - XPutBackEvent(blackbox->getXDisplay(), &e); - - return False; - } - - return True; -} - - -void BlackboxWindow::restore(bool remap) { - XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete); - XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); - XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask); - - // do not leave a shaded window as an icon unless it was an icon - if (flags.shaded && ! flags.iconic) - setState(NormalState); - - // erase the netwm stuff that we read when a window maps, so that it - // doesn't persist between mappings. - // (these are the ones read in getNetWMFlags().) - xatom->eraseValue(client.window, XAtom::net_wm_desktop); - xatom->eraseValue(client.window, XAtom::net_wm_state); - - restoreGravity(client.rect); - - XUnmapWindow(blackbox->getXDisplay(), frame.window); - XUnmapWindow(blackbox->getXDisplay(), client.window); - - XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw); - - XEvent ev; - if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, - ReparentNotify, &ev)) { - remap = True; - } else { - // according to the ICCCM - if the client doesn't reparent to - // root, then we have to do it for them - XReparentWindow(blackbox->getXDisplay(), client.window, - screen->getRootWindow(), - client.rect.x(), client.rect.y()); - } - - if (remap) XMapWindow(blackbox->getXDisplay(), client.window); -} - - -// timer for autoraise -void BlackboxWindow::timeout(void) { - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); -} - - -void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) { - if ((net->flags & AttribShaded) && - ((blackbox_attrib.attrib & AttribShaded) != - (net->attrib & AttribShaded))) - shade(); - - if (flags.visible && // watch out for requests when we can not be seen - (net->flags & (AttribMaxVert | AttribMaxHoriz)) && - ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) != - (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) { - if (flags.maximized) { - maximize(0); - } else { - int button = 0; - - if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert)) - button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0); - else if (net->flags & AttribMaxVert) - button = ((net->attrib & AttribMaxVert) ? 2 : 0); - else if (net->flags & AttribMaxHoriz) - button = ((net->attrib & AttribMaxHoriz) ? 3 : 0); - - maximize(button); - } - } - - if ((net->flags & AttribOmnipresent) && - ((blackbox_attrib.attrib & AttribOmnipresent) != - (net->attrib & AttribOmnipresent))) - stick(); - - if ((net->flags & AttribWorkspace) && - (blackbox_attrib.workspace != net->workspace)) { - screen->reassociateWindow(this, net->workspace, True); - - if (screen->getCurrentWorkspaceID() != net->workspace) { - withdraw(); - } else { - show(); - screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - } - } - - if (net->flags & AttribDecoration) { - switch (net->decoration) { - case DecorNone: - enableDecor(False); - break; - - default: - case DecorNormal: - case DecorTiny: - case DecorTool: - enableDecor(True); - break; - } - } -} - - -/* - * Set the sizes of all components of the window frame - * (the window decorations). - * These values are based upon the current style settings and the client - * window's dimensions. - */ -void BlackboxWindow::upsize(void) { - frame.bevel_w = screen->getBevelWidth(); - - if (decorations & Decor_Border) { - frame.border_w = screen->getBorderWidth(); - if (! isTransient()) - frame.mwm_border_w = screen->getFrameWidth(); - else - frame.mwm_border_w = 0; - } else { - frame.mwm_border_w = frame.border_w = 0; - } - - if (decorations & Decor_Titlebar) { - // the height of the titlebar is based upon the height of the font being - // used to display the window's title - WindowStyle *style = screen->getWindowStyle(); - frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2; - - frame.label_h = frame.title_h - (frame.bevel_w * 2); - frame.button_w = (frame.label_h - 2); - - // set the top frame margin - frame.margin.top = frame.border_w + frame.title_h + - frame.border_w + frame.mwm_border_w; - } else { - frame.title_h = 0; - frame.label_h = 0; - frame.button_w = 0; - - // set the top frame margin - frame.margin.top = frame.border_w + frame.mwm_border_w; - } - - // set the left/right frame margin - frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w; - - if (decorations & Decor_Handle) { - frame.grip_w = frame.button_w * 2; - frame.handle_h = screen->getHandleWidth(); - - // set the bottom frame margin - frame.margin.bottom = frame.border_w + frame.handle_h + - frame.border_w + frame.mwm_border_w; - } else { - frame.handle_h = 0; - frame.grip_w = 0; - - // set the bottom frame margin - frame.margin.bottom = frame.border_w + frame.mwm_border_w; - } - - /* - We first get the normal dimensions and use this to define the inside_w/h - then we modify the height if shading is in effect. - If the shade state is not considered then frame.rect gets reset to the - normal window size on a reconfigure() call resulting in improper - dimensions appearing in move/resize and other events. - */ - unsigned int - height = client.rect.height() + frame.margin.top + frame.margin.bottom, - width = client.rect.width() + frame.margin.left + frame.margin.right; - - frame.inside_w = width - (frame.border_w * 2); - frame.inside_h = height - (frame.border_w * 2); - - if (flags.shaded) - height = frame.title_h + (frame.border_w * 2); - frame.rect.setSize(width, height); -} - - -/* - * Calculate the size of the client window and constrain it to the - * size specified by the size hints of the client window. - * - * The logical width and height are placed into pw and ph, if they - * are non-zero. Logical size refers to the users perception of - * the window size (for example an xterm resizes in cells, not in pixels). - * pw and ph are then used to display the geometry during window moves, resize, - * etc. - * - * The physical geometry is placed into frame.changing_{x,y,width,height}. - * Physical geometry refers to the geometry of the window in pixels. - */ -void BlackboxWindow::constrain(Corner anchor, - unsigned int *pw, unsigned int *ph) { - // frame.changing represents the requested frame size, we need to - // strip the frame margin off and constrain the client size - frame.changing.setCoords(frame.changing.left() + frame.margin.left, - frame.changing.top() + frame.margin.top, - frame.changing.right() - frame.margin.right, - frame.changing.bottom() - frame.margin.bottom); - - unsigned int dw = frame.changing.width(), dh = frame.changing.height(), - base_width = (client.base_width) ? client.base_width : client.min_width, - base_height = (client.base_height) ? client.base_height : - client.min_height; - - // constrain, but only if the min/max are being used. if they aren't, then - // this resize is going to be from a ConfigureRequest because the window - // isn't allowed to be resized by the user. And in that case, we don't want - // to limit what the app can do - if (client.max_width > client.min_width || - client.max_height > client.min_height) { - if (dw < client.min_width) dw = client.min_width; - if (dh < client.min_height) dh = client.min_height; - if (dw > client.max_width) dw = client.max_width; - if (dh > client.max_height) dh = client.max_height; - } - - if (client.width_inc > 1) { - dw -= base_width; - dw /= client.width_inc; - } - if (client.height_inc > 1) { - dh -= base_height; - dh /= client.height_inc; - } - - if (pw) - *pw = dw; - - if (ph) - *ph = dh; - - if (client.width_inc > 1) { - dw *= client.width_inc; - dw += base_width; - } - if (client.height_inc > 1) { - dh *= client.height_inc; - dh += base_height; - } - - frame.changing.setSize(dw, dh); - - // add the frame margin back onto frame.changing - frame.changing.setCoords(frame.changing.left() - frame.margin.left, - frame.changing.top() - frame.margin.top, - frame.changing.right() + frame.margin.right, - frame.changing.bottom() + frame.margin.bottom); - - // move frame.changing to the specified anchor - int dx = 0, - dy = 0; - switch (anchor) { - case TopLeft: - break; - - case TopRight: - dx = frame.rect.right() - frame.changing.right(); - break; - - case BottomLeft: - dy = frame.rect.bottom() - frame.changing.bottom(); - break; - - case BottomRight: - dx = frame.rect.right() - frame.changing.right(); - dy = frame.rect.bottom() - frame.changing.bottom(); - break; - - default: - assert(false); // unhandled corner - } - frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy); -} - - -void WindowStyle::doJustify(const std::string &text, int &start_pos, - unsigned int max_length, - unsigned int modifier) const { - size_t text_len = text.size(); - unsigned int length; - - do { - length = font->measureString(string(text, 0, text_len)) + modifier; - } while (length > max_length && text_len-- > 0); - - switch (justify) { - case RightJustify: - start_pos += max_length - length; - break; - - case CenterJustify: - start_pos += (max_length - length) / 2; - break; - - case LeftJustify: - default: - break; - } -} - - -BWindowGroup::BWindowGroup(Blackbox *b, Window _group) - : blackbox(b), group(_group) { - XWindowAttributes wattrib; - if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) { - // group window doesn't seem to exist anymore - delete this; - return; - } - - XSelectInput(blackbox->getXDisplay(), group, - PropertyChangeMask | FocusChangeMask | StructureNotifyMask); - - blackbox->saveGroupSearch(group, this); -} - - -BWindowGroup::~BWindowGroup(void) { - blackbox->removeGroupSearch(group); -} - - -BlackboxWindow * -BWindowGroup::find(BScreen *screen, bool allow_transients) const { - BlackboxWindow *ret = blackbox->getFocusedWindow(); - - // does the focus window match (or any transient_fors)? - for (; ret; ret = ret->getTransientFor()) { - if (ret->getScreen() == screen && ret->getGroupWindow() == group && - (! ret->isTransient() || allow_transients)) - break; - } - - if (ret) return ret; - - // the focus window didn't match, look in the group's window list - BlackboxWindowList::const_iterator it, end = windowList.end(); - for (it = windowList.begin(); it != end; ++it) { - ret = *it; - if (ret->getScreen() == screen && ret->getGroupWindow() == group && - (! ret->isTransient() || allow_transients)) - break; - } - - return ret; -} diff --git a/src/Window.hh b/src/Window.hh deleted file mode 100644 index b923c4bf..00000000 --- a/src/Window.hh +++ /dev/null @@ -1,436 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Window.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Window_hh -#define __Window_hh - -extern "C" { -#include -#include -#ifdef SHAPE -# include -#endif // SHAPE -} - -#include - -#include "BaseDisplay.hh" -#include "Timer.hh" -#include "Util.hh" -#include "Windowmenu.hh" - -#define MwmHintsFunctions (1l << 0) -#define MwmHintsDecorations (1l << 1) - -#define MwmFuncAll (1l << 0) -#define MwmFuncResize (1l << 1) -#define MwmFuncMove (1l << 2) -#define MwmFuncIconify (1l << 3) -#define MwmFuncMaximize (1l << 4) -#define MwmFuncClose (1l << 5) - -#define MwmDecorAll (1l << 0) -#define MwmDecorBorder (1l << 1) -#define MwmDecorHandle (1l << 2) -#define MwmDecorTitle (1l << 3) -#define MwmDecorMenu (1l << 4) // not used -#define MwmDecorIconify (1l << 5) -#define MwmDecorMaximize (1l << 6) - -// this structure only contains 3 elements... the Motif 2.0 structure contains -// 5... we only need the first 3... so that is all we will define -typedef struct MwmHints { - unsigned long flags, functions, decorations; -} MwmHints; - -#define PropMwmHintsElements 3 - -class BWindowGroup { -private: - Blackbox *blackbox; - Window group; - BlackboxWindowList windowList; - -public: - BWindowGroup(Blackbox *b, Window _group); - ~BWindowGroup(void); - - inline Window groupWindow(void) const { return group; } - - inline bool empty(void) const { return windowList.empty(); } - - void addWindow(BlackboxWindow *w) { windowList.push_back(w); } - void removeWindow(BlackboxWindow *w) { windowList.remove(w); } - - /* - find a window on the specified screen. the focused window (if any) is - checked first, otherwise the first matching window found is returned. - transients are returned only if allow_transients is True. - */ - BlackboxWindow *find(BScreen *screen, bool allow_transients = False) const; -}; - - -class BlackboxWindow : public TimeoutHandler { -public: - enum Function { Func_Resize = (1l << 0), - Func_Move = (1l << 1), - Func_Iconify = (1l << 2), - Func_Maximize = (1l << 3), - Func_Close = (1l << 4) }; - typedef unsigned char FunctionFlags; - - enum Decoration { Decor_Titlebar = (1l << 0), - Decor_Handle = (1l << 1), - Decor_Border = (1l << 2), - Decor_Iconify = (1l << 3), - Decor_Maximize = (1l << 4), - Decor_Close = (1l << 5) }; - typedef unsigned char DecorationFlags; - - enum WindowType { Type_Desktop, - Type_Dock, - Type_Toolbar, - Type_Menu, - Type_Utility, - Type_Splash, - Type_Dialog, - Type_Normal }; - - enum Corner { TopLeft, - TopRight, - BottomLeft, - BottomRight }; - -private: - Blackbox *blackbox; - BScreen *screen; - XAtom *xatom; - BTimer *timer; - BlackboxAttributes blackbox_attrib; - - Time lastButtonPressTime; // used for double clicks, when were we clicked - Windowmenu *windowmenu; - - unsigned int window_number; - unsigned long current_state; - unsigned int mod_mask; // the mod mask used to grab buttons - - enum FocusMode { F_NoInput = 0, F_Passive, - F_LocallyActive, F_GloballyActive }; - FocusMode focus_mode; - - struct _flags { - bool moving, // is moving? - resizing, // is resizing? - shaded, // is shaded? - visible, // is visible? - iconic, // is iconified? - focused, // has focus? - stuck, // is omnipresent? - modal, // is modal? (must be dismissed to continue) - skip_taskbar, // skipped by taskbars? - skip_pager, // skipped by pagers? - fullscreen, // a fullscreen window? - send_focus_message, // should we send focus messages to our client? - shaped; // does the frame use the shape extension? - unsigned int maximized; // maximize is special, the number corresponds - // with a mouse button - // if 0, not maximized - // 1 = HorizVert, 2 = Vertical, 3 = Horizontal - } flags; - - struct _client { - Window window, // the client's window - window_group; - BlackboxWindow *transient_for; // which window are we a transient for? - BlackboxWindowList transientList; // which windows are our transients? - - std::string title, icon_title; - - Rect rect; - Strut strut; - - int old_bw; // client's borderwidth - - unsigned int - min_width, min_height, // can not be resized smaller - max_width, max_height, // can not be resized larger - width_inc, height_inc, // increment step -#if 0 // not supported at the moment - min_aspect_x, min_aspect_y, // minimum aspect ratio - max_aspect_x, max_aspect_y, // maximum aspect ratio -#endif - base_width, base_height, - win_gravity; - - unsigned long initial_state, normal_hint_flags; - } client; - - FunctionFlags functions; - /* - * what decorations do we have? - * this is based on the type of the client window as well as user input - */ - DecorationFlags decorations; - DecorationFlags mwm_decorations; - Corner resize_dir; - WindowType window_type; - - /* - * client window = the application's window - * frame window = the window drawn around the outside of the client window - * by the window manager which contains items like the - * titlebar and close button - * title = the titlebar drawn above the client window, it displays the - * window's name and any buttons for interacting with the window, - * such as iconify, maximize, and close - * label = the window in the titlebar where the title is drawn - * buttons = maximize, iconify, close - * handle = the bar drawn at the bottom of the window, which contains the - * left and right grips used for resizing the window - * grips = the smaller reactangles in the handle, one of each side of it. - * When clicked and dragged, these resize the window interactively - * border = the line drawn around the outside edge of the frame window, - * between the title, the bordered client window, and the handle. - * Also drawn between the grips and the handle - */ - - struct _frame { - // u -> unfocused, f -> has focus, p -> pressed - unsigned long ulabel_pixel, flabel_pixel, utitle_pixel, - ftitle_pixel, uhandle_pixel, fhandle_pixel, ubutton_pixel, - fbutton_pixel, pfbutton_pixel, pubutton_pixel, - uborder_pixel, fborder_pixel, ugrip_pixel, fgrip_pixel; - Pixmap ulabel, flabel, utitle, ftitle, uhandle, fhandle, - ubutton, fbutton, pfbutton, pubutton, ugrip, fgrip; - - Window window, // the frame - plate, // holds the client - title, - label, - handle, - close_button, iconify_button, maximize_button, stick_button, - right_grip, left_grip; - - /* - * size and location of the box drawn while the window dimensions or - * location is being changed, ie. resized or moved - */ - Rect changing; - - Rect rect; // frame geometry - Strut margin; // margins between the frame and client - - int grab_x, grab_y; // where was the window when it was grabbed? - - unsigned int inside_w, inside_h, // window w/h without border_w - title_h, label_w, label_h, handle_h, - button_w, grip_w, mwm_border_w, border_w, - bevel_w; - } frame; - - BlackboxWindow(const BlackboxWindow&); - BlackboxWindow& operator=(const BlackboxWindow&); - - bool getState(void); - Window createToplevelWindow(); - Window createChildWindow(Window parent, unsigned long event_mask, - Cursor = None); - - bool getWindowType(void); - void updateStrut(void); - void getWMName(void); - void getWMIconName(void); - void getWMNormalHints(void); - void getWMProtocols(void); - void getWMHints(void); - void getNetWMHints(void); - void getMWMHints(void); - bool getBlackboxHints(void); - void getTransientInfo(void); - void setNetWMAttributes(void); - void associateClientWindow(void); - void decorate(void); - void decorateLabel(void); - void positionButtons(bool redecorate_label = False); - void positionWindows(void); - void createHandle(void); - void destroyHandle(void); - void createTitlebar(void); - void destroyTitlebar(void); - void createCloseButton(void); - void destroyCloseButton(void); - void createIconifyButton(void); - void destroyIconifyButton(void); - void createMaximizeButton(void); - void destroyMaximizeButton(void); - void createStickyButton(void); - void destroyStickyButton(void); - void redrawWindowFrame(void) const; - void redrawLabel(void) const; - void redrawAllButtons(void) const; - void BlackboxWindow::redrawButton(bool pressed, Window win, - Pixmap fppix, unsigned long fppixel, - Pixmap uppix, unsigned long uppixel, - Pixmap fpix, unsigned long fpixel, - Pixmap upix, unsigned long upixel) const; - void redrawCloseButton(bool pressed) const; - void redrawIconifyButton(bool pressed) const; - void redrawMaximizeButton(bool pressed) const; - void redrawStickyButton(bool pressed) const; - void applyGravity(Rect &r); - void restoreGravity(Rect &r); - void setAllowedActions(void); - void setState(unsigned long new_state); - void upsize(void); - void doMove(int x_root, int y_root); - void doWorkspaceWarping(int x_root, int y_root, int &dx); - void doWindowSnapping(int &dx, int &dy); - void endMove(void); - void doResize(int x_root, int y_root); - void endResize(void); - - void constrain(Corner anchor, unsigned int *pw = 0, unsigned int *ph = 0); - -public: - BlackboxWindow(Blackbox *b, Window w, BScreen *s); - virtual ~BlackboxWindow(void); - - inline bool isTransient(void) const { return client.transient_for != 0; } - inline bool isFocused(void) const { return flags.focused; } - inline bool isVisible(void) const { return flags.visible; } - inline bool isIconic(void) const { return flags.iconic; } - inline bool isShaded(void) const { return flags.shaded; } - inline bool isMaximized(void) const { return flags.maximized; } - inline bool isMaximizedHoriz(void) const { return flags.maximized == 3; } - inline bool isMaximizedVert(void) const { return flags.maximized == 2; } - inline bool isMaximizedFull(void) const { return flags.maximized == 1; } - inline bool isStuck(void) const { return flags.stuck; } - inline bool isModal(void) const { return flags.modal; } - inline bool isIconifiable(void) const { return functions & Func_Iconify; } - inline bool isMaximizable(void) const { return functions & Func_Maximize; } - inline bool isResizable(void) const { return functions & Func_Resize; } - inline bool isClosable(void) const { return functions & Func_Close; } - - // is a 'normal' window? meaning, a standard client application - inline bool isNormal(void) const - { return window_type == Type_Dialog || window_type == Type_Normal || - window_type == Type_Toolbar || window_type == Type_Utility; } - inline bool isTopmost(void) const - { return window_type == Type_Toolbar || window_type == Type_Utility; } - inline bool isDesktop(void) const { return window_type == Type_Desktop; } - - inline bool hasTitlebar(void) const { return decorations & Decor_Titlebar; } - - inline const BlackboxWindowList &getTransients(void) const - { return client.transientList; } - BlackboxWindow *getTransientFor(void) const; - - inline BScreen *getScreen(void) const { return screen; } - - inline Window getFrameWindow(void) const { return frame.window; } - inline Window getClientWindow(void) const { return client.window; } - inline Window getGroupWindow(void) const { return client.window_group; } - - inline Windowmenu * getWindowmenu(void) const { return windowmenu; } - - inline const char *getTitle(void) const - { return client.title.c_str(); } - inline const char *getIconTitle(void) const - { return client.icon_title.c_str(); } - - inline unsigned int getWorkspaceNumber(void) const - { return blackbox_attrib.workspace; } - inline unsigned int getWindowNumber(void) const { return window_number; } - - inline const Rect &frameRect(void) const { return frame.rect; } - inline const Rect &clientRect(void) const { return client.rect; } - - inline unsigned int getTitleHeight(void) const - { return frame.title_h; } - - inline void setWindowNumber(int n) { window_number = n; } - - bool validateClient(void) const; - bool setInputFocus(void); - - // none of these are used by the window manager, they are here to persist - // them properly in the window's netwm state property. - inline bool skipTaskbar(void) const { return flags.skip_taskbar; } - inline void setSkipTaskbar(const bool s) { flags.skip_taskbar = s; } - inline bool skipPager(void) const { return flags.skip_pager; } - inline void setSkipPager(const bool s) { flags.skip_pager = s; } - inline bool isFullscreen(void) const { return flags.fullscreen; } - inline void setFullscreen(const bool f) { flags.fullscreen = f; } - - inline void setModal(const bool m) { flags.modal = m; } - - void beginMove(int x_root, int y_root); - void beginResize(int x_root, int y_root, Corner dir); - void enableDecor(bool enable); - void setupDecor(); - void setFocusFlag(bool focus); - void iconify(void); - void deiconify(bool reassoc = True, bool raise = True); - void show(void); - void close(void); - void withdraw(void); - void maximize(unsigned int button); - void remaximize(void); - void shade(void); - void stick(void); - void reconfigure(void); - void grabButtons(void); - void ungrabButtons(void); - void installColormap(bool install); - void restore(bool remap); - void configure(int dx, int dy, unsigned int dw, unsigned int dh); - void setWorkspace(unsigned int n); - void changeBlackboxHints(const BlackboxHints *net); - void restoreAttributes(void); - - void buttonPressEvent(const XButtonEvent *be); - void buttonReleaseEvent(const XButtonEvent *re); - void motionNotifyEvent(const XMotionEvent *me); - void destroyNotifyEvent(const XDestroyWindowEvent* /*unused*/); - void mapRequestEvent(const XMapRequestEvent *mre); - void unmapNotifyEvent(const XUnmapEvent* /*unused*/); - void reparentNotifyEvent(const XReparentEvent* /*unused*/); - void propertyNotifyEvent(const XPropertyEvent *pe); - void exposeEvent(const XExposeEvent *ee); - void configureRequestEvent(const XConfigureRequestEvent *cr); - void enterNotifyEvent(const XCrossingEvent *ce); - void leaveNotifyEvent(const XCrossingEvent* /*unused*/); - -#ifdef SHAPE - void configureShape(void); - void clearShape(void); - void shapeEvent(XShapeEvent * /*unused*/); -#endif // SHAPE - - virtual void timeout(void); -}; - - -#endif // __Window_hh diff --git a/src/Workspace.cc b/src/Workspace.cc deleted file mode 100644 index 67e19110..00000000 --- a/src/Workspace.cc +++ /dev/null @@ -1,841 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Workspace.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include -#include - -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H -} - -#include - -#include -#include - -using std::string; - -#include "i18n.hh" -#include "blackbox.hh" -#include "Clientmenu.hh" -#include "Font.hh" -#include "Netizen.hh" -#include "Screen.hh" -#include "Toolbar.hh" -#include "Util.hh" -#include "Window.hh" -#include "Workspace.hh" -#include "Windowmenu.hh" -#include "XAtom.hh" - - -Workspace::Workspace(BScreen *scrn, unsigned int i) { - screen = scrn; - xatom = screen->getBlackbox()->getXAtom(); - - cascade_x = cascade_y = 0; -#ifdef XINERAMA - cascade_region = 0; -#endif // XINERAMA - - id = i; - - clientmenu = new Clientmenu(this); - - lastfocus = (BlackboxWindow *) 0; - - readName(); -} - - -void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) { - assert(w != 0); - - if (place) placeWindow(w); - - stackingList.push_front(w); - - if (! sticky) - w->setWorkspace(id); - - if (! w->isNormal()) { - if (! sticky) { - // just give it some number, else bad things happen as it is assumed to - // not be on a workspace - w->setWindowNumber(0); - } - } else { - if (! sticky) - w->setWindowNumber(windowList.size()); - - windowList.push_back(w); - - clientmenu->insert(w->getTitle()); - clientmenu->update(); - - if (! sticky) - screen->updateNetizenWindowAdd(w->getClientWindow(), id); - - if (screen->doFocusNew() || (w->isTransient() && w->getTransientFor() && - w->getTransientFor()->isFocused())) { - if (id != screen->getCurrentWorkspaceID()) { - /* - not on the focused workspace, so the window is not going to get focus - but if the user wants new windows focused, then it should get focus - when this workspace does become focused. - */ - lastfocus = w; - } - } - } - - if (! w->isDesktop()) - raiseWindow(w); - else - lowerWindow(w); -} - - -void Workspace::removeWindow(BlackboxWindow *w, bool sticky) { - assert(w != 0); - - stackingList.remove(w); - - // pass focus to the next appropriate window - if ((w->isFocused() || w == lastfocus) && - ! screen->getBlackbox()->doShutdown()) { - focusFallback(w); - } - - if (! w->isNormal()) return; - - BlackboxWindowList::iterator it, end = windowList.end(); - int i; - for (i = 0, it = windowList.begin(); it != end; ++it, ++i) - if (*it == w) - break; - assert(it != end); - - windowList.erase(it); - clientmenu->remove(i); - clientmenu->update(); - - if (! sticky) { - screen->updateNetizenWindowDel(w->getClientWindow()); - - BlackboxWindowList::iterator it = windowList.begin(); - const BlackboxWindowList::iterator end = windowList.end(); - unsigned int i = 0; - for (; it != end; ++it, ++i) - (*it)->setWindowNumber(i); - } - - if (i == 0) { - cascade_x = cascade_y = 0; -#ifdef XINERAMA - cascade_region = 0; -#endif // XINERAMA - } -} - - -void Workspace::focusFallback(const BlackboxWindow *old_window) { - BlackboxWindow *newfocus = 0; - - if (id == screen->getCurrentWorkspaceID()) { - // The window is on the visible workspace. - - // if it's a transient, then try to focus its parent - if (old_window && old_window->isTransient()) { - newfocus = old_window->getTransientFor(); - - if (! newfocus || - newfocus->isIconic() || // do not focus icons - newfocus->getWorkspaceNumber() != id || // or other workspaces - ! newfocus->setInputFocus()) - newfocus = 0; - } - - if (! newfocus) { - BlackboxWindowList::iterator it = stackingList.begin(), - end = stackingList.end(); - for (; it != end; ++it) { - BlackboxWindow *tmp = *it; - if (tmp && tmp->isNormal() && tmp->setInputFocus()) { - // we found our new focus target - newfocus = tmp; - break; - } - } - } - - screen->getBlackbox()->setFocusedWindow(newfocus); - } else { - // The window is not on the visible workspace. - - if (old_window && lastfocus == old_window) { - // The window was the last-focus target, so we need to replace it. - BlackboxWindow *win = (BlackboxWindow*) 0; - if (! stackingList.empty()) - win = stackingList.front(); - setLastFocusedWindow(win); - } - } -} - - -void Workspace::setFocused(const BlackboxWindow *w, bool focused) { - BlackboxWindowList::iterator it, end = windowList.end(); - int i; - for (i = 0, it = windowList.begin(); it != end; ++it, ++i) - if (*it == w) - break; - // if its == end, then a window thats not in the windowList - // got focused, such as a !isNormal() window. - if (it != end) - clientmenu->setItemSelected(i, focused); -} - - -void Workspace::removeAll(void) { - while (! windowList.empty()) - windowList.front()->iconify(); -} - -void Workspace::showAll(void) { - BlackboxWindowList::iterator it = stackingList.begin(); - const BlackboxWindowList::iterator end = stackingList.end(); - for (; it != end; ++it) { - BlackboxWindow *bw = *it; - // sticky windows arent unmapped on a workspace change so we don't have ot - // map them, but sometimes on a restart, another app can unmap our sticky - // windows, so we map on startup always - if (! bw->isStuck() || screen->getBlackbox()->isStartup()) - bw->show(); - } -} - - -void Workspace::hideAll(void) { - // withdraw in reverse order to minimize the number of Expose events - - BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend()); - - BlackboxWindowList::iterator it = lst.begin(); - const BlackboxWindowList::iterator end = lst.end(); - for (; it != end; ++it) { - BlackboxWindow *bw = *it; - // don't hide sticky windows, or they'll end up flickering on a workspace - // change - if (! bw->isStuck()) - bw->withdraw(); - } -} - - - -/* - * returns the number of transients for win, plus the number of transients - * associated with each transient of win - */ -static unsigned int countTransients(const BlackboxWindow * const win) { - BlackboxWindowList transients = win->getTransients(); - if (transients.empty()) return 0; - - unsigned int ret = transients.size(); - BlackboxWindowList::const_iterator it = transients.begin(), - end = transients.end(); - for (; it != end; ++it) - ret += countTransients(*it); - - return ret; -} - - -/* - * puts the transients of win into the stack. windows are stacked above - * the window before it in the stackvector being iterated, meaning - * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above - * stack[1], etc... - */ -void Workspace::raiseTransients(const BlackboxWindow * const win, - StackVector::iterator &stack) { - if (win->getTransients().empty()) return; // nothing to do - - // put win's transients in the stack - BlackboxWindowList::const_iterator it, end = win->getTransients().end(); - for (it = win->getTransients().begin(); it != end; ++it) { - BlackboxWindow *w = *it; - *stack++ = w->getFrameWindow(); - screen->updateNetizenWindowRaise(w->getClientWindow()); - - if (! w->isIconic()) { - Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber()); - wkspc->stackingList.remove(w); - wkspc->stackingList.push_front(w); - } - } - - // put transients of win's transients in the stack - for (it = win->getTransients().begin(); it != end; ++it) - raiseTransients(*it, stack); -} - - -void Workspace::lowerTransients(const BlackboxWindow * const win, - StackVector::iterator &stack) { - if (win->getTransients().empty()) return; // nothing to do - - // put transients of win's transients in the stack - BlackboxWindowList::const_reverse_iterator it, - end = win->getTransients().rend(); - for (it = win->getTransients().rbegin(); it != end; ++it) - lowerTransients(*it, stack); - - // put win's transients in the stack - for (it = win->getTransients().rbegin(); it != end; ++it) { - BlackboxWindow *w = *it; - *stack++ = w->getFrameWindow(); - screen->updateNetizenWindowLower(w->getClientWindow()); - - if (! w->isIconic()) { - Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber()); - wkspc->stackingList.remove(w); - wkspc->stackingList.push_back(w); - } - } -} - - -void Workspace::raiseWindow(BlackboxWindow *w) { - BlackboxWindow *win = w; - - if (win->isDesktop()) return; - - // walk up the transient_for's to the window that is not a transient - while (win->isTransient() && win->getTransientFor()) - win = win->getTransientFor(); - - // get the total window count (win and all transients) - unsigned int i = 1 + countTransients(win); - - // stack the window with all transients above - StackVector stack_vector(i); - StackVector::iterator stack = stack_vector.begin(); - - *(stack++) = win->getFrameWindow(); - screen->updateNetizenWindowRaise(win->getClientWindow()); - if (! (win->isIconic() || win->isDesktop())) { - Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); - wkspc->stackingList.remove(win); - wkspc->stackingList.push_front(win); - } - - raiseTransients(win, stack); - - screen->raiseWindows(&stack_vector[0], stack_vector.size()); -} - - -void Workspace::lowerWindow(BlackboxWindow *w) { - BlackboxWindow *win = w; - - // walk up the transient_for's to the window that is not a transient - while (win->isTransient() && win->getTransientFor()) - win = win->getTransientFor(); - - // get the total window count (win and all transients) - unsigned int i = 1 + countTransients(win); - - // stack the window with all transients above - StackVector stack_vector(i); - StackVector::iterator stack = stack_vector.begin(); - - lowerTransients(win, stack); - - *(stack++) = win->getFrameWindow(); - screen->updateNetizenWindowLower(win->getClientWindow()); - if (! (win->isIconic() || win->isDesktop())) { - Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); - wkspc->stackingList.remove(win); - wkspc->stackingList.push_back(win); - } - - screen->lowerWindows(&stack_vector[0], stack_vector.size()); -} - - -void Workspace::reconfigure(void) { - clientmenu->reconfigure(); - std::for_each(windowList.begin(), windowList.end(), - std::mem_fun(&BlackboxWindow::reconfigure)); -} - - -BlackboxWindow *Workspace::getWindow(unsigned int index) { - if (index < windowList.size()) { - BlackboxWindowList::iterator it = windowList.begin(); - while (index-- > 0) // increment to index - ++it; - return *it; - } - - return 0; -} - - -BlackboxWindow* -Workspace::getNextWindowInList(BlackboxWindow *w) { - BlackboxWindowList::iterator it = std::find(windowList.begin(), - windowList.end(), - w); - assert(it != windowList.end()); // window must be in list - ++it; // next window - if (it == windowList.end()) - return windowList.front(); // if we walked off the end, wrap around - - return *it; -} - - -BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) { - BlackboxWindowList::iterator it = std::find(windowList.begin(), - windowList.end(), - w); - assert(it != windowList.end()); // window must be in list - if (it == windowList.begin()) - return windowList.back(); // if we walked of the front, wrap around - - return *(--it); -} - - -BlackboxWindow* Workspace::getTopWindowOnStack(void) const { - assert(! stackingList.empty()); - return stackingList.front(); -} - - -void Workspace::sendWindowList(Netizen &n) { - BlackboxWindowList::iterator it = windowList.begin(), - end = windowList.end(); - for(; it != end; ++it) - n.sendWindowAdd((*it)->getClientWindow(), getID()); -} - - -unsigned int Workspace::getCount(void) const { - return windowList.size(); -} - - -void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const { - BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin(); - const BlackboxWindowList::const_reverse_iterator end = stackingList.rend(); - for (; it != end; ++it) - // don't add desktop wnidows, or sticky windows more than once - if (! ( (*it)->isDesktop() || - ((*it)->isStuck() && id != screen->getCurrentWorkspaceID()))) - stack_order.push_back(*it); -} - - -bool Workspace::isCurrent(void) const { - return (id == screen->getCurrentWorkspaceID()); -} - - -bool Workspace::isLastWindow(const BlackboxWindow* const w) const { - return (w == windowList.back()); -} - - -void Workspace::setCurrent(void) { - screen->changeWorkspaceID(id); -} - - -void Workspace::readName(void) { - XAtom::StringVect namesList; - unsigned long numnames = id + 1; - - // attempt to get from the _NET_WM_DESKTOP_NAMES property - if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names, - XAtom::utf8, numnames, namesList) && - namesList.size() > id) { - name = namesList[id]; - - clientmenu->setLabel(name); - clientmenu->update(); - } else { - /* - Use a default name. This doesn't actually change the class. That will - happen after the setName changes the root property, and that change - makes its way back to this function. - */ - string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat, - "Workspace %d"); - assert(tmp.length() < 32); - char default_name[32]; - sprintf(default_name, tmp.c_str(), id + 1); - - setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property - } -} - - -void Workspace::setName(const string& new_name) { - // set the _NET_WM_DESKTOP_NAMES property with the new name - XAtom::StringVect namesList; - unsigned long numnames = (unsigned) -1; - if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names, - XAtom::utf8, numnames, namesList) && - namesList.size() > id) - namesList[id] = new_name; - else - namesList.push_back(new_name); - - xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names, - XAtom::utf8, namesList); -} - - -/* - * Calculate free space available for window placement. - */ -Workspace::rectList Workspace::calcSpace(const Rect &win, - const rectList &spaces) const { - Rect isect, extra; - rectList result; - rectList::const_iterator siter, end = spaces.end(); - for (siter = spaces.begin(); siter != end; ++siter) { - const Rect &curr = *siter; - - if(! win.intersects(curr)) { - result.push_back(curr); - continue; - } - - /* Use an intersection of win and curr to determine the space around - * curr that we can use. - * - * NOTE: the spaces calculated can overlap. - */ - isect = curr & win; - - // left - extra.setCoords(curr.left(), curr.top(), - isect.left() - screen->getSnapOffset(), curr.bottom()); - if (extra.valid()) result.push_back(extra); - - // top - extra.setCoords(curr.left(), curr.top(), - curr.right(), isect.top() - screen->getSnapOffset()); - if (extra.valid()) result.push_back(extra); - - // right - extra.setCoords(isect.right() + screen->getSnapOffset(), curr.top(), - curr.right(), curr.bottom()); - if (extra.valid()) result.push_back(extra); - - // bottom - extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(), - curr.right(), curr.bottom()); - if (extra.valid()) result.push_back(extra); - } - return result; -} - - -static bool rowRLBT(const Rect &first, const Rect &second) { - if (first.bottom() == second.bottom()) - return first.right() > second.right(); - return first.bottom() > second.bottom(); -} - -static bool rowRLTB(const Rect &first, const Rect &second) { - if (first.y() == second.y()) - return first.right() > second.right(); - return first.y() < second.y(); -} - -static bool rowLRBT(const Rect &first, const Rect &second) { - if (first.bottom() == second.bottom()) - return first.x() < second.x(); - return first.bottom() > second.bottom(); -} - -static bool rowLRTB(const Rect &first, const Rect &second) { - if (first.y() == second.y()) - return first.x() < second.x(); - return first.y() < second.y(); -} - -static bool colLRTB(const Rect &first, const Rect &second) { - if (first.x() == second.x()) - return first.y() < second.y(); - return first.x() < second.x(); -} - -static bool colLRBT(const Rect &first, const Rect &second) { - if (first.x() == second.x()) - return first.bottom() > second.bottom(); - return first.x() < second.x(); -} - -static bool colRLTB(const Rect &first, const Rect &second) { - if (first.right() == second.right()) - return first.y() < second.y(); - return first.right() > second.right(); -} - -static bool colRLBT(const Rect &first, const Rect &second) { - if (first.right() == second.right()) - return first.bottom() > second.bottom(); - return first.right() > second.right(); -} - - -bool Workspace::smartPlacement(Rect& win) { - rectList spaces; - - //initially the entire screen is free -#ifdef XINERAMA - if (screen->isXineramaActive() && - screen->getBlackbox()->doXineramaPlacement()) { - RectList availableAreas = screen->allAvailableAreas(); - RectList::iterator it, end = availableAreas.end(); - - for (it = availableAreas.begin(); it != end; ++it) { - Rect r = *it; - r.setRect(r.x() + screen->getSnapOffset(), - r.y() + screen->getSnapOffset(), - r.width() - screen->getSnapOffset(), - r.height() - screen->getSnapOffset()); - spaces.push_back(*it); - } - } else -#endif // XINERAMA - { - Rect r = screen->availableArea(); - r.setRect(r.x() + screen->getSnapOffset(), - r.y() + screen->getSnapOffset(), - r.width() - screen->getSnapOffset(), - r.height() - screen->getSnapOffset()); - spaces.push_back(r); - } - - //Find Free Spaces - BlackboxWindowList::const_iterator wit = windowList.begin(), - end = windowList.end(); - Rect tmp; - for (; wit != end; ++wit) { - const BlackboxWindow* const curr = *wit; - - // watch for shaded windows and full-maxed windows - if (curr->isShaded()) { - if (screen->getPlaceIgnoreShaded()) continue; - } else if (curr->isMaximizedFull()) { - if (screen->getPlaceIgnoreMaximized()) continue; - } - - tmp.setRect(curr->frameRect().x(), curr->frameRect().y(), - curr->frameRect().width() + screen->getBorderWidth(), - curr->frameRect().height() + screen->getBorderWidth()); - - spaces = calcSpace(tmp, spaces); - } - - if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) { - if(screen->getRowPlacementDirection() == BScreen::LeftRight) { - if(screen->getColPlacementDirection() == BScreen::TopBottom) - std::sort(spaces.begin(), spaces.end(), rowLRTB); - else - std::sort(spaces.begin(), spaces.end(), rowLRBT); - } else { - if(screen->getColPlacementDirection() == BScreen::TopBottom) - std::sort(spaces.begin(), spaces.end(), rowRLTB); - else - std::sort(spaces.begin(), spaces.end(), rowRLBT); - } - } else { - if(screen->getColPlacementDirection() == BScreen::TopBottom) { - if(screen->getRowPlacementDirection() == BScreen::LeftRight) - std::sort(spaces.begin(), spaces.end(), colLRTB); - else - std::sort(spaces.begin(), spaces.end(), colRLTB); - } else { - if(screen->getRowPlacementDirection() == BScreen::LeftRight) - std::sort(spaces.begin(), spaces.end(), colLRBT); - else - std::sort(spaces.begin(), spaces.end(), colRLBT); - } - } - - rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end(); - for(; sit != spaces_end; ++sit) { - if (sit->width() >= win.width() && sit->height() >= win.height()) - break; - } - - if (sit == spaces_end) - return False; - - //set new position based on the empty space found - const Rect& where = *sit; - win.setX(where.x()); - win.setY(where.y()); - - // adjust the location() based on left/right and top/bottom placement - if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) { - if (screen->getRowPlacementDirection() == BScreen::RightLeft) - win.setX(where.right() - win.width()); - if (screen->getColPlacementDirection() == BScreen::BottomTop) - win.setY(where.bottom() - win.height()); - } else { - if (screen->getColPlacementDirection() == BScreen::BottomTop) - win.setY(win.y() + where.height() - win.height()); - if (screen->getRowPlacementDirection() == BScreen::RightLeft) - win.setX(win.x() + where.width() - win.width()); - } - return True; -} - - -bool Workspace::underMousePlacement(Rect &win) { - int x, y, rx, ry; - Window c, r; - unsigned int m; - XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(), - &r, &c, &rx, &ry, &x, &y, &m); - - Rect area; -#ifdef XINERAMA - if (screen->isXineramaActive() && - screen->getBlackbox()->doXineramaPlacement()) { - RectList availableAreas = screen->allAvailableAreas(); - RectList::iterator it, end = availableAreas.end(); - - for (it = availableAreas.begin(); it != end; ++it) - if (it->contains(rx, ry)) break; - assert(it != end); // the mouse isn't inside an area? - area = *it; - } else -#endif // XINERAMA - area = screen->availableArea(); - - x = rx - win.width() / 2; - y = ry - win.height() / 2; - - if (x < area.x()) - x = area.x(); - if (y < area.y()) - y = area.y(); - if (x + win.width() > area.x() + area.width()) - x = area.x() + area.width() - win.width(); - if (y + win.height() > area.y() + area.height()) - y = area.y() + area.height() - win.height(); - - win.setX(x); - win.setY(y); - - return True; -} - - -bool Workspace::cascadePlacement(Rect &win, const int offset) { - Rect area; - -#ifdef XINERAMA - if (screen->isXineramaActive() && - screen->getBlackbox()->doXineramaPlacement()) { - area = screen->allAvailableAreas()[cascade_region]; - } else -#endif // XINERAMA - area = screen->availableArea(); - - if ((static_cast(cascade_x + win.width()) > area.right() + 1) || - (static_cast(cascade_y + win.height()) > area.bottom() + 1)) { - cascade_x = cascade_y = 0; -#ifdef XINERAMA - if (screen->isXineramaActive() && - screen->getBlackbox()->doXineramaPlacement()) { - // go to the next xinerama region, and use its area - if (++cascade_region >= screen->allAvailableAreas().size()) - cascade_region = 0; - area = screen->allAvailableAreas()[cascade_region]; - } -#endif // XINERAMA - } - - if (cascade_x == 0) { - cascade_x = area.x() + offset; - cascade_y = area.y() + offset; - } - - win.setPos(cascade_x, cascade_y); - - cascade_x += offset; - cascade_y += offset; - - return True; -} - - -void Workspace::placeWindow(BlackboxWindow *win) { - Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height()); - bool placed = False; - - switch (screen->getPlacementPolicy()) { - case BScreen::RowSmartPlacement: - case BScreen::ColSmartPlacement: - placed = smartPlacement(new_win); - break; - case BScreen::UnderMousePlacement: - case BScreen::ClickMousePlacement: - placed = underMousePlacement(new_win); - default: - break; // handled below - } // switch - - if (placed == False) - cascadePlacement(new_win, (win->getTitleHeight() + - screen->getBorderWidth() * 2)); - - if (new_win.right() > screen->availableArea().right()) - new_win.setX(screen->availableArea().left()); - if (new_win.bottom() > screen->availableArea().bottom()) - new_win.setY(screen->availableArea().top()); - - win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height()); -} diff --git a/src/Workspace.hh b/src/Workspace.hh deleted file mode 100644 index df0411e1..00000000 --- a/src/Workspace.hh +++ /dev/null @@ -1,123 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// Workspace.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __Workspace_hh -#define __Workspace_hh - -extern "C" { -#include -} - -#include -#include -#include - -class BScreen; -class Clientmenu; -class Workspace; -class BlackboxWindow; -class Netizen; - -typedef std::list BlackboxWindowList; -typedef std::vector StackVector; - -class Workspace { -private: - BScreen *screen; - BlackboxWindow *lastfocus; - Clientmenu *clientmenu; - XAtom *xatom; - - BlackboxWindowList stackingList, windowList; - - std::string name; - unsigned int id; - unsigned int cascade_x, cascade_y; -#ifdef XINERAMA - unsigned int cascade_region; -#endif // XINERAMA - - Workspace(const Workspace&); - Workspace& operator=(const Workspace&); - - void raiseTransients(const BlackboxWindow * const win, - StackVector::iterator &stack); - void lowerTransients(const BlackboxWindow * const win, - StackVector::iterator &stack); - - typedef std::vector rectList; - rectList calcSpace(const Rect &win, const rectList &spaces) const; - - void placeWindow(BlackboxWindow *win); - bool cascadePlacement(Rect& win, const int offset); - bool smartPlacement(Rect& win); - bool underMousePlacement(Rect& win); - -public: - Workspace(BScreen *scrn, unsigned int i = 0); - - inline BScreen *getScreen(void) { return screen; } - - inline BlackboxWindow *getLastFocusedWindow(void) { return lastfocus; } - - inline Clientmenu *getMenu(void) { return clientmenu; } - - inline const std::string& getName(void) const { return name; } - - inline unsigned int getID(void) const { return id; } - - inline void setLastFocusedWindow(BlackboxWindow *w) { lastfocus = w; } - - inline const BlackboxWindowList& getStackingList() const - { return stackingList; } - - BlackboxWindow* getWindow(unsigned int index); - BlackboxWindow* getNextWindowInList(BlackboxWindow *w); - BlackboxWindow* getPrevWindowInList(BlackboxWindow *w); - BlackboxWindow* getTopWindowOnStack(void) const; - void sendWindowList(Netizen &n); - void focusFallback(const BlackboxWindow *old_window); - void setFocused(const BlackboxWindow *w, bool focused); - - bool isCurrent(void) const; - bool isLastWindow(const BlackboxWindow* w) const; - - void addWindow(BlackboxWindow *w, bool place = False, bool sticky = False); - void removeWindow(BlackboxWindow *w, bool sticky = False); - unsigned int getCount(void) const; - void appendStackOrder(BlackboxWindowList &stack_order) const; - - void showAll(void); - void hideAll(void); - void removeAll(void); - void raiseWindow(BlackboxWindow *w); - void lowerWindow(BlackboxWindow *w); - void reconfigure(void); - void setCurrent(void); - void readName(); - void setName(const std::string& new_name); -}; - - -#endif // __Workspace_hh - diff --git a/src/XAtom.cc b/src/XAtom.cc deleted file mode 100644 index bfd58483..00000000 --- a/src/XAtom.cc +++ /dev/null @@ -1,526 +0,0 @@ -// XAtom.cc for Openbox -// Copyright (c) 2002 - 2002 Ben Jansens (xor at orodu.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#include "../config.h" - -#include - -#include "XAtom.hh" -#include "Screen.hh" -#include "Util.hh" - -XAtom::XAtom(Display *d) { - _display = d; - - // 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_string] = create("UTF8_STRING"); - -#ifdef HAVE_GETPID - _atoms[blackbox_pid] = create("_BLACKBOX_PID"); -#endif // HAVE_GETPID - - _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[motif_wm_hints] = create("_MOTIF_WM_HINTS"); - _atoms[blackbox_hints] = create("_BLACKBOX_HINTS"); - _atoms[blackbox_attributes] = create("_BLACKBOX_ATTRIBUTES"); - _atoms[blackbox_change_attributes] = create("_BLACKBOX_CHANGE_ATTRIBUTES"); - _atoms[blackbox_structure_messages] = create("_BLACKBOX_STRUCTURE_MESSAGES"); - _atoms[blackbox_notify_startup] = create("_BLACKBOX_NOTIFY_STARTUP"); - _atoms[blackbox_notify_window_add] = create("_BLACKBOX_NOTIFY_WINDOW_ADD"); - _atoms[blackbox_notify_window_del] = create("_BLACKBOX_NOTIFY_WINDOW_DEL"); - _atoms[blackbox_notify_current_workspace] = - create("_BLACKBOX_NOTIFY_CURRENT_WORKSPACE"); - _atoms[blackbox_notify_workspace_count] = - create("_BLACKBOX_NOTIFY_WORKSPACE_COUNT"); - _atoms[blackbox_notify_window_focus] = - create("_BLACKBOX_NOTIFY_WINDOW_FOCUS"); - _atoms[blackbox_notify_window_raise] = - create("_BLACKBOX_NOTIFY_WINDOW_RAISE"); - _atoms[blackbox_notify_window_lower] = - create("_BLACKBOX_NOTIFY_WINDOW_LOWER"); - - _atoms[blackbox_change_workspace] = create("_BLACKBOX_CHANGE_WORKSPACE"); - _atoms[blackbox_change_window_focus] = - create("_BLACKBOX_CHANGE_WINDOW_FOCUS"); - _atoms[blackbox_cycle_window_focus] = create("_BLACKBOX_CYCLE_WINDOW_FOCUS"); - - _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_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_shade] = create("_NET_WM_ACTION_SHADE"); - _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_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_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[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"); -} - - -/* - * clean up the class' members - */ -XAtom::~XAtom() { - while (!_support_windows.empty()) { - // make sure we aren't fucking with this somewhere - assert(_support_windows.back() != None); - XDestroyWindow(_display, _support_windows.back()); - _support_windows.pop_back(); - } -} - - -/* - * Returns an atom from the Xserver, creating it if necessary. - */ -Atom XAtom::create(const char *name) const { - return XInternAtom(_display, name, False); -} - - -/* - * Sets which atoms are supported for NETWM, by Openbox, on the root window. - */ -void XAtom::setSupported(const ScreenInfo *screen) { - Window root = screen->getRootWindow(); - - // create the netwm support window - Window w = XCreateSimpleWindow(_display, root, 0, 0, 1, 1, 0, 0, 0); - assert(w != None); - _support_windows.push_back(w); - - // set supporting window - setValue(root, net_supporting_wm_check, window, w); - - //set properties on the supporting window - setValue(w, net_wm_name, utf8, "Openbox"); - setValue(w, net_supporting_wm_check, window, w); - - // we don't support any yet.. - // yes we do! - - Atom supported[] = { - _atoms[net_current_desktop], - _atoms[net_number_of_desktops], - _atoms[net_desktop_geometry], - _atoms[net_desktop_viewport], - _atoms[net_active_window], - _atoms[net_workarea], - _atoms[net_client_list], - _atoms[net_client_list_stacking], - _atoms[net_desktop_names], - _atoms[net_close_window], - _atoms[net_wm_name], - _atoms[net_wm_visible_name], - _atoms[net_wm_icon_name], - _atoms[net_wm_visible_icon_name], - _atoms[net_wm_desktop], - _atoms[net_wm_strut], - _atoms[net_wm_window_type], - _atoms[net_wm_window_type_desktop], - _atoms[net_wm_window_type_dock], - _atoms[net_wm_window_type_toolbar], - _atoms[net_wm_window_type_menu], - _atoms[net_wm_window_type_utility], - _atoms[net_wm_window_type_splash], - _atoms[net_wm_window_type_dialog], - _atoms[net_wm_window_type_normal], - _atoms[net_wm_moveresize], - _atoms[net_wm_moveresize_size_topleft], - _atoms[net_wm_moveresize_size_topright], - _atoms[net_wm_moveresize_size_bottomleft], - _atoms[net_wm_moveresize_size_bottomright], - _atoms[net_wm_moveresize_move], - _atoms[net_wm_allowed_actions], - _atoms[net_wm_action_move], - _atoms[net_wm_action_resize], - _atoms[net_wm_action_shade], - _atoms[net_wm_action_maximize_horz], - _atoms[net_wm_action_maximize_vert], - _atoms[net_wm_action_change_desktop], - _atoms[net_wm_action_close], - _atoms[net_wm_state], - _atoms[net_wm_state_modal], - _atoms[net_wm_state_maximized_vert], - _atoms[net_wm_state_maximized_horz], - _atoms[net_wm_state_shaded], - _atoms[net_wm_state_skip_taskbar], - _atoms[net_wm_state_skip_pager], - _atoms[net_wm_state_hidden], - _atoms[net_wm_state_fullscreen], - }; - const int num_supported = sizeof(supported)/sizeof(Atom); - - setValue(root, net_supported, atom, supported, num_supported); -} - - -/* - * Internal setValue. - * Sets a window property on a window, optionally appending to the existing - * value. - */ -void XAtom::setValue(Window win, Atom atom, Atom type, - unsigned char* data, int size, int nelements, - bool append) const { - 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); -} - - -/* - * Set a 32-bit property value on a window. - */ -void XAtom::setValue(Window win, Atoms atom, Atoms type, - unsigned long value) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_ATOMS); - setValue(win, _atoms[atom], _atoms[type], - reinterpret_cast(&value), 32, 1, False); -} - - -/* - * Set an array of 32-bit properties value on a window. - */ -void XAtom::setValue(Window win, Atoms atom, Atoms type, - unsigned long value[], int elements) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_ATOMS); - setValue(win, _atoms[atom], _atoms[type], - reinterpret_cast(value), 32, elements, False); -} - - -/* - * Set an string property value on a window. - */ -void XAtom::setValue(Window win, Atoms atom, StringType type, - const std::string &value) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_STRING_TYPE); - - Atom t; - switch (type) { - case ansi: t = _atoms[string]; break; - case utf8: t = _atoms[utf8_string]; break; - default: assert(False); return; // unhandled StringType - } - setValue(win, _atoms[atom], t, - reinterpret_cast(const_cast(value.c_str())), - 8, value.size() + 1, False); // add 1 to the size to include the null -} - - -/* - * Set an array of string property values on a window. - */ -void XAtom::setValue(Window win, Atoms atom, StringType type, - const StringVect &strings) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_STRING_TYPE); - - Atom t; - switch (type) { - case ansi: t = _atoms[string]; break; - case utf8: t = _atoms[utf8_string]; break; - default: assert(False); return; // unhandled StringType - } - - std::string value; - - StringVect::const_iterator it = strings.begin(); - const StringVect::const_iterator end = strings.end(); - for (; it != end; ++it) - value += *it + '\0'; - - setValue(win, _atoms[atom], t, - reinterpret_cast(const_cast(value.c_str())), - 8, value.size(), False); -} - - -/* - * Internal getValue function used by all of the typed getValue functions. - * Gets an property's value from a window. - * Returns True if the property was successfully retrieved; False if the - * property did not exist on the window, or has a different type/size format - * than the user tried to retrieve. - */ -bool XAtom::getValue(Window win, Atom atom, Atom type, - unsigned long &nelements, unsigned char **value, - int size) const { - assert(win != None); assert(atom != None); assert(type != None); - assert(size == 8 || size == 16 || size == 32); - assert(nelements > 0); - 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; - unsigned long maxread = nelements; - 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 || maxread <= nelements) { - // 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. - int remain = (ret_bytes - 1)/sizeof(long) + 1 + 1; - if (remain > size/8 * (signed)maxread) // dont get more than the max - remain = size/8 * (signed)maxread; - 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 && - ret_bytes == 0); - /* - 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 getValue(win, atom, type, maxread, 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; -} - - -/* - * Gets a 32-bit property's value from a window. - */ -bool XAtom::getValue(Window win, Atoms atom, Atoms type, - unsigned long &nelements, - unsigned long **value) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_ATOMS); - return getValue(win, _atoms[atom], _atoms[type], nelements, - reinterpret_cast(value), 32); -} - - -/* - * Gets a single 32-bit property's value from a window. - */ -bool XAtom::getValue(Window win, Atoms atom, Atoms type, - unsigned long &value) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_ATOMS); - unsigned long *temp; - unsigned long num = 1; - if (! getValue(win, _atoms[atom], _atoms[type], num, - reinterpret_cast(&temp), 32)) - return False; - value = temp[0]; - delete [] temp; - return True; -} - - -/* - * Gets an string property's value from a window. - */ -bool XAtom::getValue(Window win, Atoms atom, StringType type, - std::string &value) const { - unsigned long n = 1; - StringVect s; - if (getValue(win, atom, type, n, s)) { - value = s[0]; - return True; - } - return False; -} - - -bool XAtom::getValue(Window win, Atoms atom, StringType type, - unsigned long &nelements, StringVect &strings) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(type >= 0 && type < NUM_STRING_TYPE); - assert(win != None); assert(_atoms[atom] != None); - assert(nelements > 0); - - Atom t; - switch (type) { - case ansi: t = _atoms[string]; break; - case utf8: t = _atoms[utf8_string]; break; - default: assert(False); return False; // unhandled StringType - } - - unsigned char *value; - unsigned long elements = (unsigned) -1; - if (!getValue(win, _atoms[atom], t, elements, &value, 8) || elements < 1) - return False; - - std::string s(reinterpret_cast(value), elements); - delete [] value; - - std::string::const_iterator it = s.begin(), end = s.end(); - unsigned long num = 0; - while(num < nelements) { - 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) - ++num; - if (it == end) break; - ++it; - if (it == end) break; - } - - nelements = num; - - return True; -} - - -/* - * Removes a property entirely from a window. - */ -void XAtom::eraseValue(Window win, Atoms atom) const { - assert(atom >= 0 && atom < NUM_ATOMS); - XDeleteProperty(_display, win, _atoms[atom]); -} - - -void XAtom::sendClientMessage(Window target, Atoms type, Window about, - long data, long data1, long data2, - long data3, long data4) const { - assert(atom >= 0 && atom < NUM_ATOMS); - assert(target != None); - - XEvent e; - e.xclient.type = ClientMessage; - e.xclient.format = 32; - e.xclient.message_type = _atoms[type]; - e.xclient.window = about; - e.xclient.data.l[0] = data; - e.xclient.data.l[1] = data1; - e.xclient.data.l[2] = data2; - e.xclient.data.l[3] = data3; - e.xclient.data.l[4] = data4; - - XSendEvent(_display, target, False, - SubstructureRedirectMask | SubstructureNotifyMask, - &e); -} diff --git a/src/XAtom.hh b/src/XAtom.hh deleted file mode 100644 index d92b01f0..00000000 --- a/src/XAtom.hh +++ /dev/null @@ -1,230 +0,0 @@ -// XAtom.h for Openbox -// Copyright (c) 2002 - 2002 Ben Janens (ben at orodu.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __XAtom_h -#define __XAtom_h - -#include -#include - -#include - -#include -#include - -class Blackbox; -class ScreenInfo; - -class XAtom { -public: - enum Atoms { - // types - cardinal, - window, - pixmap, - atom, - string, - utf8_string, - -#ifdef HAVE_GETPID - blackbox_pid, -#endif // HAVE_GETPID - - // window hints - wm_colormap_windows, - wm_protocols, - wm_state, - wm_delete_window, - wm_take_focus, - wm_change_state, - wm_name, - wm_icon_name, - wm_class, - motif_wm_hints, - blackbox_attributes, - blackbox_change_attributes, - blackbox_hints, - - // blackbox-protocol atoms (wm -> client) - blackbox_structure_messages, - blackbox_notify_startup, - blackbox_notify_window_add, - blackbox_notify_window_del, - blackbox_notify_window_focus, - blackbox_notify_current_workspace, - blackbox_notify_workspace_count, - blackbox_notify_window_raise, - blackbox_notify_window_lower, - // blackbox-protocol atoms (client -> wm) - blackbox_change_workspace, - blackbox_change_window_focus, - blackbox_cycle_window_focus, - - openbox_show_root_menu, - openbox_show_workspace_menu, - - // NETWM atoms - // root window properties - net_supported, - net_client_list, - net_client_list_stacking, - net_number_of_desktops, - net_desktop_geometry, - net_desktop_viewport, - net_current_desktop, - net_desktop_names, - net_active_window, - net_workarea, - net_supporting_wm_check, -// net_virtual_roots, - // root window messages - net_close_window, - net_wm_moveresize, - // application window properties -// net_properties, - net_wm_name, - net_wm_visible_name, - net_wm_icon_name, - net_wm_visible_icon_name, - net_wm_desktop, - net_wm_window_type, - net_wm_state, - net_wm_strut, -// net_wm_icon_geometry, -// net_wm_icon, -// net_wm_pid, -// net_wm_handled_icons, - net_wm_allowed_actions, - // application protocols -// net_wm_ping, - - net_wm_window_type_desktop, - net_wm_window_type_dock, - net_wm_window_type_toolbar, - net_wm_window_type_menu, - net_wm_window_type_utility, - net_wm_window_type_splash, - net_wm_window_type_dialog, - net_wm_window_type_normal, - - net_wm_moveresize_size_topleft, - net_wm_moveresize_size_topright, - net_wm_moveresize_size_bottomleft, - net_wm_moveresize_size_bottomright, - net_wm_moveresize_move, - - net_wm_action_move, - net_wm_action_resize, - net_wm_action_shade, - net_wm_action_maximize_horz, - net_wm_action_maximize_vert, - net_wm_action_change_desktop, - net_wm_action_close, - - net_wm_state_modal, - net_wm_state_maximized_vert, - net_wm_state_maximized_horz, - net_wm_state_shaded, - net_wm_state_skip_taskbar, - net_wm_state_skip_pager, - net_wm_state_hidden, - net_wm_state_fullscreen, - - kde_net_system_tray_windows, - kde_net_wm_system_tray_window_for, - kde_net_wm_window_type_override, - - // constant for how many atoms exist in the enumerator - NUM_ATOMS - }; - - enum StringType { - ansi, - utf8, - NUM_STRING_TYPE - }; - -private: - typedef std::vector SupportWindows; - - Display *_display; - // windows used to specify support for NETWM - SupportWindows _support_windows; - Atom _atoms[NUM_ATOMS]; - - Atom create(const char *name) const; - - void setValue(Window win, Atom atom, Atom type, unsigned char *data, - int size, int nelements, bool append) const; - bool getValue(Window win, Atom atom, Atom type, - unsigned long &nelements, unsigned char **value, - int size) const; - - // no copying!! - XAtom(const XAtom &); - XAtom& operator=(const XAtom&); - -public: - typedef std::vector StringVect; - - XAtom(Display *d); - virtual ~XAtom(); - - // setup support on a screen, each screen should call this once in its - // constructor. - void setSupported(const ScreenInfo *screen); - - void setValue(Window win, Atoms atom, Atoms type, unsigned long value) const; - void setValue(Window win, Atoms atom, Atoms type, - unsigned long value[], int elements) const; - void setValue(Window win, Atoms atom, StringType type, - const std::string &value) const; - void setValue(Window win, Atoms atom, StringType type, - const StringVect &strings) const; - - // the 'value' is allocated inside the function and - // delete [] value needs to be called when you are done with it. - // the 'value' array returned is null terminated, and has 'nelements' - // elements in it plus the null. - // nelements must be set to the maximum number of elements to read from - // the property. - bool getValue(Window win, Atoms atom, Atoms type, - unsigned long &nelements, unsigned long **value) const; - bool getValue(Window win, Atoms atom, Atoms type, unsigned long &value) const; - bool getValue(Window win, Atoms atom, StringType type, - std::string &value) const; - bool getValue(Window win, Atoms atom, StringType type, - unsigned long &nelements, StringVect &strings) const; - - void eraseValue(Window win, Atoms atom) const; - - // sends a client message a window - void sendClientMessage(Window target, Atoms type, Window about, - long data = 0, long data1 = 0, long data2 = 0, - long data3 = 0, long data4 = 0) const; - - // temporary function!! remove when not used in blackbox.hh anymore!! - inline Atom getAtom(Atoms a) - { assert(a >= 0 && a < NUM_ATOMS); Atom ret = _atoms[a]; - assert(ret != 0); return ret; } -}; - -#endif // __XAtom_h diff --git a/src/basedisplay.cc b/src/basedisplay.cc new file mode 100644 index 00000000..65574d65 --- /dev/null +++ b/src/basedisplay.cc @@ -0,0 +1,521 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// BaseDisplay.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +#include +#include +#include + +#ifdef SHAPE +# include +#endif // SHAPE + +#ifdef XINERAMA +# include +#endif // XINERAMA + +#ifdef HAVE_FCNTL_H +# include +#endif // HAVE_FCNTL_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H + +#ifdef HAVE_STRING_H +# include +#endif // HAVE_STRING_H + +#ifdef HAVE_UNISTD_H +# include +# include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_SYS_SELECT_H +# include +#endif // HAVE_SYS_SELECT_H + +#ifdef HAVE_SIGNAL_H +# include +#endif // HAVE_SIGNAL_H + +#ifndef SA_NODEFER +# ifdef SA_INTERRUPT +# define SA_NODEFER SA_INTERRUPT +# else // !SA_INTERRUPT +# define SA_NODEFER (0) +# endif // SA_INTERRUPT +#endif // SA_NODEFER + +#ifdef HAVE_SYS_WAIT_H +# include +# include +#endif // HAVE_SYS_WAIT_H +} + +#include +using std::string; + +#include "basedisplay.hh" +#include "gccache.hh" +#include "timer.hh" +#include "util.hh" + + +// X error handler to handle any and all X errors while the application is +// running +static bool internal_error = False; + +BaseDisplay *base_display; + +static int handleXErrors(Display *d, XErrorEvent *e) { +#ifdef DEBUG + char errtxt[128]; + + XGetErrorText(d, e->error_code, errtxt, 128); + fprintf(stderr, + i18n(BaseDisplaySet, BaseDisplayXError, + "%s: X error: %s(%d) opcodes %d/%d\n resource 0x%lx\n"), + base_display->getApplicationName(), errtxt, e->error_code, + e->request_code, e->minor_code, e->resourceid); +#else + // shutup gcc + (void) d; + (void) e; +#endif // DEBUG + + if (internal_error) abort(); + + return(False); +} + + +// signal handler to allow for proper and gentle shutdown + +#ifndef HAVE_SIGACTION +static RETSIGTYPE signalhandler(int sig) { +#else // HAVE_SIGACTION +static void signalhandler(int sig) { +#endif // HAVE_SIGACTION + + static int re_enter = 0; + + switch (sig) { + case SIGCHLD: + int status; + waitpid(-1, &status, WNOHANG | WUNTRACED); + +#ifndef HAVE_SIGACTION + // assume broken, braindead sysv signal semantics + signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler); +#endif // HAVE_SIGACTION + + break; + + default: + if (base_display->handleSignal(sig)) { + +#ifndef HAVE_SIGACTION + // assume broken, braindead sysv signal semantics + signal(sig, (RETSIGTYPE (*)(int)) signalhandler); +#endif // HAVE_SIGACTION + + return; + } + + fprintf(stderr, i18n(BaseDisplaySet, BaseDisplaySignalCaught, + "%s: signal %d caught\n"), + base_display->getApplicationName(), sig); + + if (! base_display->isStartup() && ! re_enter) { + internal_error = True; + + re_enter = 1; + fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayShuttingDown, + "shutting down\n")); + base_display->shutdown(); + } + + if (sig != SIGTERM && sig != SIGINT) { + fprintf(stderr, i18n(BaseDisplaySet, BaseDisplayAborting, + "aborting... dumping core\n")); + abort(); + } + + exit(0); + + break; + } +} + + +BaseDisplay::BaseDisplay(const char *app_name, const char *dpy_name) { + application_name = app_name; + + run_state = STARTUP; + + ::base_display = this; + +#ifdef HAVE_SIGACTION + struct sigaction action; + + action.sa_handler = signalhandler; + action.sa_mask = sigset_t(); + action.sa_flags = SA_NOCLDSTOP | SA_NODEFER; + + sigaction(SIGPIPE, &action, NULL); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGFPE, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGCHLD, &action, NULL); + sigaction(SIGHUP, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + sigaction(SIGUSR2, &action, NULL); +#else // !HAVE_SIGACTION + signal(SIGPIPE, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGSEGV, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGFPE, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGTERM, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGINT, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGUSR1, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGUSR2, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGHUP, (RETSIGTYPE (*)(int)) signalhandler); + signal(SIGCHLD, (RETSIGTYPE (*)(int)) signalhandler); +#endif // HAVE_SIGACTION + + if (! (display = XOpenDisplay(dpy_name))) { + fprintf(stderr, + i18n(BaseDisplaySet, BaseDisplayXConnectFail, + "BaseDisplay::BaseDisplay: connection to X server failed.\n")); + ::exit(2); + } else if (fcntl(ConnectionNumber(display), F_SETFD, 1) == -1) { + fprintf(stderr, + i18n(BaseDisplaySet, BaseDisplayCloseOnExecFail, + "BaseDisplay::BaseDisplay: couldn't mark display connection " + "as close-on-exec\n")); + ::exit(2); + } + + display_name = XDisplayName(dpy_name); + +#ifdef SHAPE + shape.extensions = XShapeQueryExtension(display, &shape.event_basep, + &shape.error_basep); +#else // !SHAPE + shape.extensions = False; +#endif // SHAPE + +#ifdef XINERAMA + if (XineramaQueryExtension(display, &xinerama.event_basep, + &xinerama.error_basep) && + XineramaQueryVersion(display, &xinerama.major, &xinerama.minor)) { +#ifdef DEBUG + fprintf(stderr, + "BaseDisplay::BaseDisplay: Found Xinerama version %d.%d\n", + xinerama.major, xinerama.minor); +#endif // DEBUG + xinerama.extensions = True; + } else { + xinerama.extensions = False; + } +#endif // XINERAMA + + XSetErrorHandler((XErrorHandler) handleXErrors); + + screenInfoList.reserve(ScreenCount(display)); + for (int i = 0; i < ScreenCount(display); ++i) + screenInfoList.push_back(ScreenInfo(this, i)); + + NumLockMask = ScrollLockMask = 0; + + const XModifierKeymap* const modmap = XGetModifierMapping(display); + 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]) + NumLockMask = mask_table[cnt / modmap->max_keypermod]; + if (scroll_lock == modmap->modifiermap[cnt]) + ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; + } + } + + MaskList[0] = 0; + MaskList[1] = LockMask; + MaskList[2] = NumLockMask; + MaskList[3] = LockMask | NumLockMask; + MaskList[4] = ScrollLockMask; + MaskList[5] = ScrollLockMask | LockMask; + MaskList[6] = ScrollLockMask | NumLockMask; + MaskList[7] = ScrollLockMask | LockMask | NumLockMask; + MaskListLength = sizeof(MaskList) / sizeof(MaskList[0]); + + if (modmap) XFreeModifiermap(const_cast(modmap)); + + gccache = (BGCCache *) 0; +} + + +BaseDisplay::~BaseDisplay(void) { + delete gccache; + + XCloseDisplay(display); +} + + +void BaseDisplay::eventLoop(void) { + run(); + + const int xfd = ConnectionNumber(display); + + while (run_state == RUNNING && ! internal_error) { + if (XPending(display)) { + XEvent e; + XNextEvent(display, &e); + process_event(&e); + } else { + fd_set rfds; + timeval now, tm, *timeout = (timeval *) 0; + + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); + + if (! timerList.empty()) { + const BTimer* const timer = timerList.top(); + + gettimeofday(&now, 0); + tm = timer->timeRemaining(now); + + timeout = &tm; + } + + select(xfd + 1, &rfds, 0, 0, timeout); + + // check for timer timeout + gettimeofday(&now, 0); + + // there is a small chance for deadlock here: + // *IF* the timer list keeps getting refreshed *AND* the time between + // timer->start() and timer->shouldFire() is within the timer's period + // then the timer will keep firing. This should be VERY near impossible. + while (! timerList.empty()) { + BTimer *timer = timerList.top(); + if (! timer->shouldFire(now)) + break; + + timerList.pop(); + + timer->fireTimeout(); + timer->halt(); + if (timer->isRecurring()) + timer->start(); + } + } + } +} + + +void BaseDisplay::addTimer(BTimer *timer) { + if (! timer) return; + + timerList.push(timer); +} + + +void BaseDisplay::removeTimer(BTimer *timer) { + timerList.release(timer); +} + + +/* + * 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 BaseDisplay::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) ? MaskListLength / 2: + MaskListLength; + for (size_t cnt = 0; cnt < length; ++cnt) + XGrabButton(display, button, modifiers | MaskList[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 BaseDisplay::ungrabButton(unsigned int button, unsigned int modifiers, + Window grab_window) const { + for (size_t cnt = 0; cnt < MaskListLength; ++cnt) + XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window); +} + + +const ScreenInfo* BaseDisplay::getScreenInfo(unsigned int s) const { + if (s < screenInfoList.size()) + return &screenInfoList[s]; + return (const ScreenInfo*) 0; +} + + +BGCCache* BaseDisplay::gcCache(void) const { + if (! gccache) + gccache = new BGCCache(this, screenInfoList.size()); + + return gccache; +} + + +ScreenInfo::ScreenInfo(BaseDisplay *d, unsigned int num) { + basedisplay = d; + screen_number = num; + + root_window = RootWindow(basedisplay->getXDisplay(), screen_number); + + rect.setSize(WidthOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), + screen_number)), + HeightOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), + screen_number))); + /* + 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. + */ + + depth = DefaultDepth(basedisplay->getXDisplay(), screen_number); + visual = DefaultVisual(basedisplay->getXDisplay(), screen_number); + colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number); + + 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_number; + vinfo_template.c_class = TrueColor; + + vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(), + 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(basedisplay->getXDisplay(), root_window, + visual, AllocNone); + } + + XFree(vinfo_return); + } + + // get the default display string and strip the screen number + string default_string = DisplayString(basedisplay->getXDisplay()); + 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(screen_number)); + +#ifdef 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(d->getXDisplay())) { + /* + 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(d->getXDisplay(), &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; + } + } + } + } +#endif // XINERAMA +} diff --git a/src/basedisplay.hh b/src/basedisplay.hh new file mode 100644 index 00000000..c4286955 --- /dev/null +++ b/src/basedisplay.hh @@ -0,0 +1,182 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// BaseDisplay.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __BaseDisplay_hh +#define __BaseDisplay_hh + +extern "C" { +#include +#include +} + +#include +#include + +// forward declaration +class BaseDisplay; +class BGCCache; + +#include "timer.hh" +#include "util.hh" + +class ScreenInfo { +private: + BaseDisplay *basedisplay; + Visual *visual; + Window root_window; + Colormap colormap; + + int depth; + unsigned int screen_number; + std::string display_string; + Rect rect; +#ifdef XINERAMA + RectList xinerama_areas; + bool xinerama_active; +#endif + +public: + ScreenInfo(BaseDisplay *d, unsigned int num); + + inline BaseDisplay *getBaseDisplay(void) const { return basedisplay; } + inline Visual *getVisual(void) const { return visual; } + inline Window getRootWindow(void) const { return root_window; } + inline Colormap getColormap(void) const { return colormap; } + inline int getDepth(void) const { return depth; } + inline unsigned int getScreenNumber(void) const + { return screen_number; } + inline const Rect& getRect(void) const { return rect; } + inline unsigned int getWidth(void) const { return rect.width(); } + inline unsigned int getHeight(void) const { return rect.height(); } + inline const std::string& displayString(void) const + { return display_string; } +#ifdef XINERAMA + inline const RectList &getXineramaAreas(void) const { return xinerama_areas; } + inline bool isXineramaActive(void) const { return xinerama_active; } +#endif +}; + + +class BaseDisplay: public TimerQueueManager { +private: + struct BShape { + bool extensions; + int event_basep, error_basep; + }; + BShape shape; + +#ifdef XINERAMA + struct BXinerama { + bool extensions; + int event_basep, error_basep; + int major, minor; // version + }; + BXinerama xinerama; +#endif // XINERAMA + + unsigned int MaskList[8]; + size_t MaskListLength; + + enum RunState { STARTUP, RUNNING, SHUTDOWN }; + RunState run_state; + + Display *display; + mutable BGCCache *gccache; + + typedef std::vector ScreenInfoList; + ScreenInfoList screenInfoList; + TimerQueue timerList; + + const char *display_name, *application_name; + + // no copying! + BaseDisplay(const BaseDisplay &); + BaseDisplay& operator=(const BaseDisplay&); + +protected: + // pure virtual function... you must override this + virtual void process_event(XEvent *e) = 0; + + // the masks of the modifiers which are ignored in button events. + int NumLockMask, ScrollLockMask; + + +public: + BaseDisplay(const char *app_name, const char *dpy_name = 0); + virtual ~BaseDisplay(void); + + const ScreenInfo* getScreenInfo(const unsigned int s) const; + + BGCCache *gcCache(void) const; + + inline bool hasShapeExtensions(void) const + { return shape.extensions; } +#ifdef XINERAMA + inline bool hasXineramaExtensions(void) const + { return xinerama.extensions; } +#endif // XINERAMA + inline bool doShutdown(void) const + { return run_state == SHUTDOWN; } + inline bool isStartup(void) const + { return run_state == STARTUP; } + + inline Display *getXDisplay(void) const { return display; } + + inline const char *getXDisplayName(void) const + { return display_name; } + inline const char *getApplicationName(void) const + { return application_name; } + + inline unsigned int getNumberOfScreens(void) const + { return screenInfoList.size(); } + inline int getShapeEventBase(void) const + { return shape.event_basep; } +#ifdef XINERAMA + inline int getXineramaMajorVersion(void) const + { return xinerama.major; } +#endif // XINERAMA + + inline void shutdown(void) { run_state = SHUTDOWN; } + inline void run(void) { run_state = RUNNING; } + + 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 eventLoop(void); + + // from TimerQueueManager interface + virtual void addTimer(BTimer *timer); + virtual void removeTimer(BTimer *timer); + + // another pure virtual... this is used to handle signals that BaseDisplay + // doesn't understand itself + virtual bool handleSignal(int sig) = 0; +}; + + +#endif // __BaseDisplay_hh diff --git a/src/blackbox.cc b/src/blackbox.cc index 82c8b1d1..63e0ef05 100644 --- a/src/blackbox.cc +++ b/src/blackbox.cc @@ -96,21 +96,20 @@ extern "C" { #include using std::string; -#include "i18n.hh" #include "blackbox.hh" -#include "Basemenu.hh" -#include "Clientmenu.hh" -#include "GCCache.hh" -#include "Image.hh" -#include "Rootmenu.hh" -#include "Screen.hh" -#include "Slit.hh" -#include "Toolbar.hh" -#include "Util.hh" -#include "Window.hh" -#include "Workspace.hh" -#include "Workspacemenu.hh" -#include "XAtom.hh" +#include "basemenu.hh" +#include "clientmenu.hh" +#include "gccache.hh" +#include "image.hh" +#include "rootmenu.hh" +#include "screen.hh" +#include "slit.hh" +#include "toolbar.hh" +#include "util.hh" +#include "window.hh" +#include "workspace.hh" +#include "workspacemenu.hh" +#include "xatom.hh" Blackbox *blackbox; diff --git a/src/blackbox.hh b/src/blackbox.hh index 1efec772..52e0e653 100644 --- a/src/blackbox.hh +++ b/src/blackbox.hh @@ -47,11 +47,10 @@ extern "C" { #include #include -#include "i18n.hh" -#include "BaseDisplay.hh" -#include "Configuration.hh" -#include "Timer.hh" -#include "XAtom.hh" +#include "basedisplay.hh" +#include "configuration.hh" +#include "timer.hh" +#include "xatom.hh" #define AttribShaded (1l << 0) #define AttribMaxHoriz (1l << 1) diff --git a/src/color.cc b/src/color.cc new file mode 100644 index 00000000..0aca132d --- /dev/null +++ b/src/color.cc @@ -0,0 +1,244 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Color.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +} + +#include + +#include "color.hh" +#include "basedisplay.hh" + + +BColor::ColorCache BColor::colorcache; +bool BColor::cleancache = false; + +BColor::BColor(const BaseDisplay * const _display, unsigned int _screen) + : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen) +{} + +BColor::BColor(int _r, int _g, int _b, + const BaseDisplay * const _display, unsigned int _screen) + : allocated(false), r(_r), g(_g), b(_b), p(0), dpy(_display), scrn(_screen) +{} + + +BColor::BColor(const std::string &_name, + const BaseDisplay * const _display, unsigned int _screen) + : allocated(false), r(-1), g(-1), b(-1), p(0), dpy(_display), scrn(_screen), + colorname(_name) { + parseColorName(); +} + + +BColor::~BColor(void) { + deallocate(); +} + + +void BColor::setDisplay(const BaseDisplay * const _display, + unsigned int _screen) { + if (_display == display() && _screen == screen()) { + // nothing to do + return; + } + + deallocate(); + + dpy = _display; + scrn = _screen; + + if (! colorname.empty()) { + parseColorName(); + } +} + + +unsigned long BColor::pixel(void) const { + if (! allocated) { + // mutable + BColor *that = (BColor *) this; + that->allocate(); + } + + return p; +} + + +void BColor::parseColorName(void) { + assert(dpy != 0); + + if (colorname.empty()) { + fprintf(stderr, "BColor: empty colorname, cannot parse (using black)\n"); + setRGB(0, 0, 0); + } + + if (scrn == ~(0u)) + scrn = DefaultScreen(display()->getXDisplay()); + Colormap colormap = display()->getScreenInfo(scrn)->getColormap(); + + // get rgb values from colorname + XColor xcol; + xcol.red = 0; + xcol.green = 0; + xcol.blue = 0; + xcol.pixel = 0; + + if (! XParseColor(display()->getXDisplay(), colormap, + colorname.c_str(), &xcol)) { + fprintf(stderr, "BColor::allocate: color parse error: \"%s\"\n", + colorname.c_str()); + setRGB(0, 0, 0); + return; + } + + setRGB(xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8); +} + + +void BColor::allocate(void) { + assert(dpy != 0); + + if (scrn == ~(0u)) scrn = DefaultScreen(display()->getXDisplay()); + Colormap colormap = display()->getScreenInfo(scrn)->getColormap(); + + if (! isValid()) { + if (colorname.empty()) { + fprintf(stderr, "BColor: cannot allocate invalid color (using black)\n"); + setRGB(0, 0, 0); + } else { + parseColorName(); + } + } + + // see if we have allocated this color before + RGB rgb(display(), scrn, r, g, b); + ColorCache::iterator it = colorcache.find(rgb); + if (it != colorcache.end()) { + // found + allocated = true; + p = (*it).second.p; + (*it).second.count++; + return; + } + + // allocate color from rgb values + XColor xcol; + xcol.red = r | r << 8; + xcol.green = g | g << 8; + xcol.blue = b | b << 8; + xcol.pixel = 0; + + if (! XAllocColor(display()->getXDisplay(), colormap, &xcol)) { + fprintf(stderr, "BColor::allocate: color alloc error: rgb:%x/%x/%x\n", + r, g, b); + xcol.pixel = 0; + } + + p = xcol.pixel; + allocated = true; + + colorcache.insert(ColorCacheItem(rgb, PixelRef(p))); + + if (cleancache) + doCacheCleanup(); +} + + +void BColor::deallocate(void) { + if (! allocated) + return; + + assert(dpy != 0); + + ColorCache::iterator it = colorcache.find(RGB(display(), scrn, r, g, b)); + if (it != colorcache.end()) { + if ((*it).second.count >= 1) + (*it).second.count--; + } + + if (cleancache) + doCacheCleanup(); + + allocated = false; +} + + +BColor &BColor::operator=(const BColor &c) { + deallocate(); + + setRGB(c.r, c.g, c.b); + colorname = c.colorname; + dpy = c.dpy; + scrn = c.scrn; + return *this; +} + + +void BColor::cleanupColorCache(void) { + cleancache = true; +} + + +void BColor::doCacheCleanup(void) { + // ### TODO - support multiple displays! + ColorCache::iterator it = colorcache.begin(); + if (it == colorcache.end()) { + // nothing to do + return; + } + + const BaseDisplay* const display = (*it).first.display; + unsigned long *pixels = new unsigned long[ colorcache.size() ]; + unsigned int i, count; + + for (i = 0; i < display->getNumberOfScreens(); i++) { + count = 0; + it = colorcache.begin(); + + while (it != colorcache.end()) { + if ((*it).second.count != 0 || (*it).first.screen != i) { + ++it; + continue; + } + + pixels[ count++ ] = (*it).second.p; + ColorCache::iterator it2 = it; + ++it; + colorcache.erase(it2); + } + + if (count > 0) + XFreeColors(display->getXDisplay(), + display->getScreenInfo(i)->getColormap(), + pixels, count, 0); + } + + delete [] pixels; + cleancache = false; +} diff --git a/src/color.hh b/src/color.hh new file mode 100644 index 00000000..9eb8ef2e --- /dev/null +++ b/src/color.hh @@ -0,0 +1,128 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Color.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef COLOR_HH +#define COLOR_HH + +extern "C" { +#include +} + +#include +#include + +class BaseDisplay; + +class BColor { +public: + BColor(const BaseDisplay * const _display = 0, unsigned int _screen = ~(0u)); + BColor(int _r, int _g, int _b, + const BaseDisplay * const _display, unsigned int _screen = ~(0u)); + BColor(const std::string &_name, + const BaseDisplay * const _display, unsigned int _screen = ~(0u)); + ~BColor(void); + + inline const std::string &name(void) const { return colorname; } + + inline int red(void) const { return r; } + inline int green(void) const { return g; } + inline int blue(void) const { return b; } + void setRGB(int _r, int _g, int _b) { + deallocate(); + r = _r; + g = _g; + b = _b; + } + + inline const BaseDisplay *display(void) const { return dpy; } + inline unsigned int screen(void) const { return scrn; } + void setDisplay(const BaseDisplay * const _display, + unsigned int _screen = ~(0u)); + + inline bool isAllocated(void) const { return allocated; } + + inline bool isValid(void) const { return r != -1 && g != -1 && b != -1; } + + unsigned long pixel(void) const; + + // operators + BColor &operator=(const BColor &c); + inline bool operator==(const BColor &c) const + { return (r == c.r && b == c.b && b == c.b); } + inline bool operator!=(const BColor &c) const + { return (! operator==(c)); } + + static void cleanupColorCache(void); + +private: + void parseColorName(void); + void allocate(void); + void deallocate(void); + + bool allocated; + int r, g, b; + unsigned long p; + const BaseDisplay *dpy; + unsigned int scrn; + std::string colorname; + + // global color allocator/deallocator + struct RGB { + const BaseDisplay* const display; + const unsigned int screen; + const int r, g, b; + + RGB(void) : display(0), screen(~(0u)), r(-1), g(-1), b(-1) { } + RGB(const BaseDisplay * const a, const unsigned int b, + const int x, const int y, const int z) + : display(a), screen(b), r(x), g(y), b(z) {} + RGB(const RGB &x) + : display(x.display), screen(x.screen), r(x.r), g(x.g), b(x.b) {} + + inline bool operator==(const RGB &x) const { + return display == x.display && + screen == x.screen && + r == x.r && g == x.g && b == x.b; + } + + inline bool operator<(const RGB &x) const { + unsigned long p1, p2; + p1 = (screen << 24 | r << 16 | g << 8 | b) & 0x00ffffff; + p2 = (x.screen << 24 | x.r << 16 | x.g << 8 | x.b) & 0x00ffffff; + return p1 < p2; + } + }; + struct PixelRef { + const unsigned long p; + unsigned int count; + inline PixelRef(void) : p(0), count(0) { } + inline PixelRef(const unsigned long x) : p(x), count(1) { } + }; + typedef std::map ColorCache; + typedef ColorCache::value_type ColorCacheItem; + static ColorCache colorcache; + static bool cleancache; + static void doCacheCleanup(void); +}; + +#endif // COLOR_HH diff --git a/src/configuration.cc b/src/configuration.cc new file mode 100644 index 00000000..b7a7097e --- /dev/null +++ b/src/configuration.cc @@ -0,0 +1,253 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Configuration.hh for Blackbox - an X11 Window manager +// Copyright (c) 2002 - 2002 Ben Jansens (ben@orodu.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H +} + +#include "configuration.hh" +#include "util.hh" + +#include + +using std::string; + +bool Configuration::_initialized = False; + +Configuration::Configuration(const string &file, bool autosave) { + setFile(file); + _modified = False; + _database = NULL; + _autosave = autosave; + if (! _initialized) { + XrmInitialize(); + _initialized = True; + } +} + +Configuration::Configuration(bool autosave) { + _modified = False; + _database = NULL; + _autosave = autosave; + if (! _initialized) { + XrmInitialize(); + _initialized = True; + } +} + +Configuration::~Configuration() { + if (_database != NULL) + XrmDestroyDatabase(_database); +} + +void Configuration::setFile(const string &file) { + _file = file; +} + +void Configuration::setAutoSave(bool autosave) { + _autosave = autosave; +} + +void Configuration::save() { + assert(_database != NULL); + XrmPutFileDatabase(_database, _file.c_str()); + _modified = False; +} + +bool Configuration::load() { + if (_database != NULL) + XrmDestroyDatabase(_database); + _modified = False; + if (NULL == (_database = XrmGetFileDatabase(_file.c_str()))) + return False; + return True; +} + +bool Configuration::merge(const string &file, bool overwrite) { + if (XrmCombineFileDatabase(file.c_str(), &_database, overwrite) == 0) + return False; + _modified = True; + if (_autosave) + save(); + return True; +} + +void Configuration::create() { + if (_database != NULL) + XrmDestroyDatabase(_database); + _modified = False; + assert(NULL != (_database = XrmGetStringDatabase(""))); +} + +void Configuration::setValue(const string &rname, bool value) { + assert(_database != NULL); + + const char *val = (value ? "True" : "False"); + string rc_string = rname + ": " + val; + XrmPutLineResource(&_database, rc_string.c_str()); + + _modified = True; + if (_autosave) + save(); +} + +void Configuration::setValue(const string &rname, unsigned long value) { + assert(_database != NULL); + + string rc_string = rname + ": " + itostring(value); + XrmPutLineResource(&_database, rc_string.c_str()); + + _modified = True; + if (_autosave) + save(); +} + +void Configuration::setValue(const string &rname, long value) { + assert(_database != NULL); + + string rc_string = rname + ": " + itostring(value); + XrmPutLineResource(&_database, rc_string.c_str()); + + _modified = True; + if (_autosave) + save(); +} + +void Configuration::setValue(const string &rname, const char *value) { + assert(_database != NULL); + assert(value != NULL); + + string rc_string = rname + ": " + value; + XrmPutLineResource(&_database, rc_string.c_str()); + + _modified = True; + if (_autosave) + save(); +} + +void Configuration::setValue(const string &rname, const string &value) { + assert(_database != NULL); + + string rc_string = rname + ": " + value; + XrmPutLineResource(&_database, rc_string.c_str()); + + _modified = True; + if (_autosave) + save(); +} + +bool Configuration::getValue(const string &rname, bool &value) const { + assert(_database != NULL); + + string rclass = createClassName(rname); + + char *rettype; + XrmValue retvalue; + if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), + &rettype, &retvalue) || retvalue.addr == NULL) + return False; + string val = retvalue.addr; + if (val == "True" || val == "True") + value = True; + else + value = False; + return True; +} + +bool Configuration::getValue(const string &rname, long &value) const { + assert(_database != NULL); + + string rclass = createClassName(rname); + + char *rettype; + XrmValue retvalue; + if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), + &rettype, &retvalue) || retvalue.addr == NULL) + return False; + char *end; + value = strtol(retvalue.addr, &end, 10); + if (end == retvalue.addr) + return False; + return True; +} + +bool Configuration::getValue(const string &rname, unsigned long &value) const { + assert(_database != NULL); + + string rclass = createClassName(rname); + + char *rettype; + XrmValue retvalue; + if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), + &rettype, &retvalue) || retvalue.addr == NULL) + return False; + char *end; + value = strtoul(retvalue.addr, &end, 10); + if (end == retvalue.addr) + return False; + return True; +} + +bool Configuration::getValue(const string &rname, + string &value) const { + assert(_database != NULL); + + string rclass = createClassName(rname); + + char *rettype; + XrmValue retvalue; + if (0 == XrmGetResource(_database, rname.c_str(), rclass.c_str(), + &rettype, &retvalue) || retvalue.addr == NULL) + return False; + value = retvalue.addr; + return True; +} + + +string Configuration::createClassName(const string &rname) const { + string rclass(rname); + + string::iterator it = rclass.begin(), end = rclass.end(); + while (True) { + *it = toUpper(*it); + ++it; + if (it == end) break; + it = std::find(it, rclass.end(), '.'); + if (it == end) break; + ++it; + if (it == end) break; + } + return rclass; +} + + +char Configuration::toUpper(char c) const { + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + return c; +} diff --git a/src/configuration.hh b/src/configuration.hh new file mode 100644 index 00000000..8f4a3157 --- /dev/null +++ b/src/configuration.hh @@ -0,0 +1,98 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Configuration.hh for Blackbox - an X11 Window manager +// Copyright (c) 2002 - 2002 Ben Jansens (ben@orodu.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Configuration_hh +#define __Configuration_hh + +#include +#include +#include + +/* + * The Configuration class is a generic wrapper for configuration settings. + * + * This class is used for the global rc/config file, and for styles. + * + * This implementation of the Configuration class wraps an X resource database + * file. + */ +class Configuration { +public: + explicit Configuration(const std::string &file, bool autosave = True); + Configuration(bool autosave = True); + virtual ~Configuration(); + + inline const std::string &file() const { + return static_cast(_file); + } + void setFile(const std::string &file); + + // defaults to true! + inline bool autoSave() const { + return _autosave; + } + void setAutoSave(bool); + + inline bool isModified() const { + return _modified; + } + + void save(); + bool load(); + bool merge(const std::string &file, bool overwrite = False); + void create(); + + void setValue(const std::string &rname, bool value); + inline void setValue(const std::string &rname, int value) { + setValue(rname, (long) value); + } + inline void setValue(const std::string &rname, unsigned int value) { + setValue(rname, (unsigned long) value); + } + void setValue(const std::string &rname, long value); + void setValue(const std::string &rname, unsigned long value); + void setValue(const std::string &rname, const std::string &value); + void setValue(const std::string &rname, const char *value); + + bool getValue(const std::string &rname, bool &value) const; + inline bool getValue(const std::string &rname, int &value) const { + return getValue(rname, (long) value); + } + inline bool getValue(const std::string &rname, unsigned int &value) const { + return getValue(rname, (unsigned long) value); + } + bool getValue(const std::string &rname, long &value) const; + bool getValue(const std::string &rname, unsigned long &value) const; + bool getValue(const std::string &rname, std::string &value) const; + +private: + std::string createClassName(const std::string &rname) const; + char toUpper(char) const; + + static bool _initialized; + std::string _file; + bool _modified; + bool _autosave; + XrmDatabase _database; +}; + +#endif // __Configuration_hh diff --git a/src/font.cc b/src/font.cc new file mode 100644 index 00000000..ba1ae1c1 --- /dev/null +++ b/src/font.cc @@ -0,0 +1,374 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Font.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H +} + +#include +#include + +using std::string; +using std::cerr; +using std::endl; + +#include "font.hh" +#include "util.hh" +#include "gccache.hh" +#include "color.hh" + +string BFont::_fallback_font = "fixed"; + +#ifdef XFT +BFont::BFont(Display *d, BScreen *screen, const string &family, int size, + bool bold, bool italic, bool shadow, unsigned char offset, + unsigned char tint, bool antialias) : + _display(d), + _screen(screen), + _family(family), + _simplename(False), + _size(size), + _bold(bold), + _italic(italic), + _antialias(antialias), + _shadow(shadow), + _offset(offset), + _tint(tint), + _xftfont(0), + _font(0), + _fontset(0), + _fontset_extents(0) { + _valid = False; + + _xftfont = XftFontOpen(_display, _screen->getScreenNumber(), + XFT_FAMILY, XftTypeString, _family.c_str(), + XFT_SIZE, XftTypeInteger, _size, + XFT_WEIGHT, XftTypeInteger, (_bold ? + XFT_WEIGHT_BOLD : + XFT_WEIGHT_MEDIUM), + XFT_SLANT, XftTypeInteger, (_italic ? + XFT_SLANT_ITALIC : + XFT_SLANT_ROMAN), + XFT_ANTIALIAS, XftTypeBool, _antialias, + 0); + if (! _xftfont) + return; // failure + + _font = XLoadQueryFont(_display, buildXlfd().c_str()); + if (! _font) + return; // failure + + _valid = True; +} +#endif + + +BFont::BFont(Display *d, BScreen *screen, const string &xlfd) : + _display(d), + _screen(screen), +#ifdef XFT + _antialias(False), + _shadow(False), + _xftfont(0), +#endif // XFT + _font(0), + _fontset(0), + _fontset_extents(0) { + string int_xlfd; + if (xlfd.empty()) + int_xlfd = _fallback_font; + else + int_xlfd = xlfd; + + if ((_valid = createXFont(int_xlfd))) + return; // success + + if (int_xlfd != _fallback_font) { + // try the fallback + cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl << + "Falling back to default '" << _fallback_font << "'" << endl; + + if ((_valid = createXFont(_fallback_font))) + return; // success + } + + cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl << + "Giving up!" << endl; + return; // failure +} + + +bool BFont::createXFont(const std::string &xlfd) { + /* + Even though this is only used for font sets (multibyte), it is still parsed + out so that the bold/italic/etc information is still available from the + class when using non-multibyte. + + This is where _simplename, _bold, _italic, and _size are initialized, since + they are not initialized in the constructor. This needs to occur before + calling any Xlfd-building functions. + */ + if (! parseXlfd(xlfd)) + return False; + + if (i18n.multibyte()) { + char **missing, *def = "-"; + int nmissing; + + _fontset = XCreateFontSet(_display, buildMultibyteXlfd().c_str(), + &missing, &nmissing, &def); + if (nmissing) XFreeStringList(missing); + if (_fontset) + _fontset_extents = XExtentsOfFontSet(_fontset); + else + return False; + + assert(_fontset_extents); + } + + _font = XLoadQueryFont(_display, xlfd.c_str()); + if (! _font) + return False; + return True; +} + + +BFont::~BFont(void) { +#ifdef XFT + if (_xftfont) + XftFontClose(_display, _xftfont); +#endif // XFT + + if (i18n.multibyte() && _fontset) + XFreeFontSet(_display, _fontset); + if (_font) + XFreeFont(_display, _font); +} + + +/* + * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD. + */ +string BFont::buildXlfd(void) const { + if (_simplename) + return _family; + + string weight = _bold ? "bold" : "medium"; + string slant = _italic ? "i" : "r"; + string sizestr= _size ? itostring(_size * 10) : "*"; + + return "-*-" + _family + "-" + weight + "-" + slant + "-*-*-*-" + sizestr + + "-*-*-*-*-*-*"; +} + + +/* + * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD. + */ +string BFont::buildMultibyteXlfd(void) const { + string weight = _bold ? "bold" : "medium"; + string slant = _italic ? "i" : "r"; + string sizestr= _size ? itostring(_size) : "*"; + + return _family + ',' + + "-*-*-" + weight + "-" + slant + "-*-*-*-" + sizestr + + "-*-*-*-*-*-*" + ',' + + "-*-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*" + ',' + + + "*"; +} + + +/* + * Takes a full X font name and parses it out so we know if we're bold, our + * size, etc. + */ +bool BFont::parseXlfd(const string &xlfd) { + if (xlfd.empty() || xlfd[0] != '-') { + _family = xlfd; + _simplename = True; + _bold = False; + _italic = False; + _size = 0; + } else { + _simplename = False; + string weight, + slant, + sizestr; + int i = 0; + + string::const_iterator it = xlfd.begin(), end = xlfd.end(); + while(1) { + string::const_iterator tmp = it; // current string.begin() + it = std::find(tmp, end, '-'); // look for comma between tmp and end + if (i == 2) _family = string(tmp, it); // s[tmp:it] + if (i == 3) weight = string(tmp, it); + if (i == 4) slant = string(tmp, it); + if (i == 7 && string(tmp, it) != "*") sizestr = string(tmp, it); + if (sizestr.empty() && + i == 8 && string(tmp, it) != "*") sizestr = string(tmp, it); + if (it == end || i >= 8) + break; + ++it; + ++i; + } + if (i < 3) // no name even! can't parse that + return False; + _bold = weight == "bold" || weight == "demibold"; + _italic = slant == "i" || slant == "o"; + _size = atoi(sizestr.c_str()) / 10; + } + + // min/max size restrictions for sanity, but 0 is the font's "default size" + if (_size && _size < 3) + _size = 3; + else if (_size > 97) + _size = 97; + + return True; +} + + +void BFont::drawString(Drawable d, int x, int y, const BColor &color, + const string &string) const { + assert(_valid); + +#ifdef XFT + if (_xftfont) { + XftDraw *draw = XftDrawCreate(_display, d, _screen->getVisual(), + _screen->getColormap()); + assert(draw); + + if (_shadow) { + XftColor c; + c.color.red = 0; + c.color.green = 0; + c.color.blue = 0; + c.color.alpha = _tint | _tint << 8; // transparent shadow + c.pixel = BlackPixel(_display, _screen->getScreenNumber()); + +#ifdef XFT_UTF8 + XftDrawStringUtf8( +#else + XftDrawString8( +#endif + draw, &c, _xftfont, x + _offset, + _xftfont->ascent + y + _offset, (XftChar8 *) string.c_str(), + string.size()); + } + + 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 BColor yet + +#ifdef XFT_UTF8 + XftDrawStringUtf8( +#else + XftDrawString8( +#endif + draw, &c, _xftfont, x, _xftfont->ascent + y, + (XftChar8 *) string.c_str(), string.size()); + + XftDrawDestroy(draw); + return; + } +#endif // XFT + + BPen pen(color, _font); + + if (i18n.multibyte()) + XmbDrawString(_display, d, _fontset, pen.gc(), + x, y - _fontset_extents->max_ink_extent.y, + string.c_str(), string.size()); + else + XDrawString(_display, d, pen.gc(), + x, _font->ascent + y, + string.c_str(), string.size()); +} + + +unsigned int BFont::measureString(const string &string) const { + assert(_valid); + +#ifdef XFT + if (_xftfont) { + XGlyphInfo info; + +#ifdef XFT_UTF8 + XftTextExtentsUtf8( +#else + XftTextExtents8( +#endif + _display, _xftfont, (XftChar8 *) string.c_str(), + string.size(), &info); + + return info.xOff + (_shadow ? _offset : 0); + } +#endif // XFT + + if (i18n.multibyte()) { + XRectangle ink, logical; + XmbTextExtents(_fontset, string.c_str(), string.size(), &ink, &logical); + return logical.width; + } else { + return XTextWidth(_font, string.c_str(), string.size()); + } +} + + +unsigned int BFont::height(void) const { + assert(_valid); + +#ifdef XFT + if (_xftfont) + return _xftfont->height + (_shadow ? _offset : 0); +#endif // XFT + + if (i18n.multibyte()) + return _fontset_extents->max_ink_extent.height; + else + return _font->ascent + _font->descent; +} + + +unsigned int BFont::maxCharWidth(void) const { + assert(_valid); + +#ifdef XFT + if (_xftfont) + return _xftfont->max_advance_width; +#endif // XFT + + if (i18n.multibyte()) + return _fontset_extents->max_logical_extent.width; + else + return _font->max_bounds.rbearing - _font->min_bounds.lbearing; +} diff --git a/src/font.hh b/src/font.hh new file mode 100644 index 00000000..f28a0ac5 --- /dev/null +++ b/src/font.hh @@ -0,0 +1,124 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// Font.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Font_hh +#define __Font_hh + +extern "C" { +#include + +#ifdef XFT +# include +#endif +} + +#include + +#include + +class BGCCache; +class BGCCacheItem; +class BColor; + +#include "screen.hh" + +class BFont { + /* + * static members + */ +private: + static std::string _fallback_font; + +public: + // the fallback is only used for X fonts, not for Xft fonts, since it is + // assumed that X fonts will be the fallback from Xft. + inline static std::string fallbackFont(void) { return _fallback_font; } + inline static void setFallbackFont(const std::string &f) + { _fallback_font = f; } + + /* + * instance members + */ +private: + Display *_display; + BScreen *_screen; + + std::string _family; + bool _simplename; // true if not spec'd as a -*-* string + int _size; + bool _bold; + bool _italic; + +#ifdef XFT + bool _antialias; + bool _shadow; + unsigned char _offset; + unsigned char _tint; + + XftFont *_xftfont; + + bool createXftFont(void); +#endif + + // standard + XFontStruct *_font; + // multibyte + XFontSet _fontset; + XFontSetExtents *_fontset_extents; + + std::string buildXlfd(void) const; + std::string buildMultibyteXlfd(void) const; + + bool createXFont(const std::string &xlfd); + bool parseXlfd(const std::string &xlfd); + + bool _valid; + +public: +#ifdef XFT + // loads an Xft font + BFont(Display *d, BScreen *screen, const std::string &family, int size, + bool bold, bool italic, bool shadow, unsigned char offset, + unsigned char tint, bool antialias = True); +#endif + // loads a standard X font + BFont(Display *d, BScreen *screen, const std::string &xlfd); + virtual ~BFont(void); + + inline bool valid(void) const { return _valid; } + + inline std::string family(void) const { assert(_valid); return _family; } + inline int size(void) const { assert(_valid); return _size; } + inline bool bold(void) const { assert(_valid); return _bold; } + inline bool italic(void) const { assert(_valid); return _italic; } + + unsigned int height(void) const; + unsigned int maxCharWidth(void) const; + + unsigned int measureString(const std::string &string) const; + + void drawString(Drawable d, int x, int y, const BColor &color, + const std::string &string) const; +}; + +#endif // __Font_hh diff --git a/src/gccache.cc b/src/gccache.cc new file mode 100644 index 00000000..76bdfc37 --- /dev/null +++ b/src/gccache.cc @@ -0,0 +1,209 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// GCCache.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +} + +#include "gccache.hh" +#include "basedisplay.hh" +#include "color.hh" +#include "util.hh" + + +BGCCacheContext::~BGCCacheContext(void) { + if (gc) + XFreeGC(display->getXDisplay(), gc); +} + + +void BGCCacheContext::set(const BColor &_color, + const XFontStruct * const _font, + const int _function, const int _subwindow, + int _linewidth) { + XGCValues gcv; + pixel = gcv.foreground = _color.pixel(); + function = gcv.function = _function; + subwindow = gcv.subwindow_mode = _subwindow; + linewidth = gcv.line_width = _linewidth; + gcv.cap_style = CapProjecting; + + unsigned long mask = GCForeground | GCFunction | GCSubwindowMode | + GCLineWidth | GCCapStyle; + + if (_font) { + fontid = gcv.font = _font->fid; + mask |= GCFont; + } else { + fontid = 0; + } + + XChangeGC(display->getXDisplay(), gc, mask, &gcv); +} + + +void BGCCacheContext::set(const XFontStruct * const _font) { + if (! _font) { + fontid = 0; + return; + } + + XGCValues gcv; + fontid = gcv.font = _font->fid; + XChangeGC(display->getXDisplay(), gc, GCFont, &gcv); +} + + +BGCCache::BGCCache(const BaseDisplay * const _display, + unsigned int screen_count) + : display(_display), context_count(128u), + cache_size(16u), cache_buckets(8u * screen_count), + cache_total_size(cache_size * cache_buckets) { + + contexts = new BGCCacheContext*[context_count]; + unsigned int i; + for (i = 0; i < context_count; i++) { + contexts[i] = new BGCCacheContext(display); + } + + cache = new BGCCacheItem*[cache_total_size]; + for (i = 0; i < cache_total_size; ++i) { + cache[i] = new BGCCacheItem; + } +} + + +BGCCache::~BGCCache(void) { + std::for_each(contexts, contexts + context_count, PointerAssassin()); + std::for_each(cache, cache + cache_total_size, PointerAssassin()); + delete [] cache; + delete [] contexts; +} + + +BGCCacheContext *BGCCache::nextContext(unsigned int scr) { + Window hd = display->getScreenInfo(scr)->getRootWindow(); + + BGCCacheContext *c; + + for (unsigned int i = 0; i < context_count; ++i) { + c = contexts[i]; + + if (! c->gc) { + c->gc = XCreateGC(display->getXDisplay(), hd, 0, 0); + c->used = false; + c->screen = scr; + } + if (! c->used && c->screen == scr) + return c; + } + + fprintf(stderr, "BGCCache: context fault!\n"); + abort(); + return (BGCCacheContext*) 0; // not reached +} + + +void BGCCache::release(BGCCacheContext *ctx) { + ctx->used = false; +} + + +BGCCacheItem *BGCCache::find(const BColor &_color, + const XFontStruct * const _font, + int _function, int _subwindow, int _linewidth) { + const unsigned long pixel = _color.pixel(); + const unsigned int screen = _color.screen(); + const int key = _color.red() ^ _color.green() ^ _color.blue(); + int k = (key % cache_size) * cache_buckets; + unsigned int i = 0; // loop variable + BGCCacheItem *c = cache[ k ], *prev = 0; + + /* + this will either loop cache_buckets times then return/abort or + it will stop matching + */ + while (c->ctx && + (c->ctx->pixel != pixel || c->ctx->function != _function || + c->ctx->subwindow != _subwindow || c->ctx->screen != screen || + c->ctx->linewidth != _linewidth)) { + if (i < (cache_buckets - 1)) { + prev = c; + c = cache[ ++k ]; + ++i; + continue; + } + if (c->count == 0 && c->ctx->screen == screen) { + // use this cache item + c->ctx->set(_color, _font, _function, _subwindow, _linewidth); + c->ctx->used = true; + c->count = 1; + c->hits = 1; + return c; + } + // cache fault! + fprintf(stderr, "BGCCache: cache fault, count: %d, screen: %d, item screen: %d\n", c->count, screen, c->ctx->screen); + abort(); + } + + if (c->ctx) { + // reuse existing context + if (_font && _font->fid && _font->fid != c->ctx->fontid) + c->ctx->set(_font); + c->count++; + c->hits++; + if (prev && c->hits > prev->hits) { + cache[ k ] = prev; + cache[ k - 1 ] = c; + } + } else { + c->ctx = nextContext(screen); + c->ctx->set(_color, _font, _function, _subwindow, _linewidth); + c->ctx->used = true; + c->count = 1; + c->hits = 1; + } + + return c; +} + + +void BGCCache::release(BGCCacheItem *_item) { + _item->count--; +} + + +void BGCCache::purge(void) { + for (unsigned int i = 0; i < cache_total_size; ++i) { + BGCCacheItem *d = cache[ i ]; + + if (d->ctx && d->count == 0) { + release(d->ctx); + d->ctx = 0; + } + } +} diff --git a/src/gccache.hh b/src/gccache.hh new file mode 100644 index 00000000..b81cdfd9 --- /dev/null +++ b/src/gccache.hh @@ -0,0 +1,141 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// GCCache.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef GCCACHE_HH +#define GCCACHE_HH + +extern "C" { +#include +} + +#include "basedisplay.hh" +#include "color.hh" + +class BGCCacheItem; + +class BGCCacheContext { +public: + void set(const BColor &_color, const XFontStruct * const _font, + const int _function, const int _subwindow, const int _linewidth); + void set(const XFontStruct * const _font); + + ~BGCCacheContext(void); + +private: + BGCCacheContext(const BaseDisplay * const _display) + : display(_display), gc(0), pixel(0ul), fontid(0ul), + function(0), subwindow(0), used(false), screen(~(0u)), linewidth(0) {} + + const BaseDisplay *display; + GC gc; + unsigned long pixel; + unsigned long fontid; + int function; + int subwindow; + bool used; + unsigned int screen; + int linewidth; + + BGCCacheContext(const BGCCacheContext &_nocopy); + BGCCacheContext &operator=(const BGCCacheContext &_nocopy); + + friend class BGCCache; + friend class BGCCacheItem; +}; + +class BGCCacheItem { +public: + inline const GC &gc(void) const { return ctx->gc; } + +private: + BGCCacheItem(void) : ctx(0), count(0), hits(0), fault(false) { } + + BGCCacheContext *ctx; + unsigned int count; + unsigned int hits; + bool fault; + + BGCCacheItem(const BGCCacheItem &_nocopy); + BGCCacheItem &operator=(const BGCCacheItem &_nocopy); + + friend class BGCCache; +}; + +class BGCCache { +public: + BGCCache(const BaseDisplay * const _display, unsigned int screen_count); + ~BGCCache(void); + + // cleans up the cache + void purge(void); + + BGCCacheItem *find(const BColor &_color, const XFontStruct * const _font = 0, + int _function = GXcopy, int _subwindow = ClipByChildren, + int _linewidth = 0); + void release(BGCCacheItem *_item); + +private: + BGCCacheContext *nextContext(unsigned int _screen); + void release(BGCCacheContext *ctx); + + // this is closely modelled after the Qt GC cache, but with some of the + // complexity stripped out + const BaseDisplay *display; + + const unsigned int context_count; + const unsigned int cache_size; + const unsigned int cache_buckets; + const unsigned int cache_total_size; + BGCCacheContext **contexts; + BGCCacheItem **cache; +}; + +class BPen { +public: + inline BPen(const BColor &_color, const XFontStruct * const _font = 0, + int _linewidth = 0, int _function = GXcopy, + int _subwindow = ClipByChildren) + : color(_color), font(_font), linewidth(_linewidth), function(_function), + subwindow(_subwindow), cache(_color.display()->gcCache()), item(0) { } + + inline ~BPen(void) { if (item) cache->release(item); } + + inline const GC &gc(void) const { + if (! item) item = cache->find(color, font, function, subwindow, + linewidth); + return item->gc(); + } + +private: + const BColor &color; + const XFontStruct *font; + int linewidth; + int function; + int subwindow; + + mutable BGCCache *cache; + mutable BGCCacheItem *item; +}; + + +#endif // GCCACHE_HH diff --git a/src/i18n.cc b/src/i18n.cc deleted file mode 100644 index 0eb0a911..00000000 --- a/src/i18n.cc +++ /dev/null @@ -1,119 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -// i18n.cc for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - -extern "C" { -#include - -#ifdef HAVE_STDLIB_H -# include -#endif // HAVE_STDLIB_H - -#ifdef HAVE_STRING_H -# include -#endif // HAVE_STRING_H - -#ifdef HAVE_STDIO_H -# include -#endif // HAVE_STDIO_H - -#ifdef HAVE_LOCALE_H -# include -#endif // HAVE_LOCALE_H -} - -#include -using std::string; - -#include "i18n.hh" - - -// the rest of bb source uses True and False from X, so we continue that -#define True true -#define False false - -I18n::I18n(void) { - mb = False; -#ifdef HAVE_SETLOCALE - locale = setlocale(LC_ALL, ""); - if (! locale) { - fprintf(stderr, "failed to set locale, reverting to \"C\"\n"); -#endif // HAVE_SETLOCALE - locale = "C"; -#ifdef HAVE_SETLOCALE - } else { - // MB_CUR_MAX returns the size of a char in the current locale - if (MB_CUR_MAX > 1) - mb = True; - // truncate any encoding off the end of the locale - char *l = strchr(locale, '@'); - if (l) *l = '\0'; - l = strchr(locale, '.'); - if (l) *l = '\0'; - } - -#ifdef HAVE_CATOPEN - catalog_fd = (nl_catd) -1; -#endif -#endif // HAVE_SETLOCALE -} - - -I18n::~I18n(void) { -#if defined(NLS) && defined(HAVE_CATCLOSE) - if (catalog_fd != (nl_catd) -1) - catclose(catalog_fd); -#endif // HAVE_CATCLOSE -} - - -void I18n::openCatalog(const char *catalog) { -#if defined(NLS) && defined(HAVE_CATOPEN) - string catalog_filename = LOCALEPATH; - catalog_filename += '/'; - catalog_filename += locale; - catalog_filename += '/'; - catalog_filename += catalog; - -# ifdef MCLoadBySet - catalog_fd = catopen(catalog_filename.c_str(), MCLoadBySet); -# else // !MCLoadBySet - catalog_fd = catopen(catalog_filename.c_str(), NL_CAT_LOCALE); -# endif // MCLoadBySet - - if (catalog_fd == (nl_catd) -1) - fprintf(stderr, "failed to open catalog, using default messages\n"); -#endif // HAVE_CATOPEN -} - -const char* I18n::operator()(int set, int msg, const char *msgString) const { -#if defined(NLS) && defined(HAVE_CATGETS) - if (catalog_fd != (nl_catd) -1) - return catgets(catalog_fd, set, msg, msgString); - else -#endif - return msgString; -} diff --git a/src/i18n.hh b/src/i18n.hh deleted file mode 100644 index b86d9d80..00000000 --- a/src/i18n.hh +++ /dev/null @@ -1,63 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; -*- -// i18n.hh for Blackbox - an X11 Window manager -// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry -// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -#ifndef __i18n_h -#define __i18n_h - -// always include this just for the #defines -// this keeps the calls to i18n->getMessage clean, otherwise we have to -// add ifdefs to every call to getMessage -#include "../nls/blackbox-nls.hh" - -extern "C" { -#ifdef HAVE_LOCALE_H -# include -#endif // HAVE_LOCALE_H - -#ifdef HAVE_NL_TYPES_H -# include -#endif // HAVE_NL_TYPES_H -} - - -class I18n { -private: - char *locale; - bool mb; -#ifdef HAVE_NL_TYPES_H - nl_catd catalog_fd; -#endif - -public: - I18n(void); - ~I18n(void); - - inline bool multibyte(void) const { return mb; } - - const char* operator()(int set, int msg, const char *msgString) const; - void openCatalog(const char *catalog); -}; - -extern I18n i18n; - -#endif // __i18n_h diff --git a/src/image.cc b/src/image.cc new file mode 100644 index 00000000..11fcd1d7 --- /dev/null +++ b/src/image.cc @@ -0,0 +1,1702 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// Image.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#include +using std::max; +using std::min; + +#include "blackbox.hh" +#include "basedisplay.hh" +#include "gccache.hh" +#include "image.hh" +#include "texture.hh" + + +BImage::BImage(BImageControl *c, int w, int h) { + control = c; + + width = (w > 0) ? w : 1; + height = (h > 0) ? h : 1; + + red = new unsigned char[width * height]; + green = new unsigned char[width * height]; + blue = new unsigned char[width * height]; + + xtable = ytable = (unsigned int *) 0; + + cpc = control->getColorsPerChannel(); + cpccpc = cpc * cpc; + + control->getColorTables(&red_table, &green_table, &blue_table, + &red_offset, &green_offset, &blue_offset, + &red_bits, &green_bits, &blue_bits); + + if (control->getVisual()->c_class != TrueColor) + control->getXColorTable(&colors, &ncolors); +} + + +BImage::~BImage(void) { + delete [] red; + delete [] green; + delete [] blue; +} + + +Pixmap BImage::render(const BTexture &texture) { + if (texture.texture() & BTexture::Parent_Relative) + return ParentRelative; + else if (texture.texture() & BTexture::Solid) + return render_solid(texture); + else if (texture.texture() & BTexture::Gradient) + return render_gradient(texture); + return None; +} + + +Pixmap BImage::render_solid(const BTexture &texture) { + Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(), + control->getDrawable(), width, + height, control->getDepth()); + if (pixmap == None) { + fprintf(stderr, i18n(ImageSet, ImageErrorCreatingSolidPixmap, + "BImage::render_solid: error creating pixmap\n")); + return None; + } + + Display *display = control->getBaseDisplay()->getXDisplay(); + + BPen pen(texture.color()); + BPen penlight(texture.lightColor()); + BPen penshadow(texture.shadowColor()); + + XFillRectangle(display, pixmap, pen.gc(), 0, 0, width, height); + + if (texture.texture() & BTexture::Interlaced) { + BPen peninterlace(texture.colorTo()); + for (unsigned int i = 0; i < height; i += 2) + XDrawLine(display, pixmap, peninterlace.gc(), 0, i, width, i); + } + + int left = 0, top = 0, right = width - 1, bottom = height - 1; + + if (texture.texture() & BTexture::Border) { + BPen penborder(texture.borderColor()); + XDrawRectangle(display, pixmap, penborder.gc(), + left, top, right, bottom); + } + + if (texture.texture() & BTexture::Bevel1) { + if (texture.texture() & BTexture::Raised) { + XDrawLine(display, pixmap, penshadow.gc(), + left, bottom, right, bottom); + XDrawLine(display, pixmap, penshadow.gc(), + right, bottom, right, top); + + XDrawLine(display, pixmap, penlight.gc(), + left, top, right, top); + XDrawLine(display, pixmap, penlight.gc(), + left, bottom, left, top); + } else if (texture.texture() & BTexture::Sunken) { + XDrawLine(display, pixmap, penlight.gc(), + left, bottom, right, bottom); + XDrawLine(display, pixmap, penlight.gc(), + right, bottom, right, top); + + XDrawLine(display, pixmap, penshadow.gc(), + left, top, right, top); + XDrawLine(display, pixmap, penshadow.gc(), + left, bottom, left, top); + } + } else if (texture.texture() & BTexture::Bevel2) { + if (texture.texture() & BTexture::Raised) { + XDrawLine(display, pixmap, penshadow.gc(), + left + 1, bottom - 2, right - 2, bottom - 2); + XDrawLine(display, pixmap, penshadow.gc(), + right - 2, bottom - 2, right - 2, top + 1); + + XDrawLine(display, pixmap, penlight.gc(), + left + 1, top + 1, right - 2, top + 1); + XDrawLine(display, pixmap, penlight.gc(), + left + 1, bottom - 2, left + 1, top + 1); + } else if (texture.texture() & BTexture::Sunken) { + XDrawLine(display, pixmap, penlight.gc(), + left + 1, bottom - 2, right - 2, bottom - 2); + XDrawLine(display, pixmap, penlight.gc(), + right - 2, bottom - 2, right - 2, top + 1); + + XDrawLine(display, pixmap, penshadow.gc(), + left + 1, top + 1, right - 2, top + 1); + XDrawLine(display, pixmap, penshadow.gc(), + left + 1, bottom - 2, left + 1, top + 1); + } + } + + return pixmap; +} + + +Pixmap BImage::render_gradient(const BTexture &texture) { + bool inverted = False; + + interlaced = texture.texture() & BTexture::Interlaced; + + if (texture.texture() & BTexture::Sunken) { + from = texture.colorTo(); + to = texture.color(); + + if (! (texture.texture() & BTexture::Invert)) inverted = True; + } else { + from = texture.color(); + to = texture.colorTo(); + + if (texture.texture() & BTexture::Invert) inverted = True; + } + + control->getGradientBuffers(width, height, &xtable, &ytable); + + if (texture.texture() & BTexture::Diagonal) dgradient(); + else if (texture.texture() & BTexture::Elliptic) egradient(); + else if (texture.texture() & BTexture::Horizontal) hgradient(); + else if (texture.texture() & BTexture::Pyramid) pgradient(); + else if (texture.texture() & BTexture::Rectangle) rgradient(); + else if (texture.texture() & BTexture::Vertical) vgradient(); + else if (texture.texture() & BTexture::CrossDiagonal) cdgradient(); + else if (texture.texture() & BTexture::PipeCross) pcgradient(); + + if (texture.texture() & BTexture::Bevel1) bevel1(); + else if (texture.texture() & BTexture::Bevel2) bevel2(); + + if (texture.texture() & BTexture::Border) border(texture); + + if (inverted) invert(); + + return renderPixmap(); + +} + + +static const unsigned char dither4[4][4] = { + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2} +}; + + +/* + * Helper function for TrueColorDither and renderXImage + * + * This handles the proper setting of the image data based on the image depth + * and the machine's byte ordering + */ +static inline +void assignPixelData(unsigned int bit_depth, unsigned char **data, + unsigned long pixel) { + unsigned char *pixel_data = *data; + switch (bit_depth) { + case 8: // 8bpp + *pixel_data++ = pixel; + break; + + case 16: // 16bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + break; + + case 17: // 16bpp MSB + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 24: // 24bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + break; + + case 25: // 24bpp MSB + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + + case 32: // 32bpp LSB + *pixel_data++ = pixel; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 24; + break; + + case 33: // 32bpp MSB + *pixel_data++ = pixel >> 24; + *pixel_data++ = pixel >> 16; + *pixel_data++ = pixel >> 8; + *pixel_data++ = pixel; + break; + } + *data = pixel_data; // assign back so we don't lose our place +} + + +// algorithm: ordered dithering... many many thanks to rasterman +// (raster@rasterman.com) for telling me about this... portions of this +// code is based off of his code in Imlib +void BImage::TrueColorDither(unsigned int bit_depth, int bytes_per_line, + unsigned char *pixel_data) { + unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset; + unsigned char *ppixel_data = pixel_data; + unsigned long pixel; + + for (y = 0, offset = 0; y < height; y++) { + dithy = y & 0x3; + + for (x = 0; x < width; x++, offset++) { + dithx = x & 0x3; + r = red[offset]; + g = green[offset]; + b = blue[offset]; + + er = r & (red_bits - 1); + eg = g & (green_bits - 1); + eb = b & (blue_bits - 1); + + r = red_table[r]; + g = green_table[g]; + b = blue_table[b]; + + if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++; + if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++; + if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++; + + pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); + assignPixelData(bit_depth, &pixel_data, pixel); + } + + pixel_data = (ppixel_data += bytes_per_line); + } +} + +#ifdef ORDEREDPSEUDO +const static unsigned char dither8[8][8] = { + { 0, 32, 8, 40, 2, 34, 10, 42}, + { 48, 16, 56, 24, 50, 18, 58, 26}, + { 12, 44, 4, 36, 14, 46, 6, 38}, + { 60, 28, 52, 20, 62, 30, 54, 22}, + { 3, 35, 11, 43, 1, 33, 9, 41}, + { 51, 19, 59, 27, 49, 17, 57, 25}, + { 15, 47, 7, 39, 13, 45, 5, 37}, + { 63, 31, 55, 23, 61, 29, 53, 21} +}; + +void BImage::OrderedPseudoColorDither(int bytes_per_line, + unsigned char *pixel_data) { + unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset; + unsigned long pixel; + unsigned char *ppixel_data = pixel_data; + + for (y = 0, offset = 0; y < height; y++) { + dithy = y & 7; + + for (x = 0; x < width; x++, offset++) { + dithx = x & 7; + + r = red[offset]; + g = green[offset]; + b = blue[offset]; + + er = r & (red_bits - 1); + eg = g & (green_bits - 1); + eb = b & (blue_bits - 1); + + r = red_table[r]; + g = green_table[g]; + b = blue_table[b]; + + if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++; + if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++; + if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++; + + pixel = (r * cpccpc) + (g * cpc) + b; + *(pixel_data++) = colors[pixel].pixel; + } + + pixel_data = (ppixel_data += bytes_per_line); + } +} +#endif + +void BImage::PseudoColorDither(int bytes_per_line, unsigned char *pixel_data) { + short *terr, + *rerr = new short[width + 2], + *gerr = new short[width + 2], + *berr = new short[width + 2], + *nrerr = new short[width + 2], + *ngerr = new short[width + 2], + *nberr = new short[width + 2]; + + int rr, gg, bb, rer, ger, ber; + int dd = 255 / control->getColorsPerChannel(); + unsigned int x, y, r, g, b, offset; + unsigned long pixel; + unsigned char *ppixel_data = pixel_data; + + for (x = 0; x < width; x++) { + *(rerr + x) = *(red + x); + *(gerr + x) = *(green + x); + *(berr + x) = *(blue + x); + } + + *(rerr + x) = *(gerr + x) = *(berr + x) = 0; + + for (y = 0, offset = 0; y < height; y++) { + if (y < (height - 1)) { + int i = offset + width; + for (x = 0; x < width; x++, i++) { + *(nrerr + x) = *(red + i); + *(ngerr + x) = *(green + i); + *(nberr + x) = *(blue + i); + } + + *(nrerr + x) = *(red + (--i)); + *(ngerr + x) = *(green + i); + *(nberr + x) = *(blue + i); + } + + for (x = 0; x < width; x++) { + rr = rerr[x]; + gg = gerr[x]; + bb = berr[x]; + + if (rr > 255) rr = 255; else if (rr < 0) rr = 0; + if (gg > 255) gg = 255; else if (gg < 0) gg = 0; + if (bb > 255) bb = 255; else if (bb < 0) bb = 0; + + r = red_table[rr]; + g = green_table[gg]; + b = blue_table[bb]; + + rer = rerr[x] - r*dd; + ger = gerr[x] - g*dd; + ber = berr[x] - b*dd; + + pixel = (r * cpccpc) + (g * cpc) + b; + *pixel_data++ = colors[pixel].pixel; + + r = rer >> 1; + g = ger >> 1; + b = ber >> 1; + rerr[x+1] += r; + gerr[x+1] += g; + berr[x+1] += b; + nrerr[x] += r; + ngerr[x] += g; + nberr[x] += b; + } + + offset += width; + + pixel_data = (ppixel_data += bytes_per_line); + + terr = rerr; + rerr = nrerr; + nrerr = terr; + + terr = gerr; + gerr = ngerr; + ngerr = terr; + + terr = berr; + berr = nberr; + nberr = terr; + } + + delete [] rerr; + delete [] gerr; + delete [] berr; + delete [] nrerr; + delete [] ngerr; + delete [] nberr; +} + +XImage *BImage::renderXImage(void) { + XImage *image = + XCreateImage(control->getBaseDisplay()->getXDisplay(), + control->getVisual(), control->getDepth(), ZPixmap, 0, 0, + width, height, 32, 0); + + if (! image) { + fprintf(stderr, i18n(ImageSet, ImageErrorCreatingXImage, + "BImage::renderXImage: error creating XImage\n")); + return (XImage *) 0; + } + + // insurance policy + image->data = (char *) 0; + + unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)]; + + unsigned int o = image->bits_per_pixel + + ((image->byte_order == MSBFirst) ? 1 : 0); + + bool unsupported = False; + + if (control->doDither() && width > 1 && height > 1) { + switch (control->getVisual()->c_class) { + case TrueColor: + TrueColorDither(o, image->bytes_per_line, d); + break; + + case StaticColor: + case PseudoColor: { +#ifdef ORDEREDPSEUDO + OrderedPseudoColorDither(image->bytes_per_line, d); +#else + PseudoColorDither(image->bytes_per_line, d); +#endif + break; + } + + default: + unsupported = True; + } + } else { + unsigned int x, y, r, g, b, offset; + unsigned char *pixel_data = d, *ppixel_data = d; + unsigned long pixel; + + switch (control->getVisual()->c_class) { + case StaticColor: + case PseudoColor: + for (y = 0, offset = 0; y < height; ++y) { + for (x = 0; x < width; ++x, ++offset) { + r = red_table[red[offset]]; + g = green_table[green[offset]]; + b = blue_table[blue[offset]]; + + pixel = (r * cpccpc) + (g * cpc) + b; + *pixel_data++ = colors[pixel].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case TrueColor: + for (y = 0, offset = 0; y < height; y++) { + for (x = 0; x < width; x++, offset++) { + r = red_table[red[offset]]; + g = green_table[green[offset]]; + b = blue_table[blue[offset]]; + + pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset); + assignPixelData(o, &pixel_data, pixel); + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case StaticGray: + case GrayScale: + for (y = 0, offset = 0; y < height; y++) { + for (x = 0; x < width; x++, offset++) { + r = *(red_table + *(red + offset)); + g = *(green_table + *(green + offset)); + b = *(blue_table + *(blue + offset)); + + g = ((r * 30) + (g * 59) + (b * 11)) / 100; + *pixel_data++ = colors[g].pixel; + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + default: + unsupported = True; + } + } + + if (unsupported) { + fprintf(stderr, i18n(ImageSet, ImageUnsupVisual, + "BImage::renderXImage: unsupported visual\n")); + delete [] d; + XDestroyImage(image); + return (XImage *) 0; + } + + image->data = (char *) d; + + return image; +} + + +Pixmap BImage::renderPixmap(void) { + Pixmap pixmap = + XCreatePixmap(control->getBaseDisplay()->getXDisplay(), + control->getDrawable(), width, height, control->getDepth()); + + if (pixmap == None) { + fprintf(stderr, i18n(ImageSet, ImageErrorCreatingPixmap, + "BImage::renderPixmap: error creating pixmap\n")); + return None; + } + + XImage *image = renderXImage(); + + if (! image) { + XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); + return None; + } + + if (! image->data) { + XDestroyImage(image); + XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); + return None; + } + + XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap, + DefaultGC(control->getBaseDisplay()->getXDisplay(), + control->getScreenInfo()->getScreenNumber()), + image, 0, 0, 0, 0, width, height); + + if (image->data) { + delete [] image->data; + image->data = NULL; + } + + XDestroyImage(image); + + return pixmap; +} + + +void BImage::bevel1(void) { + if (width > 2 && height > 2) { + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned char r, g, b, rr ,gg ,bb; + register unsigned int w = width, h = height - 1, wh = w * h; + + while (--w) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *((pr++) + wh) = rr; + *((pg++) + wh) = gg; + *((pb++) + wh) = bb; + } + + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr + wh) = rr; + *(pg + wh) = gg; + *(pb + wh) = bb; + + pr = red + width; + pg = green + width; + pb = blue + width; + + while (--h) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + pr += width - 1; + pg += width - 1; + pb += width - 1; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr++) = rr; + *(pg++) = gg; + *(pb++) = bb; + } + + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + pr += width - 1; + pg += width - 1; + pb += width - 1; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *pr = rr; + *pg = gg; + *pb = bb; + } +} + + +void BImage::bevel2(void) { + if (width > 4 && height > 4) { + unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1, + *pg = green + width + 1, *pb = blue + width + 1; + unsigned int w = width - 2, h = height - 1, wh = width * (height - 3); + + while (--w) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *pr = rr; + *pg = gg; + *pb = bb; + + r = *(pr + wh); + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *(pg + wh); + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *(pb + wh); + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *((pr++) + wh) = rr; + *((pg++) + wh) = gg; + *((pb++) + wh) = bb; + } + + pr = red + width; + pg = green + width; + pb = blue + width; + + while (--h) { + r = *pr; + rr = r + (r >> 1); + if (rr < r) rr = ~0; + g = *pg; + gg = g + (g >> 1); + if (gg < g) gg = ~0; + b = *pb; + bb = b + (b >> 1); + if (bb < b) bb = ~0; + + *(++pr) = rr; + *(++pg) = gg; + *(++pb) = bb; + + pr += width - 3; + pg += width - 3; + pb += width - 3; + + r = *pr; + rr = (r >> 2) + (r >> 1); + if (rr > r) rr = 0; + g = *pg; + gg = (g >> 2) + (g >> 1); + if (gg > g) gg = 0; + b = *pb; + bb = (b >> 2) + (b >> 1); + if (bb > b) bb = 0; + + *(pr++) = rr; + *(pg++) = gg; + *(pb++) = bb; + + pr++; pg++; pb++; + } + } +} + + +void BImage::border(const BTexture &texture) { + if (width < 2 || height < 2) return; + + register unsigned int i; + int r = texture.borderColor().red(), + g = texture.borderColor().green(), + b = texture.borderColor().blue(); + + unsigned char *pr, *pg, *pb; + + // top line + pr = red; + pg = green; + pb = blue; + for (i = 0; i < width; ++i) { + *pr++ = r; + *pg++ = g; + *pb++ = b; + } + + if (height > 2) { + // left and right lines (pr,pg,pb are already lined up) + for (i = 1; i < height - 1; ++i) { + *pr = r; + *pg = g; + *pb = b; + pr += width - 1; + pg += width - 1; + pb += width - 1; + *pr++ = r; + *pg++ = g; + *pb++ = b; + } + } + + // bottom line (pr,pg,pb are already lined up) + for (i = 0; i < width; ++i) { + *pr++ = r; + *pg++ = g; + *pb++ = b; + } +} + + +void BImage::invert(void) { + register unsigned int i, j, wh = (width * height) - 1; + unsigned char tmp; + + for (i = 0, j = wh; j > i; j--, i++) { + tmp = *(red + j); + *(red + j) = *(red + i); + *(red + i) = tmp; + + tmp = *(green + j); + *(green + j) = *(green + i); + *(green + i) = tmp; + + tmp = *(blue + j); + *(blue + j) = *(blue + i); + *(blue + i) = tmp; + } +} + + +void BImage::dgradient(void) { + // diagonal gradient code was written by Mike Cole + // modified for interlacing by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, + xr = (float) from.red(), + xg = (float) from.green(), + xb = (float) from.blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + // Create X table + drx /= w; + dgx /= w; + dbx /= w; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) (xr); + *(xt++) = (unsigned char) (xg); + *(xt++) = (unsigned char) (xb); + + xr += drx; + xg += dgx; + xb += dbx; + } + + // Create Y table + dry /= h; + dgy /= h; + dby /= h; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) yr); + *(yt++) = ((unsigned char) yg); + *(yt++) = ((unsigned char) yb); + + yr += dry; + yg += dgy; + yb += dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal dgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = *(xt++) + *(yt); + *(pg++) = *(xt++) + *(yt + 1); + *(pb++) = *(xt++) + *(yt + 2); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = *(xt++) + *(yt); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = *(xt++) + *(yt); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} + + +void BImage::hgradient(void) { + float drx, dgx, dbx, + xr = (float) from.red(), + xg = (float) from.green(), + xb = (float) from.blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int x, y; + + drx = (float) (to.red() - from.red()); + dgx = (float) (to.green() - from.green()); + dbx = (float) (to.blue() - from.blue()); + + drx /= width; + dgx /= width; + dbx /= width; + + if (interlaced && height > 2) { + // faked interlacing effect + unsigned char channel, channel2; + + for (x = 0; x < width; x++, pr++, pg++, pb++) { + channel = (unsigned char) xr; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pr = channel2; + + channel = (unsigned char) xg; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pg = channel2; + + channel = (unsigned char) xb; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *pb = channel2; + + + channel = (unsigned char) xr; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr + width) = channel2; + + channel = (unsigned char) xg; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg + width) = channel2; + + channel = (unsigned char) xb; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb + width) = channel2; + + xr += drx; + xg += dgx; + xb += dbx; + } + + pr += width; + pg += width; + pb += width; + + int offset; + + for (y = 2; y < height; y++, pr += width, pg += width, pb += width) { + if (y & 1) offset = width; else offset = 0; + + memcpy(pr, (red + offset), width); + memcpy(pg, (green + offset), width); + memcpy(pb, (blue + offset), width); + } + } else { + // normal hgradient + for (x = 0; x < width; x++) { + *(pr++) = (unsigned char) (xr); + *(pg++) = (unsigned char) (xg); + *(pb++) = (unsigned char) (xb); + + xr += drx; + xg += dgx; + xb += dbx; + } + + for (y = 1; y < height; y++, pr += width, pg += width, pb += width) { + memcpy(pr, red, width); + memcpy(pg, green, width); + memcpy(pb, blue, width); + } + } +} + + +void BImage::vgradient(void) { + float dry, dgy, dby, + yr = (float) from.red(), + yg = (float) from.green(), + yb = (float) from.blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int y; + + dry = (float) (to.red() - from.red()); + dgy = (float) (to.green() - from.green()); + dby = (float) (to.blue() - from.blue()); + + dry /= height; + dgy /= height; + dby /= height; + + if (interlaced) { + // faked interlacing effect + unsigned char channel, channel2; + + for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { + if (y & 1) { + channel = (unsigned char) yr; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pr, channel2, width); + + channel = (unsigned char) yg; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pg, channel2, width); + + channel = (unsigned char) yb; + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + memset(pb, channel2, width); + } else { + channel = (unsigned char) yr; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pr, channel2, width); + + channel = (unsigned char) yg; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pg, channel2, width); + + channel = (unsigned char) yb; + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + memset(pb, channel2, width); + } + + yr += dry; + yg += dgy; + yb += dby; + } + } else { + // normal vgradient + for (y = 0; y < height; y++, pr += width, pg += width, pb += width) { + memset(pr, (unsigned char) yr, width); + memset(pg, (unsigned char) yg, width); + memset(pb, (unsigned char) yb, width); + + yr += dry; + yg += dgy; + yb += dby; + } + } +} + + +void BImage::pgradient(void) { + // pyramid gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, + xr, xg, xb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int tr = to.red(), tg = to.green(), tb = to.blue(), + *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + rsign = (drx < 0) ? -1 : 1; + gsign = (dgx < 0) ? -1 : 1; + bsign = (dbx < 0) ? -1 : 1; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal pgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} + + +void BImage::rgradient(void) { + // rectangle gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int tr = to.red(), tg = to.green(), tb = to.blue(), + *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + rsign = (drx < 0) ? -2 : 2; + gsign = (dgx < 0) ? -2 : 2; + bsign = (dbx < 0) ? -2 : 2; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal rgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} + + +void BImage::egradient(void) { + // elliptic gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int *xt = xtable, *yt = ytable, + tr = (unsigned long) to.red(), + tg = (unsigned long) to.green(), + tb = (unsigned long) to.blue(); + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + rsign = (drx < 0) ? -1 : 1; + gsign = (dgx < 0) ? -1 : 1; + bsign = (dbx < 0) ? -1 : 1; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned long) (xr * xr); + *(xt++) = (unsigned long) (xg * xg); + *(xt++) = (unsigned long) (xb * xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = (unsigned long) (yr * yr); + *(yt++) = (unsigned long) (yg * yg); + *(yt++) = (unsigned long) (yb * yb); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal egradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) + (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); + *(pg++) = (unsigned char) + (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); + *(pb++) = (unsigned char) + (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) + (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) + (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) + (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) + (tr - (rsign * control->getSqrt(*(xt++) + *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) + (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) + (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} + + +void BImage::pcgradient(void) { + // pipe cross gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb; + int rsign, gsign, bsign; + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int *xt = xtable, *yt = ytable, + tr = to.red(), + tg = to.green(), + tb = to.blue(); + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + rsign = (drx < 0) ? -2 : 2; + gsign = (dgx < 0) ? -2 : 2; + bsign = (dbx < 0) ? -2 : 2; + + xr = yr = (drx / 2); + xg = yg = (dgx / 2); + xb = yb = (dbx / 2); + + // Create X table + drx /= width; + dgx /= width; + dbx /= width; + + for (x = 0; x < width; x++) { + *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr); + *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg); + *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb); + + xr -= drx; + xg -= dgx; + xb -= dbx; + } + + // Create Y table + dry /= height; + dgy /= height; + dby /= height; + + for (y = 0; y < height; y++) { + *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr)); + *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg)); + *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb)); + + yr -= dry; + yg -= dgy; + yb -= dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal pcgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); + *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); + *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2)))); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2)))); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} + + +void BImage::cdgradient(void) { + // cross diagonal gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Blackbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, + xr = (float) from.red(), + xg = (float) from.green(), + xb = (float) from.blue(); + unsigned char *pr = red, *pg = green, *pb = blue; + unsigned int w = width * 2, h = height * 2, *xt, *yt; + + register unsigned int x, y; + + dry = drx = (float) (to.red() - from.red()); + dgy = dgx = (float) (to.green() - from.green()); + dby = dbx = (float) (to.blue() - from.blue()); + + // Create X table + drx /= w; + dgx /= w; + dbx /= w; + + for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) { + *(xt--) = (unsigned char) xb; + *(xt--) = (unsigned char) xg; + *(xt--) = (unsigned char) xr; + + xr += drx; + xg += dgx; + xb += dbx; + } + + // Create Y table + dry /= h; + dgy /= h; + dby /= h; + + for (yt = ytable, y = 0; y < height; y++) { + *(yt++) = (unsigned char) yr; + *(yt++) = (unsigned char) yg; + *(yt++) = (unsigned char) yb; + + yr += dry; + yg += dgy; + yb += dby; + } + + // Combine tables to create gradient + + if (! interlaced) { + // normal cdgradient + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + *(pr++) = *(xt++) + *(yt); + *(pg++) = *(xt++) + *(yt + 1); + *(pb++) = *(xt++) + *(yt + 2); + } + } + } else { + // faked interlacing effect + unsigned char channel, channel2; + + for (yt = ytable, y = 0; y < height; y++, yt += 3) { + for (xt = xtable, x = 0; x < width; x++) { + if (y & 1) { + channel = *(xt++) + *(yt); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = (channel >> 1) + (channel >> 2); + if (channel2 > channel) channel2 = 0; + *(pb++) = channel2; + } else { + channel = *(xt++) + *(yt); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pr++) = channel2; + + channel = *(xt++) + *(yt + 1); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pg++) = channel2; + + channel = *(xt++) + *(yt + 2); + channel2 = channel + (channel >> 3); + if (channel2 < channel) channel2 = ~0; + *(pb++) = channel2; + } + } + } + } +} diff --git a/src/image.hh b/src/image.hh new file mode 100644 index 00000000..3482b065 --- /dev/null +++ b/src/image.hh @@ -0,0 +1,168 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// Image.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Image_hh +#define __Image_hh + +extern "C" { +#include +#include +} + +#include + +#include "timer.hh" +#include "basedisplay.hh" +#include "color.hh" + +class BImageControl; +class BTexture; + +class BImage { +private: + BImageControl *control; + bool interlaced; + XColor *colors; + + BColor from, to; + int red_offset, green_offset, blue_offset, red_bits, green_bits, blue_bits, + ncolors, cpc, cpccpc; + unsigned char *red, *green, *blue, *red_table, *green_table, *blue_table; + unsigned int width, height, *xtable, *ytable; + + void TrueColorDither(unsigned int bit_depth, int bytes_per_line, + unsigned char *pixel_data); + void PseudoColorDither(int bytes_per_line, unsigned char *pixel_data); +#ifdef ORDEREDPSEUDO + void OrderedPseudoColorDither(int bytes_per_line, unsigned char *pixel_data); +#endif + + Pixmap renderPixmap(void); + Pixmap render_solid(const BTexture &texture); + Pixmap render_gradient(const BTexture &texture); + + XImage *renderXImage(void); + + void invert(void); + void bevel1(void); + void bevel2(void); + void border(const BTexture &texture); + void dgradient(void); + void egradient(void); + void hgradient(void); + void pgradient(void); + void rgradient(void); + void vgradient(void); + void cdgradient(void); + void pcgradient(void); + + +public: + BImage(BImageControl *c, int w, int h); + ~BImage(void); + + Pixmap render(const BTexture &texture); +}; + + +class BImageControl : public TimeoutHandler { +public: + struct CachedImage { + Pixmap pixmap; + + unsigned int count, width, height; + unsigned long pixel1, pixel2, texture; + }; + + BImageControl(BaseDisplay *dpy, const ScreenInfo *scrn, + bool _dither= False, int _cpc = 4, + unsigned long cache_timeout = 300000l, + unsigned long cmax = 200l); + virtual ~BImageControl(void); + + inline BaseDisplay *getBaseDisplay(void) const { return basedisplay; } + + inline bool doDither(void) { return dither; } + + inline const ScreenInfo *getScreenInfo(void) { return screeninfo; } + + inline Window getDrawable(void) const { return window; } + + inline Visual *getVisual(void) { return screeninfo->getVisual(); } + + inline int getBitsPerPixel(void) const { return bits_per_pixel; } + inline int getDepth(void) const { return screen_depth; } + inline int getColorsPerChannel(void) const + { return colors_per_channel; } + + unsigned long getSqrt(unsigned int x); + + Pixmap renderImage(unsigned int width, unsigned int height, + const BTexture &texture); + + void installRootColormap(void); + void removeImage(Pixmap pixmap); + void getColorTables(unsigned char **rmt, unsigned char **gmt, + unsigned char **bmt, + int *roff, int *goff, int *boff, + int *rbit, int *gbit, int *bbit); + void getXColorTable(XColor **c, int *n); + void getGradientBuffers(unsigned int w, unsigned int h, + unsigned int **xbuf, unsigned int **ybuf); + void setDither(bool d) { dither = d; } + void setColorsPerChannel(int cpc); + + virtual void timeout(void); + +private: + bool dither; + BaseDisplay *basedisplay; + const ScreenInfo *screeninfo; +#ifdef TIMEDCACHE + BTimer *timer; +#endif // TIMEDCACHE + + Colormap colormap; + + Window window; + XColor *colors; + int colors_per_channel, ncolors, screen_number, screen_depth, + bits_per_pixel, red_offset, green_offset, blue_offset, + red_bits, green_bits, blue_bits; + unsigned char red_color_table[256], green_color_table[256], + blue_color_table[256]; + unsigned int *grad_xbuffer, *grad_ybuffer, grad_buffer_width, + grad_buffer_height; + unsigned long *sqrt_table, cache_max; + + typedef std::list CacheContainer; + CacheContainer cache; + + Pixmap searchCache(const unsigned int width, const unsigned int height, + const unsigned long texture, + const BColor &c1, const BColor &c2); +}; + + +#endif // __Image_hh + diff --git a/src/imagecontrol.cc b/src/imagecontrol.cc new file mode 100644 index 00000000..159e02fd --- /dev/null +++ b/src/imagecontrol.cc @@ -0,0 +1,598 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// ImageControl.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef HAVE_CTYPE_H +# include +#endif // HAVE_CTYPE_H + +#include +} + +#include + +#include "blackbox.hh" +#include "basedisplay.hh" +#include "color.hh" +#include "image.hh" +#include "texture.hh" + +static unsigned long bsqrt(unsigned long x) { + if (x <= 0) return 0; + if (x == 1) return 1; + + unsigned long r = x >> 1; + unsigned long q; + + while (1) { + q = x / r; + if (q >= r) return r; + r = (r + q) >> 1; + } +} + +BImageControl *ctrl = 0; + +BImageControl::BImageControl(BaseDisplay *dpy, const ScreenInfo *scrn, + bool _dither, int _cpc, + unsigned long cache_timeout, + unsigned long cmax) { + if (! ctrl) ctrl = this; + + basedisplay = dpy; + screeninfo = scrn; + setDither(_dither); + setColorsPerChannel(_cpc); + + cache_max = cmax; +#ifdef TIMEDCACHE + if (cache_timeout) { + timer = new BTimer(basedisplay, this); + timer->setTimeout(cache_timeout); + timer->start(); + } else { + timer = (BTimer *) 0; + } +#endif // TIMEDCACHE + + colors = (XColor *) 0; + ncolors = 0; + + grad_xbuffer = grad_ybuffer = (unsigned int *) 0; + grad_buffer_width = grad_buffer_height = 0; + + sqrt_table = (unsigned long *) 0; + + screen_depth = screeninfo->getDepth(); + window = screeninfo->getRootWindow(); + screen_number = screeninfo->getScreenNumber(); + colormap = screeninfo->getColormap(); + + int count; + XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(), + &count); + if (pmv) { + bits_per_pixel = 0; + for (int i = 0; i < count; i++) + if (pmv[i].depth == screen_depth) { + bits_per_pixel = pmv[i].bits_per_pixel; + break; + } + + XFree(pmv); + } + + if (bits_per_pixel == 0) bits_per_pixel = screen_depth; + if (bits_per_pixel >= 24) setDither(False); + + red_offset = green_offset = blue_offset = 0; + + switch (getVisual()->c_class) { + case TrueColor: { + int i; + + // compute color tables + unsigned long red_mask = getVisual()->red_mask, + green_mask = getVisual()->green_mask, + blue_mask = getVisual()->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_bits = 255 / red_mask; + green_bits = 255 / green_mask; + blue_bits = 255 / blue_mask; + + for (i = 0; i < 256; i++) { + red_color_table[i] = i / red_bits; + green_color_table[i] = i / green_bits; + blue_color_table[i] = i / blue_bits; + } + break; + } + + case PseudoColor: + case StaticColor: { + ncolors = colors_per_channel * colors_per_channel * colors_per_channel; + + if (ncolors > (1 << screen_depth)) { + colors_per_channel = (1 << screen_depth) / 3; + ncolors = colors_per_channel * colors_per_channel * colors_per_channel; + } + + if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { + fprintf(stderr, + i18n(ImageSet, ImageInvalidColormapSize, + "BImageControl::BImageControl: invalid colormap size %d " + "(%d/%d/%d) - reducing"), + ncolors, colors_per_channel, colors_per_channel, + colors_per_channel); + + colors_per_channel = (1 << screen_depth) / 3; + } + + colors = new XColor[ncolors]; + if (! colors) { + fprintf(stderr, i18n(ImageSet, ImageErrorAllocatingColormap, + "BImageControl::BImageControl: error allocating " + "colormap\n")); + exit(1); + } + + int i = 0, ii, p, r, g, b, + +#ifdef ORDEREDPSEUDO + bits = 256 / colors_per_channel; +#else // !ORDEREDPSEUDO + bits = 255 / (colors_per_channel - 1); +#endif // ORDEREDPSEUDO + + red_bits = green_bits = blue_bits = bits; + + for (i = 0; i < 256; i++) + red_color_table[i] = green_color_table[i] = blue_color_table[i] = + i / bits; + + for (r = 0, i = 0; r < colors_per_channel; r++) + for (g = 0; g < colors_per_channel; g++) + for (b = 0; b < colors_per_channel; b++, i++) { + colors[i].red = (r * 0xffff) / (colors_per_channel - 1); + colors[i].green = (g * 0xffff) / (colors_per_channel - 1); + colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);; + colors[i].flags = DoRed|DoGreen|DoBlue; + } + + for (i = 0; i < ncolors; i++) { + if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { + fprintf(stderr, i18n(ImageSet, ImageColorAllocFail, + "couldn't alloc color %i %i %i\n"), + colors[i].red, colors[i].green, colors[i].blue); + colors[i].flags = 0; + } else { + colors[i].flags = DoRed|DoGreen|DoBlue; + } + } + + XColor icolors[256]; + int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth)); + + for (i = 0; i < incolors; i++) + icolors[i].pixel = i; + + XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); + for (i = 0; i < ncolors; i++) { + if (! colors[i].flags) { + unsigned long chk = 0xffffffff, pixel, close = 0; + + p = 2; + while (p--) { + for (ii = 0; ii < incolors; ii++) { + r = (colors[i].red - icolors[i].red) >> 8; + g = (colors[i].green - icolors[i].green) >> 8; + b = (colors[i].blue - icolors[i].blue) >> 8; + pixel = (r * r) + (g * g) + (b * b); + + if (pixel < chk) { + chk = pixel; + close = ii; + } + + colors[i].red = icolors[close].red; + colors[i].green = icolors[close].green; + colors[i].blue = icolors[close].blue; + + if (XAllocColor(basedisplay->getXDisplay(), colormap, + &colors[i])) { + colors[i].flags = DoRed|DoGreen|DoBlue; + break; + } + } + } + } + } + + break; + } + + case GrayScale: + case StaticGray: { + if (getVisual()->c_class == StaticGray) { + ncolors = 1 << screen_depth; + } else { + ncolors = colors_per_channel * colors_per_channel * colors_per_channel; + + if (ncolors > (1 << screen_depth)) { + colors_per_channel = (1 << screen_depth) / 3; + ncolors = + colors_per_channel * colors_per_channel * colors_per_channel; + } + } + + if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) { + fprintf(stderr, + i18n(ImageSet, ImageInvalidColormapSize, + "BImageControl::BImageControl: invalid colormap size %d " + "(%d/%d/%d) - reducing"), + ncolors, colors_per_channel, colors_per_channel, + colors_per_channel); + + colors_per_channel = (1 << screen_depth) / 3; + } + + colors = new XColor[ncolors]; + if (! colors) { + fprintf(stderr, + i18n(ImageSet, ImageErrorAllocatingColormap, + "BImageControl::BImageControl: error allocating colormap\n")); + exit(1); + } + + int i = 0, ii, p, bits = 255 / (colors_per_channel - 1); + red_bits = green_bits = blue_bits = bits; + + for (i = 0; i < 256; i++) + red_color_table[i] = green_color_table[i] = blue_color_table[i] = + i / bits; + + for (i = 0; i < ncolors; i++) { + colors[i].red = (i * 0xffff) / (colors_per_channel - 1); + colors[i].green = (i * 0xffff) / (colors_per_channel - 1); + colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);; + colors[i].flags = DoRed|DoGreen|DoBlue; + + if (! XAllocColor(basedisplay->getXDisplay(), colormap, + &colors[i])) { + fprintf(stderr, i18n(ImageSet, ImageColorAllocFail, + "couldn't alloc color %i %i %i\n"), + colors[i].red, colors[i].green, colors[i].blue); + colors[i].flags = 0; + } else { + colors[i].flags = DoRed|DoGreen|DoBlue; + } + } + + XColor icolors[256]; + int incolors = (((1 << screen_depth) > 256) ? 256 : + (1 << screen_depth)); + + for (i = 0; i < incolors; i++) + icolors[i].pixel = i; + + XQueryColors(basedisplay->getXDisplay(), colormap, icolors, incolors); + for (i = 0; i < ncolors; i++) { + if (! colors[i].flags) { + unsigned long chk = 0xffffffff, pixel, close = 0; + + p = 2; + while (p--) { + for (ii = 0; ii < incolors; ii++) { + int r = (colors[i].red - icolors[i].red) >> 8; + int g = (colors[i].green - icolors[i].green) >> 8; + int b = (colors[i].blue - icolors[i].blue) >> 8; + pixel = (r * r) + (g * g) + (b * b); + + if (pixel < chk) { + chk = pixel; + close = ii; + } + + colors[i].red = icolors[close].red; + colors[i].green = icolors[close].green; + colors[i].blue = icolors[close].blue; + + if (XAllocColor(basedisplay->getXDisplay(), colormap, + &colors[i])) { + colors[i].flags = DoRed|DoGreen|DoBlue; + break; + } + } + } + } + } + + break; + } + + default: + fprintf(stderr, + i18n(ImageSet, ImageUnsupVisual, + "BImageControl::BImageControl: unsupported visual %d\n"), + getVisual()->c_class); + exit(1); + } +} + + +BImageControl::~BImageControl(void) { + delete [] sqrt_table; + + delete [] grad_xbuffer; + + delete [] grad_ybuffer; + + if (colors) { + unsigned long *pixels = new unsigned long [ncolors]; + + for (int i = 0; i < ncolors; i++) + *(pixels + i) = (*(colors + i)).pixel; + + XFreeColors(basedisplay->getXDisplay(), colormap, pixels, ncolors, 0); + + delete [] colors; + } + + if (! cache.empty()) { + //#ifdef DEBUG + fprintf(stderr, i18n(ImageSet, ImagePixmapRelease, + "BImageContol::~BImageControl: pixmap cache - " + "releasing %d pixmaps\n"), cache.size()); + //#endif + CacheContainer::iterator it = cache.begin(); + const CacheContainer::iterator end = cache.end(); + for (; it != end; ++it) + XFreePixmap(basedisplay->getXDisplay(), it->pixmap); + } +#ifdef TIMEDCACHE + if (timer) { + timer->stop(); + delete timer; + } +#endif // TIMEDCACHE +} + + +Pixmap BImageControl::searchCache(const unsigned int width, + const unsigned int height, + const unsigned long texture, + const BColor &c1, const BColor &c2) { + if (cache.empty()) + return None; + + CacheContainer::iterator it = cache.begin(); + const CacheContainer::iterator end = cache.end(); + for (; it != end; ++it) { + CachedImage& tmp = *it; + if (tmp.width == width && tmp.height == height && + tmp.texture == texture && tmp.pixel1 == c1.pixel()) + if (texture & BTexture::Gradient) { + if (tmp.pixel2 == c2.pixel()) { + tmp.count++; + return tmp.pixmap; + } + } else { + tmp.count++; + return tmp.pixmap; + } + } + return None; +} + + +Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, + const BTexture &texture) { + if (texture.texture() & BTexture::Parent_Relative) return ParentRelative; + + Pixmap pixmap = searchCache(width, height, texture.texture(), + texture.color(), texture.colorTo()); + if (pixmap) return pixmap; + + BImage image(this, width, height); + pixmap = image.render(texture); + + if (! pixmap) + return None; + + CachedImage tmp; + + tmp.pixmap = pixmap; + tmp.width = width; + tmp.height = height; + tmp.count = 1; + tmp.texture = texture.texture(); + tmp.pixel1 = texture.color().pixel(); + + if (texture.texture() & BTexture::Gradient) + tmp.pixel2 = texture.colorTo().pixel(); + else + tmp.pixel2 = 0l; + + cache.push_back(tmp); + + if (cache.size() > cache_max) { +#ifdef DEBUG + fprintf(stderr, i18n(ImageSet, ImagePixmapCacheLarge, + "BImageControl::renderImage: cache is large, " + "forcing cleanout\n")); +#endif // DEBUG + + timeout(); + } + + return pixmap; +} + + +void BImageControl::removeImage(Pixmap pixmap) { + if (! pixmap) + return; + + CacheContainer::iterator it = cache.begin(); + const CacheContainer::iterator end = cache.end(); + for (; it != end; ++it) { + CachedImage &tmp = *it; + if (tmp.pixmap == pixmap && tmp.count > 0) + tmp.count--; + } + +#ifdef TIMEDCACHE + if (! timer) +#endif // TIMEDCACHE + timeout(); +} + + +void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt, + unsigned char **bmt, + int *roff, int *goff, int *boff, + int *rbit, int *gbit, int *bbit) { + if (rmt) *rmt = red_color_table; + if (gmt) *gmt = green_color_table; + if (bmt) *bmt = blue_color_table; + + if (roff) *roff = red_offset; + if (goff) *goff = green_offset; + if (boff) *boff = blue_offset; + + if (rbit) *rbit = red_bits; + if (gbit) *gbit = green_bits; + if (bbit) *bbit = blue_bits; +} + + +void BImageControl::getXColorTable(XColor **c, int *n) { + if (c) *c = colors; + if (n) *n = ncolors; +} + + +void BImageControl::getGradientBuffers(unsigned int w, + unsigned int h, + unsigned int **xbuf, + unsigned int **ybuf) +{ + if (w > grad_buffer_width) { + if (grad_xbuffer) + delete [] grad_xbuffer; + + grad_buffer_width = w; + + grad_xbuffer = new unsigned int[grad_buffer_width * 3]; + } + + if (h > grad_buffer_height) { + if (grad_ybuffer) + delete [] grad_ybuffer; + + grad_buffer_height = h; + + grad_ybuffer = new unsigned int[grad_buffer_height * 3]; + } + + *xbuf = grad_xbuffer; + *ybuf = grad_ybuffer; +} + + +void BImageControl::installRootColormap(void) { + int ncmap = 0; + Colormap *cmaps = + XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap); + + if (cmaps) { + bool install = True; + for (int i = 0; i < ncmap; i++) + if (*(cmaps + i) == colormap) + install = False; + + if (install) + XInstallColormap(basedisplay->getXDisplay(), colormap); + + XFree(cmaps); + } +} + + +void BImageControl::setColorsPerChannel(int cpc) { + if (cpc < 2) cpc = 2; + if (cpc > 6) cpc = 6; + + colors_per_channel = cpc; +} + + +unsigned long BImageControl::getSqrt(unsigned int x) { + if (! sqrt_table) { + // build sqrt table for use with elliptic gradient + + sqrt_table = new unsigned long[(256 * 256 * 2) + 1]; + + for (int i = 0; i < (256 * 256 * 2); i++) + *(sqrt_table + i) = bsqrt(i); + } + + return (*(sqrt_table + x)); +} + + +struct ZeroRefCheck { + inline bool operator()(const BImageControl::CachedImage &image) const { + return (image.count == 0); + } +}; + +struct CacheCleaner { + Display *display; + ZeroRefCheck ref_check; + CacheCleaner(Display *d): display(d) {} + inline void operator()(const BImageControl::CachedImage& image) const { + if (ref_check(image)) + XFreePixmap(display, image.pixmap); + } +}; + + +void BImageControl::timeout(void) { + CacheCleaner cleaner(basedisplay->getXDisplay()); + std::for_each(cache.begin(), cache.end(), cleaner); + cache.remove_if(cleaner.ref_check); +} + diff --git a/src/main.cc b/src/main.cc index c16fba2d..f672eb23 100644 --- a/src/main.cc +++ b/src/main.cc @@ -52,7 +52,6 @@ extern "C" { #include using std::string; -#include "i18n.hh" #include "blackbox.hh" diff --git a/src/screen.cc b/src/screen.cc new file mode 100644 index 00000000..6fbfbdcc --- /dev/null +++ b/src/screen.cc @@ -0,0 +1,2777 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Screen.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +#include + +#ifdef XINERAMA +# include +# include +#endif // XINERAMA + +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H + +#ifdef HAVE_STRING_H +# include +#endif // HAVE_STRING_H + +#ifdef HAVE_CTYPE_H +# include +#endif // HAVE_CTYPE_H + +#ifdef HAVE_UNISTD_H +# include +# include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_DIRENT_H +# include +#endif // HAVE_DIRENT_H + +#ifdef HAVE_LOCALE_H +# include +#endif // HAVE_LOCALE_H + +#ifdef HAVE_SYS_STAT_H +# include +#endif // HAVE_SYS_STAT_H + +#ifdef HAVE_STDARG_H +# include +#endif // HAVE_STDARG_H +} + +#include + +#include +#include +#include +using std::string; + +#include "i18n.hh" +#include "blackbox.hh" +#include "clientmenu.hh" +#include "font.hh" +#include "gccache.hh" +#include "iconmenu.hh" +#include "image.hh" +#include "screen.hh" +#include "slit.hh" +#include "rootmenu.hh" +#include "toolbar.hh" +#include "util.hh" +#include "window.hh" +#include "workspace.hh" +#include "workspacemenu.hh" +#include "util.hh" +#include "xatom.hh" + +#ifndef FONT_ELEMENT_SIZE +#define FONT_ELEMENT_SIZE 50 +#endif // FONT_ELEMENT_SIZE + + +static bool running = True; + +static int anotherWMRunning(Display *display, XErrorEvent *) { + fprintf(stderr, i18n(ScreenSet, ScreenAnotherWMRunning, + "BScreen::BScreen: an error occured while querying the X server.\n" + " another window manager already running on display %s.\n"), + DisplayString(display)); + + running = False; + + return(-1); +} + + +BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) { + blackbox = bb; + screenstr = "session.screen" + itostring(scrn) + '.'; + config = blackbox->getConfig(); + xatom = blackbox->getXAtom(); + + event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask | + SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask; + + XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning); + XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask); + XSync(getBaseDisplay()->getXDisplay(), False); + XSetErrorHandler((XErrorHandler) old); + + managed = running; + if (! managed) return; + + fprintf(stderr, i18n(ScreenSet, ScreenManagingScreen, + "BScreen::BScreen: managing screen %d " + "using visual 0x%lx, depth %d\n"), + getScreenNumber(), XVisualIDFromVisual(getVisual()), + getDepth()); + + rootmenu = 0; + + resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font = + resource.wstyle.font = (BFont *) 0; + + geom_pixmap = None; + + xatom->setSupported(this); // set-up netwm support +#ifdef HAVE_GETPID + xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal, + (unsigned long) getpid()); +#endif // HAVE_GETPID + unsigned long geometry[] = { getWidth(), + getHeight()}; + xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry, + XAtom::cardinal, geometry, 2); + unsigned long viewport[] = {0,0}; + xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport, + XAtom::cardinal, viewport, 2); + + + XDefineCursor(blackbox->getXDisplay(), getRootWindow(), + blackbox->getSessionCursor()); + + updateAvailableArea(); + + image_control = + new BImageControl(blackbox, this, True, blackbox->getColorsPerChannel(), + blackbox->getCacheLife(), blackbox->getCacheMax()); + image_control->installRootColormap(); + root_colormap_installed = True; + + load_rc(); + LoadStyle(); + + XGCValues gcv; + gcv.foreground = WhitePixel(blackbox->getXDisplay(), getScreenNumber()) + ^ BlackPixel(blackbox->getXDisplay(), getScreenNumber()); + gcv.function = GXxor; + gcv.subwindow_mode = IncludeInferiors; + opGC = XCreateGC(blackbox->getXDisplay(), getRootWindow(), + GCForeground | GCFunction | GCSubwindowMode, &gcv); + + const char *s = i18n(ScreenSet, ScreenPositionLength, + "0: 0000 x 0: 0000"); + geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2; + geom_h = resource.wstyle.font->height() + resource.bevel_width * 2; + + XSetWindowAttributes attrib; + unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder; + attrib.border_pixel = getBorderColor()->pixel(); + attrib.colormap = getColormap(); + attrib.save_under = True; + + geom_window = XCreateWindow(blackbox->getXDisplay(), getRootWindow(), + 0, 0, geom_w, geom_h, resource.border_width, + getDepth(), InputOutput, getVisual(), + mask, &attrib); + geom_visible = False; + + BTexture* texture = &(resource.wstyle.l_focus); + geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); + if (geom_pixmap == ParentRelative) { + texture = &(resource.wstyle.t_focus); + geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); + } + if (! geom_pixmap) + XSetWindowBackground(blackbox->getXDisplay(), geom_window, + texture->color().pixel()); + else + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + geom_window, geom_pixmap); + + workspacemenu = new Workspacemenu(this); + iconmenu = new Iconmenu(this); + configmenu = new Configmenu(this); + + if (resource.workspaces > 0) { + for (unsigned int i = 0; i < resource.workspaces; ++i) { + Workspace *wkspc = new Workspace(this, workspacesList.size()); + workspacesList.push_back(wkspc); + workspacemenu->insertWorkspace(wkspc); + workspacemenu->update(); + + } + } else { + Workspace *wkspc = new Workspace(this, workspacesList.size()); + workspacesList.push_back(wkspc); + workspacemenu->insertWorkspace(wkspc); + workspacemenu->update(); + } + saveWorkspaceNames(); + + updateNetizenWorkspaceCount(); + + workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu); + workspacemenu->update(); + + current_workspace = workspacesList.front(); + + xatom->setValue(getRootWindow(), XAtom::net_current_desktop, + XAtom::cardinal, 0); //first workspace + + workspacemenu->setItemSelected(2, True); + + toolbar = new Toolbar(this); + + slit = new Slit(this); + + InitMenu(); + + raiseWindows(0, 0); // this also initializes the empty stacking list + rootmenu->update(); + + updateClientList(); // initialize the client lists, which will be empty + updateAvailableArea(); + + changeWorkspaceID(0); + + unsigned int i, j, nchild; + Window r, p, *children; + XQueryTree(blackbox->getXDisplay(), getRootWindow(), &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(blackbox->getXDisplay(), + 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 || ! blackbox->validateWindow(children[i])) + continue; + + XWindowAttributes attrib; + if (XGetWindowAttributes(blackbox->getXDisplay(), children[i], &attrib)) { + if (attrib.override_redirect) continue; + + if (attrib.map_state != IsUnmapped) { + manageWindow(children[i]); + } + } + } + + XFree(children); + + // call this again just in case a window we found updates the Strut list + updateAvailableArea(); +} + + +BScreen::~BScreen(void) { + if (! managed) return; + + if (geom_pixmap != None) + image_control->removeImage(geom_pixmap); + + if (geom_window != None) + XDestroyWindow(blackbox->getXDisplay(), geom_window); + + std::for_each(workspacesList.begin(), workspacesList.end(), + PointerAssassin()); + + std::for_each(iconList.begin(), iconList.end(), PointerAssassin()); + + std::for_each(netizenList.begin(), netizenList.end(), PointerAssassin()); + + while (! systrayWindowList.empty()) + removeSystrayWindow(systrayWindowList[0]); + + delete rootmenu; + delete workspacemenu; + delete iconmenu; + delete configmenu; + delete slit; + delete toolbar; + delete image_control; + + if (resource.wstyle.font) + delete resource.wstyle.font; + if (resource.mstyle.t_font) + delete resource.mstyle.t_font; + if (resource.mstyle.f_font) + delete resource.mstyle.f_font; + if (resource.tstyle.font) + delete resource.tstyle.font; + +#ifdef BITMAPBUTTONS + if (resource.wstyle.close_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask); + if (resource.wstyle.max_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask); + if (resource.wstyle.icon_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask); + if (resource.wstyle.stick_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask); + + if (resource.tstyle.left_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask); + if (resource.tstyle.right_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask); + + if (resource.mstyle.bullet_image.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask); + if (resource.mstyle.tick_image.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask); + + resource.wstyle.max_button.mask = resource.wstyle.close_button.mask = + resource.wstyle.icon_button.mask = + resource.wstyle.stick_button.mask = None; + resource.tstyle.left_button.mask = resource.tstyle.right_button.mask = None; + resource.mstyle.bullet_image.mask = resource.mstyle.tick_image.mask = None; +#endif // BITMAPBUTTONS + + XFreeGC(blackbox->getXDisplay(), opGC); +} + + +void BScreen::saveSloppyFocus(bool s) { + resource.sloppy_focus = s; + + string fmodel; + if (resource.sloppy_focus) { + fmodel = "SloppyFocus"; + if (resource.auto_raise) fmodel += " AutoRaise"; + if (resource.click_raise) fmodel += " ClickRaise"; + } else { + fmodel = "ClickToFocus"; + } + config->setValue(screenstr + "focusModel", fmodel); +} + + +void BScreen::saveAutoRaise(bool a) { + resource.auto_raise = a; + saveSloppyFocus(resource.sloppy_focus); +} + + +void BScreen::saveClickRaise(bool c) { + resource.click_raise = c; + saveSloppyFocus(resource.sloppy_focus); +} + + +void BScreen::saveImageDither(bool d) { + image_control->setDither(d); + config->setValue(screenstr + "imageDither", doImageDither()); +} + + +void BScreen::saveOpaqueMove(bool o) { + resource.opaque_move = o; + config->setValue(screenstr + "opaqueMove", resource.opaque_move); +} + + +void BScreen::saveFullMax(bool f) { + resource.full_max = f; + config->setValue(screenstr + "fullMaximization", resource.full_max); +} + + +void BScreen::saveFocusNew(bool f) { + resource.focus_new = f; + config->setValue(screenstr + "focusNewWindows", resource.focus_new); +} + + +void BScreen::saveFocusLast(bool f) { + resource.focus_last = f; + config->setValue(screenstr + "focusLastWindow", resource.focus_last); +} + + +void BScreen::saveAAFonts(bool f) { + resource.aa_fonts = f; + config->setValue(screenstr + "antialiasFonts", resource.aa_fonts); + reconfigure(); +} + + +void BScreen::saveShadowFonts(bool f) { + resource.shadow_fonts = f; + config->setValue(screenstr + "dropShadowFonts", resource.shadow_fonts); + reconfigure(); +} + + +void BScreen::saveHideToolbar(bool h) { + resource.hide_toolbar = h; + if (resource.hide_toolbar) + toolbar->unmapToolbar(); + else + toolbar->mapToolbar(); + config->setValue(screenstr + "hideToolbar", resource.hide_toolbar); +} + + +void BScreen::saveWindowToEdgeSnap(int s) { + resource.snap_to_edges = s; + + const char *snap; + switch (resource.snap_to_edges) { + case WindowNoSnap: snap = "NoSnap"; break; + case WindowResistance: snap = "Resistance"; break; + case WindowSnap: default: snap = "Snap"; break; + } + config->setValue(screenstr + "windowToEdgeSnap", snap); +} + + +void BScreen::saveWindowToWindowSnap(int s) { + resource.snap_to_windows = s; + + const char *snap; + switch (resource.snap_to_windows) { + case WindowNoSnap: snap = "NoSnap"; break; + case WindowResistance: snap = "Resistance"; break; + case WindowSnap: default: snap = "Snap"; break; + } + config->setValue(screenstr + "windowToWindowSnap", snap); +} + + +void BScreen::saveResizeZones(unsigned int z) { + resource.resize_zones = z; + config->setValue(screenstr + "resizeZones", resource.resize_zones); +} + + +void BScreen::saveWindowCornerSnap(bool s) { + resource.window_corner_snap = s; + config->setValue(screenstr + "windowCornerSnap", + resource.window_corner_snap); +} + + +void BScreen::saveWorkspaces(unsigned int w) { + resource.workspaces = w; + config->setValue(screenstr + "workspaces", resource.workspaces); +} + + +void BScreen::savePlacementPolicy(int p) { + resource.placement_policy = p; + const char *placement; + switch (resource.placement_policy) { + case CascadePlacement: placement = "CascadePlacement"; break; + case UnderMousePlacement: placement = "UnderMousePlacement"; break; + case ClickMousePlacement: placement = "ClickMousePlacement"; break; + case ColSmartPlacement: placement = "ColSmartPlacement"; break; + case RowSmartPlacement: default: placement = "RowSmartPlacement"; break; + } + config->setValue(screenstr + "windowPlacement", placement); +} + + +void BScreen::saveResistanceSize(int s) { + resource.resistance_size = s; + config->setValue(screenstr + "resistanceSize", + resource.resistance_size); +} + + +void BScreen::saveSnapThreshold(int t) { + resource.snap_threshold = t; + config->setValue(screenstr + "edgeSnapThreshold", + resource.snap_threshold); +} + + +void BScreen::saveSnapOffset(int t) { + resource.snap_offset = t; + config->setValue(screenstr + "edgeSnapOffset", + resource.snap_offset); +} + + +void BScreen::saveRowPlacementDirection(int d) { + resource.row_direction = d; + config->setValue(screenstr + "rowPlacementDirection", + resource.row_direction == LeftRight ? + "LeftToRight" : "RightToLeft"); +} + + +void BScreen::saveColPlacementDirection(int d) { + resource.col_direction = d; + config->setValue(screenstr + "colPlacementDirection", + resource.col_direction == TopBottom ? + "TopToBottom" : "BottomToTop"); +} + + +#ifdef HAVE_STRFTIME +void BScreen::saveStrftimeFormat(const std::string& format) { + resource.strftime_format = format; + config->setValue(screenstr + "strftimeFormat", resource.strftime_format); +} + +#else // !HAVE_STRFTIME + +void BScreen::saveDateFormat(int f) { + resource.date_format = f; + config->setValue(screenstr + "dateFormat", + resource.date_format == B_EuropeanDate ? + "European" : "American"); +} + + +void BScreen::saveClock24Hour(bool c) { + resource.clock24hour = c; + config->setValue(screenstr + "clockFormat", resource.clock24hour ? 24 : 12); +} +#endif // HAVE_STRFTIME + + +void BScreen::saveWorkspaceNames() { + string names; + + for (unsigned int i = 0; i < workspacesList.size(); ++i) { + names += workspacesList[i]->getName(); + if (i < workspacesList.size() - 1) + names += ','; + } + + config->setValue(screenstr + "workspaceNames", names); +} + + +void BScreen::savePlaceIgnoreShaded(bool i) { + resource.ignore_shaded = i; + config->setValue(screenstr + "placementIgnoreShaded", + resource.ignore_shaded); +} + + +void BScreen::savePlaceIgnoreMaximized(bool i) { + resource.ignore_maximized = i; + config->setValue(screenstr + "placementIgnoreMaximized", + resource.ignore_maximized); +} + + +void BScreen::saveAllowScrollLock(bool a) { + resource.allow_scroll_lock = a; + config->setValue(screenstr + "disableBindingsWithScrollLock", + resource.allow_scroll_lock); +} + + +void BScreen::saveWorkspaceWarping(bool w) { + resource.workspace_warping = w; + config->setValue(screenstr + "workspaceWarping", + resource.workspace_warping); +} + + +void BScreen::saveRootScrollDirection(int d) { + resource.root_scroll = d; + const char *dir; + switch (resource.root_scroll) { + case NoScroll: dir = "None"; break; + case ReverseScroll: dir = "Reverse"; break; + case NormalScroll: default: dir = "Normal"; break; + } + config->setValue(screenstr + "rootScrollDirection", dir); +} + + +void BScreen::saveRootMenuButton(unsigned int b) { + resource.root_menu_button = b; + const char *but; + switch (resource.root_menu_button) { + case 0: but = "None"; break; + case 1: but = "Left"; break; + case 2: but = "Middle"; break; + case 3: default: but = "Right"; break; + } + config->setValue(screenstr + "rootMenuButton", but); +} + + +void BScreen::saveWorkspaceMenuButton(unsigned int b) { + resource.workspace_menu_button = b; + const char *but; + switch (resource.workspace_menu_button) { + case 0: but = "None"; break; + case 1: but = "Left"; break; + case 2: default: but = "Middle"; break; + case 3: but = "Right"; break; + } + config->setValue(screenstr + "workspaceMenuButton", but); +} + + +void BScreen::save_rc(void) { + saveSloppyFocus(resource.sloppy_focus); + saveAutoRaise(resource.auto_raise); + saveImageDither(doImageDither()); + saveShadowFonts(resource.shadow_fonts); + saveAAFonts(resource.aa_fonts); + saveResizeZones(resource.resize_zones); + saveOpaqueMove(resource.opaque_move); + saveFullMax(resource.full_max); + saveFocusNew(resource.focus_new); + saveFocusLast(resource.focus_last); + saveHideToolbar(resource.hide_toolbar); + saveWindowToWindowSnap(resource.snap_to_windows); + saveWindowToEdgeSnap(resource.snap_to_edges); + saveWindowCornerSnap(resource.window_corner_snap); + saveWorkspaces(resource.workspaces); + savePlacementPolicy(resource.placement_policy); + saveSnapThreshold(resource.snap_threshold); + saveSnapOffset(resource.snap_offset); + saveResistanceSize(resource.resistance_size); + saveRowPlacementDirection(resource.row_direction); + saveColPlacementDirection(resource.col_direction); +#ifdef HAVE_STRFTIME + saveStrftimeFormat(resource.strftime_format); +#else // !HAVE_STRFTIME + saveDateFormat(resource.date_format); + savwClock24Hour(resource.clock24hour); +#endif // HAVE_STRFTIME + savePlaceIgnoreShaded(resource.ignore_shaded); + savePlaceIgnoreMaximized(resource.ignore_maximized); + saveAllowScrollLock(resource.allow_scroll_lock); + saveWorkspaceWarping(resource.workspace_warping); + saveRootScrollDirection(resource.root_scroll); + saveRootMenuButton(resource.root_menu_button); + saveWorkspaceMenuButton(resource.workspace_menu_button); + + toolbar->save_rc(); + slit->save_rc(); +} + + +void BScreen::load_rc(void) { + std::string s; + bool b; + + if (! config->getValue(screenstr + "fullMaximization", resource.full_max)) + resource.full_max = false; + + if (! config->getValue(screenstr + "focusNewWindows", resource.focus_new)) + resource.focus_new = false; + + if (! config->getValue(screenstr + "focusLastWindow", resource.focus_last)) + resource.focus_last = false; + + if (! config->getValue(screenstr + "workspaces", resource.workspaces)) + resource.workspaces = 1; + + if (! config->getValue(screenstr + "opaqueMove", resource.opaque_move)) + resource.opaque_move = false; + + if (! config->getValue(screenstr + "antialiasFonts", resource.aa_fonts)) + resource.aa_fonts = true; + + if (! resource.aa_fonts || + ! config->getValue(screenstr + "dropShadowFonts", resource.shadow_fonts)) + resource.shadow_fonts = false; + + if (! config->getValue(screenstr + "resizeZones", resource.resize_zones) || + (resource.resize_zones != 1 && resource.resize_zones != 2 && + resource.resize_zones != 4)) + resource.resize_zones = 4; + + if (! config->getValue(screenstr + "hideToolbar", resource.hide_toolbar)) + resource.hide_toolbar = false; + + resource.snap_to_windows = WindowResistance; + if (config->getValue(screenstr + "windowToWindowSnap", s)) { + if (s == "NoSnap") + resource.snap_to_windows = WindowNoSnap; + else if (s == "Snap") + resource.snap_to_windows = WindowSnap; + } + + resource.snap_to_edges = WindowResistance; + if (config->getValue(screenstr + "windowToEdgeSnap", s)) { + if (s == "NoSnap") + resource.snap_to_edges = WindowNoSnap; + else if (s == "Snap") + resource.snap_to_edges = WindowSnap; + } + + if (! config->getValue(screenstr + "windowCornerSnap", + resource.window_corner_snap)) + resource.window_corner_snap = true; + + if (! config->getValue(screenstr + "imageDither", b)) + b = true; + image_control->setDither(b); + + if (! config->getValue(screenstr + "edgeSnapOffset", + resource.snap_offset)) + resource.snap_offset = 0; + if (resource.snap_offset > 50) // sanity check, setting this huge would + resource.snap_offset = 50; // seriously suck. + + if (! config->getValue(screenstr + "edgeSnapThreshold", + resource.snap_threshold)) + resource.snap_threshold = 4; + + if (! config->getValue(screenstr + "resistanceSize", + resource.resistance_size)) + resource.resistance_size = 18; + + if (config->getValue(screenstr + "rowPlacementDirection", s) && + s == "RightToLeft") + resource.row_direction = RightLeft; + else + resource.row_direction = LeftRight; + + if (config->getValue(screenstr + "colPlacementDirection", s) && + s == "BottomToTop") + resource.col_direction = BottomTop; + else + resource.col_direction = TopBottom; + + if (config->getValue(screenstr + "workspaceNames", s)) { + XAtom::StringVect workspaceNames; + + string::const_iterator it = s.begin(), end = s.end(); + while(1) { + string::const_iterator tmp = it; // current string.begin() + it = std::find(tmp, end, ','); // look for comma between tmp and end + workspaceNames.push_back(string(tmp, it)); // s[tmp:it] + if (it == end) + break; + ++it; + } + + xatom->setValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8, + workspaceNames); + } + + resource.sloppy_focus = true; + resource.auto_raise = false; + resource.click_raise = false; + if (config->getValue(screenstr + "focusModel", s)) { + if (s.find("ClickToFocus") != string::npos) { + resource.sloppy_focus = false; + } else { + // must be sloppy + if (s.find("AutoRaise") != string::npos) + resource.auto_raise = true; + if (s.find("ClickRaise") != string::npos) + resource.click_raise = true; + } + } + + if (config->getValue(screenstr + "windowPlacement", s)) { + if (s == "CascadePlacement") + resource.placement_policy = CascadePlacement; + else if (s == "UnderMousePlacement") + resource.placement_policy = UnderMousePlacement; + else if (s == "ClickMousePlacement") + resource.placement_policy = ClickMousePlacement; + else if (s == "ColSmartPlacement") + resource.placement_policy = ColSmartPlacement; + else //if (s == "RowSmartPlacement") + resource.placement_policy = RowSmartPlacement; + } else + resource.placement_policy = RowSmartPlacement; + +#ifdef HAVE_STRFTIME + if (! config->getValue(screenstr + "strftimeFormat", + resource.strftime_format)) + resource.strftime_format = "%I:%M %p"; +#else // !HAVE_STRFTIME + long l; + + if (config->getValue(screenstr + "dateFormat", s) && s == "European") + resource.date_format = B_EuropeanDate; + else + resource.date_format = B_AmericanDate; + + if (! config->getValue(screenstr + "clockFormat", l)) + l = 12; + resource.clock24hour = l == 24; +#endif // HAVE_STRFTIME + + if (! config->getValue(screenstr + "placementIgnoreShaded", + resource.ignore_shaded)) + resource.ignore_shaded = true; + + if (! config->getValue(screenstr + "placementIgnoreMaximized", + resource.ignore_maximized)) + resource.ignore_maximized = true; + + if (! config->getValue(screenstr + "disableBindingsWithScrollLock", + resource.allow_scroll_lock)) + resource.allow_scroll_lock = false; + + if (! config->getValue(screenstr + "workspaceWarping", + resource.workspace_warping)) + resource.workspace_warping = false; + + resource.root_scroll = NormalScroll; + if (config->getValue(screenstr + "rootScrollDirection", s)) { + if (s == "None") + resource.root_scroll = NoScroll; + else if (s == "Reverse") + resource.root_scroll = ReverseScroll; + } + + resource.root_menu_button = 3; + if (config->getValue(screenstr + "rootMenuButton", s)) { + if (s == "None") + resource.root_menu_button = 0; + else if (s == "Left") + resource.root_menu_button = 1; + else if (s == "Middle") + resource.root_menu_button = 2; + } + + resource.workspace_menu_button = 2; + if (config->getValue(screenstr + "workspaceMenuButton", s)) { + if (s == "None") + resource.workspace_menu_button = 0; + else if (s == "Left") + resource.workspace_menu_button = 1; + else if (s == "Right") + resource.workspace_menu_button = 3; + } + // cant both be the same + if (resource.workspace_menu_button == resource.root_menu_button) + resource.workspace_menu_button = 0; +} + + +void BScreen::changeWorkspaceCount(unsigned int new_count) { + assert(new_count > 0); + + if (new_count < workspacesList.size()) { + // shrink + for (unsigned int i = workspacesList.size(); i > new_count; --i) + removeLastWorkspace(); + // removeLast already sets the current workspace to the + // last available one. + } else if (new_count > workspacesList.size()) { + // grow + for(unsigned int i = workspacesList.size(); i < new_count; ++i) + addWorkspace(); + } +} + + +void BScreen::reconfigure(void) { + // don't reconfigure while saving the initial rc file, it's a waste and it + // breaks somethings (workspace names) + if (blackbox->isStartup()) return; + + load_rc(); + toolbar->load_rc(); + slit->load_rc(); + LoadStyle(); + + // we need to do this explicitly, because just loading this value from the rc + // does nothing + changeWorkspaceCount(resource.workspaces); + + XGCValues gcv; + gcv.foreground = WhitePixel(blackbox->getXDisplay(), + getScreenNumber()); + gcv.function = GXinvert; + gcv.subwindow_mode = IncludeInferiors; + XChangeGC(blackbox->getXDisplay(), opGC, + GCForeground | GCFunction | GCSubwindowMode, &gcv); + + const char *s = i18n(ScreenSet, ScreenPositionLength, + "0: 0000 x 0: 0000"); + + geom_w = resource.wstyle.font->measureString(s) + resource.bevel_width * 2; + geom_h = resource.wstyle.font->height() + resource.bevel_width * 2; + + BTexture* texture = &(resource.wstyle.l_focus); + geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); + if (geom_pixmap == ParentRelative) { + texture = &(resource.wstyle.t_focus); + geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap); + } + if (! geom_pixmap) + XSetWindowBackground(blackbox->getXDisplay(), geom_window, + texture->color().pixel()); + else + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + geom_window, geom_pixmap); + + XSetWindowBorderWidth(blackbox->getXDisplay(), geom_window, + resource.border_width); + XSetWindowBorder(blackbox->getXDisplay(), geom_window, + resource.border_color.pixel()); + + workspacemenu->reconfigure(); + iconmenu->reconfigure(); + + typedef std::vector SubList; + SubList remember_subs; + + // save the current open menus + Basemenu *menu = rootmenu; + int submenu; + while ((submenu = menu->getCurrentSubmenu()) >= 0) { + remember_subs.push_back(submenu); + menu = menu->find(submenu)->submenu(); + assert(menu); + } + + InitMenu(); + raiseWindows(0, 0); + rootmenu->reconfigure(); + + // reopen the saved menus + menu = rootmenu; + const SubList::iterator subs_end = remember_subs.end(); + for (SubList::iterator it = remember_subs.begin(); it != subs_end; ++it) { + menu->drawSubmenu(*it); + menu = menu->find(*it)->submenu(); + if (! menu) + break; + } + + configmenu->reconfigure(); + + toolbar->reconfigure(); + + slit->reconfigure(); + + std::for_each(workspacesList.begin(), workspacesList.end(), + std::mem_fun(&Workspace::reconfigure)); + + BlackboxWindowList::iterator iit = iconList.begin(); + for (; iit != iconList.end(); ++iit) { + BlackboxWindow *bw = *iit; + if (bw->validateClient()) + bw->reconfigure(); + } + + image_control->timeout(); +} + + +void BScreen::rereadMenu(void) { + InitMenu(); + raiseWindows(0, 0); + + rootmenu->reconfigure(); +} + + +void BScreen::LoadStyle(void) { + Configuration style(False); + + const char *sfile = blackbox->getStyleFilename(); + if (sfile != NULL) { + style.setFile(sfile); + if (! style.load()) { + style.setFile(DEFAULTSTYLE); + if (! style.load()) + style.create(); // hardcoded default values will be used. + } + } + + // merge in the rc file + style.merge(config->file(), True); + + string s; + + // load fonts/fontsets + if (resource.wstyle.font) + delete resource.wstyle.font; + if (resource.tstyle.font) + delete resource.tstyle.font; + if (resource.mstyle.f_font) + delete resource.mstyle.f_font; + if (resource.mstyle.t_font) + delete resource.mstyle.t_font; + resource.wstyle.font = resource.tstyle.font = resource.mstyle.f_font = + resource.mstyle.t_font = (BFont *) 0; + + resource.wstyle.font = readDatabaseFont("window.", style); + resource.tstyle.font = readDatabaseFont("toolbar.", style); + resource.mstyle.t_font = readDatabaseFont("menu.title.", style); + resource.mstyle.f_font = readDatabaseFont("menu.frame.", style); + + // load window config + resource.wstyle.t_focus = + readDatabaseTexture("window.title.focus", "white", style); + resource.wstyle.t_unfocus = + readDatabaseTexture("window.title.unfocus", "black", style); + resource.wstyle.l_focus = + readDatabaseTexture("window.label.focus", "white", style); + resource.wstyle.l_unfocus = + readDatabaseTexture("window.label.unfocus", "black", style); + resource.wstyle.h_focus = + readDatabaseTexture("window.handle.focus", "white", style); + resource.wstyle.h_unfocus = + readDatabaseTexture("window.handle.unfocus", "black", style); + resource.wstyle.g_focus = + readDatabaseTexture("window.grip.focus", "white", style); + resource.wstyle.g_unfocus = + readDatabaseTexture("window.grip.unfocus", "black", style); + resource.wstyle.b_focus = + readDatabaseTexture("window.button.focus", "white", style); + resource.wstyle.b_unfocus = + readDatabaseTexture("window.button.unfocus", "black", style); + resource.wstyle.b_pressed = + readDatabaseTexture("window.button.pressed", "black", style); + + //if neither of these can be found, we will use the previous resource + resource.wstyle.b_pressed_focus = + readDatabaseTexture("window.button.pressed.focus", "black", style, true); + resource.wstyle.b_pressed_unfocus = + readDatabaseTexture("window.button.pressed.unfocus", "black", style, true); + +#ifdef BITMAPBUTTONS + if (resource.wstyle.close_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.close_button.mask); + if (resource.wstyle.max_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.max_button.mask); + if (resource.wstyle.icon_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.icon_button.mask); + if (resource.wstyle.stick_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.wstyle.stick_button.mask); + + resource.wstyle.close_button.mask = resource.wstyle.max_button.mask = + resource.wstyle.icon_button.mask = + resource.wstyle.icon_button.mask = None; + + readDatabaseMask("window.button.close.mask", resource.wstyle.close_button, + style); + readDatabaseMask("window.button.max.mask", resource.wstyle.max_button, + style); + readDatabaseMask("window.button.icon.mask", resource.wstyle.icon_button, + style); + readDatabaseMask("window.button.stick.mask", resource.wstyle.stick_button, + style); +#endif // BITMAPBUTTONS + + // we create the window.frame texture by hand because it exists only to + // make the code cleaner and is not actually used for display + BColor color = readDatabaseColor("window.frame.focusColor", "white", style); + resource.wstyle.f_focus = BTexture("solid flat", getBaseDisplay(), + getScreenNumber(), image_control); + resource.wstyle.f_focus.setColor(color); + + color = readDatabaseColor("window.frame.unfocusColor", "white", style); + resource.wstyle.f_unfocus = BTexture("solid flat", getBaseDisplay(), + getScreenNumber(), image_control); + resource.wstyle.f_unfocus.setColor(color); + + resource.wstyle.l_text_focus = + readDatabaseColor("window.label.focus.textColor", "black", style); + resource.wstyle.l_text_unfocus = + readDatabaseColor("window.label.unfocus.textColor", "white", style); + resource.wstyle.b_pic_focus = + readDatabaseColor("window.button.focus.picColor", "black", style); + resource.wstyle.b_pic_unfocus = + readDatabaseColor("window.button.unfocus.picColor", "white", style); + + resource.wstyle.justify = LeftJustify; + if (style.getValue("window.justify", s)) { + if (s == "right" || s == "Right") + resource.wstyle.justify = RightJustify; + else if (s == "center" || s == "Center") + resource.wstyle.justify = CenterJustify; + } + + // sanity checks + if (resource.wstyle.t_focus.texture() == BTexture::Parent_Relative) + resource.wstyle.t_focus = resource.wstyle.f_focus; + if (resource.wstyle.t_unfocus.texture() == BTexture::Parent_Relative) + resource.wstyle.t_unfocus = resource.wstyle.f_unfocus; + if (resource.wstyle.h_focus.texture() == BTexture::Parent_Relative) + resource.wstyle.h_focus = resource.wstyle.f_focus; + if (resource.wstyle.h_unfocus.texture() == BTexture::Parent_Relative) + resource.wstyle.h_unfocus = resource.wstyle.f_unfocus; + + // load toolbar config +#ifdef BITMAPBUTTONS + if (resource.tstyle.left_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.tstyle.left_button.mask); + if (resource.tstyle.right_button.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.tstyle.right_button.mask); +#endif // BITMAPBUTTONS + + resource.tstyle.toolbar = + readDatabaseTexture("toolbar", "black", style); + resource.tstyle.label = + readDatabaseTexture("toolbar.label", "black", style); + resource.tstyle.window = + readDatabaseTexture("toolbar.windowLabel", "black", style); + resource.tstyle.button = + readDatabaseTexture("toolbar.button", "white", style); + resource.tstyle.pressed = + readDatabaseTexture("toolbar.button.pressed", "black", style); + resource.tstyle.clock = + readDatabaseTexture("toolbar.clock", "black", style); + resource.tstyle.l_text = + readDatabaseColor("toolbar.label.textColor", "white", style); + resource.tstyle.w_text = + readDatabaseColor("toolbar.windowLabel.textColor", "white", style); + resource.tstyle.c_text = + readDatabaseColor("toolbar.clock.textColor", "white", style); + resource.tstyle.b_pic = + readDatabaseColor("toolbar.button.picColor", "black", style); + +#ifdef BITMAPBUTTONS + readDatabaseMask("toolbar.button.left.mask", resource.tstyle.left_button, + style); + readDatabaseMask("toolbar.button.right.mask", resource.tstyle.right_button, + style); +#endif // BITMAPBUTTONS + + resource.tstyle.justify = LeftJustify; + if (style.getValue("toolbar.justify", s)) { + if (s == "right" || s == "Right") + resource.tstyle.justify = RightJustify; + else if (s == "center" || s == "Center") + resource.tstyle.justify = CenterJustify; + } + + // sanity checks + if (resource.tstyle.toolbar.texture() == BTexture::Parent_Relative) { + resource.tstyle.toolbar = BTexture("solid flat", getBaseDisplay(), + getScreenNumber(), image_control); + resource.tstyle.toolbar.setColor(BColor("black", getBaseDisplay(), + getScreenNumber())); + } + + // load menu config +#ifdef BITMAPBUTTONS + if (resource.mstyle.bullet_image.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.mstyle.bullet_image.mask); + if (resource.mstyle.tick_image.mask != None) + XFreePixmap(blackbox->getXDisplay(), resource.mstyle.tick_image.mask); +#endif // BITMAPBUTTONS + + resource.mstyle.title = + readDatabaseTexture("menu.title", "white", style); + resource.mstyle.frame = + readDatabaseTexture("menu.frame", "black", style); + resource.mstyle.hilite = + readDatabaseTexture("menu.hilite", "white", style); + resource.mstyle.t_text = + readDatabaseColor("menu.title.textColor", "black", style); + resource.mstyle.f_text = + readDatabaseColor("menu.frame.textColor", "white", style); + resource.mstyle.d_text = + readDatabaseColor("menu.frame.disableColor", "black", style); + resource.mstyle.h_text = + readDatabaseColor("menu.hilite.textColor", "black", style); + +#ifdef BITMAPBUTTONS + readDatabaseMask("menu.arrow.mask", resource.mstyle.bullet_image, style); + readDatabaseMask("menu.selected.mask", resource.mstyle.tick_image, style); +#endif // BITMAPBUTTONS + + resource.mstyle.t_justify = LeftJustify; + if (style.getValue("menu.title.justify", s)) { + if (s == "right" || s == "Right") + resource.mstyle.t_justify = RightJustify; + else if (s == "center" || s == "Center") + resource.mstyle.t_justify = CenterJustify; + } + + resource.mstyle.f_justify = LeftJustify; + if (style.getValue("menu.frame.justify", s)) { + if (s == "right" || s == "Right") + resource.mstyle.f_justify = RightJustify; + else if (s == "center" || s == "Center") + resource.mstyle.f_justify = CenterJustify; + } + + resource.mstyle.bullet = Basemenu::Triangle; + if (style.getValue("menu.bullet", s)) { + if (s == "empty" || s == "Empty") + resource.mstyle.bullet = Basemenu::Empty; + else if (s == "square" || s == "Square") + resource.mstyle.bullet = Basemenu::Square; + else if (s == "diamond" || s == "Diamond") + resource.mstyle.bullet = Basemenu::Diamond; + } + + resource.mstyle.bullet_pos = Basemenu::Left; + if (style.getValue("menu.bullet.position", s)) { + if (s == "right" || s == "Right") + resource.mstyle.bullet_pos = Basemenu::Right; + } + + // sanity checks + if (resource.mstyle.frame.texture() == BTexture::Parent_Relative) { + resource.mstyle.frame = BTexture("solid flat", getBaseDisplay(), + getScreenNumber(), image_control); + resource.mstyle.frame.setColor(BColor("black", getBaseDisplay(), + getScreenNumber())); + } + + resource.border_color = + readDatabaseColor("borderColor", "black", style); + + // load bevel, border and handle widths + if (! style.getValue("handleWidth", resource.handle_width) || + resource.handle_width > (getWidth() / 2) || resource.handle_width == 0) + resource.handle_width = 6; + + if (! style.getValue("borderWidth", resource.border_width)) + resource.border_width = 1; + + if (! style.getValue("bevelWidth", resource.bevel_width) || + resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0) + resource.bevel_width = 3; + + if (! style.getValue("frameWidth", resource.frame_width) || + resource.frame_width > (getWidth() / 2)) + resource.frame_width = resource.bevel_width; + + if (style.getValue("rootCommand", s)) + bexec(s, displayString()); +} + + +void BScreen::addIcon(BlackboxWindow *w) { + if (! w) return; + + w->setWorkspace(BSENTINEL); + w->setWindowNumber(iconList.size()); + + iconList.push_back(w); + + const char* title = w->getIconTitle(); + iconmenu->insert(title); + iconmenu->update(); +} + + +void BScreen::removeIcon(BlackboxWindow *w) { + if (! w) return; + + iconList.remove(w); + + iconmenu->remove(w->getWindowNumber()); + iconmenu->update(); + + BlackboxWindowList::iterator it = iconList.begin(), + end = iconList.end(); + for (int i = 0; it != end; ++it) + (*it)->setWindowNumber(i++); +} + + +BlackboxWindow *BScreen::getIcon(unsigned int index) { + if (index < iconList.size()) { + BlackboxWindowList::iterator it = iconList.begin(); + while (index-- > 0) // increment to index + ++it; + return *it; + } + + return (BlackboxWindow *) 0; +} + + +unsigned int BScreen::addWorkspace(void) { + Workspace *wkspc = new Workspace(this, workspacesList.size()); + workspacesList.push_back(wkspc); + saveWorkspaces(getWorkspaceCount()); + saveWorkspaceNames(); + + workspacemenu->insertWorkspace(wkspc); + workspacemenu->update(); + + toolbar->reconfigure(); + + updateNetizenWorkspaceCount(); + + return workspacesList.size(); +} + + +unsigned int BScreen::removeLastWorkspace(void) { + if (workspacesList.size() == 1) + return 1; + + Workspace *wkspc = workspacesList.back(); + + if (current_workspace->getID() == wkspc->getID()) + changeWorkspaceID(current_workspace->getID() - 1); + + wkspc->removeAll(); + + workspacemenu->removeWorkspace(wkspc); + workspacemenu->update(); + + workspacesList.pop_back(); + delete wkspc; + + saveWorkspaces(getWorkspaceCount()); + saveWorkspaceNames(); + + toolbar->reconfigure(); + + updateNetizenWorkspaceCount(); + + return workspacesList.size(); +} + + +void BScreen::changeWorkspaceID(unsigned int id) { + if (! current_workspace || id == current_workspace->getID()) return; + + BlackboxWindow *focused = blackbox->getFocusedWindow(); + if (focused && focused->getScreen() == this) { + assert(focused->isStuck() || + focused->getWorkspaceNumber() == current_workspace->getID()); + + current_workspace->setLastFocusedWindow(focused); + } else { + // if no window had focus, no need to store a last focus + current_workspace->setLastFocusedWindow((BlackboxWindow *) 0); + } + + // when we switch workspaces, unfocus whatever was focused if it is going + // to be unmapped + if (focused && ! focused->isStuck()) + blackbox->setFocusedWindow((BlackboxWindow *) 0); + + current_workspace->hideAll(); + workspacemenu->setItemSelected(current_workspace->getID() + 2, False); + + current_workspace = getWorkspace(id); + + xatom->setValue(getRootWindow(), XAtom::net_current_desktop, + XAtom::cardinal, id); + + workspacemenu->setItemSelected(current_workspace->getID() + 2, True); + toolbar->redrawWorkspaceLabel(True); + + current_workspace->showAll(); + + int x, y, rx, ry; + Window c, r; + unsigned int m; + BlackboxWindow *win = (BlackboxWindow *) 0; + bool f = False; + + XSync(blackbox->getXDisplay(), False); + + // If sloppy focus and we can find the client window under the pointer, + // try to focus it. + if (resource.sloppy_focus && + XQueryPointer(blackbox->getXDisplay(), getRootWindow(), &r, &c, + &rx, &ry, &x, &y, &m) && + c != None) { + if ( (win = blackbox->searchWindow(c)) ) + f = win->setInputFocus(); + } + + // If that fails, and we're doing focus_last, try to focus the last window. + if (! f && resource.focus_last && + (win = current_workspace->getLastFocusedWindow())) + f = win->setInputFocus(); + + /* + if we found a focus target, then we set the focused window explicitly + because it is possible to switch off this workspace before the x server + generates the FocusIn event for the window. if that happens, openbox would + lose track of what window was the 'LastFocused' window on the workspace. + + if we did not find a focus target, then set the current focused window to + nothing. + */ + if (f) + blackbox->setFocusedWindow(win); + else + blackbox->setFocusedWindow((BlackboxWindow *) 0); + + updateNetizenCurrentWorkspace(); +} + + +/* + * Set the _NET_CLIENT_LIST root window property. + */ +void BScreen::updateClientList(void) { + if (windowList.size() > 0) { + Window *windows = new Window[windowList.size()]; + Window *win_it = windows; + BlackboxWindowList::iterator it = windowList.begin(); + const BlackboxWindowList::iterator end = windowList.end(); + for (; it != end; ++it, ++win_it) + *win_it = (*it)->getClientWindow(); + xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window, + windows, windowList.size()); + delete [] windows; + } else + xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window, + 0, 0); + + updateStackingList(); +} + + +/* + * Set the _NET_CLIENT_LIST_STACKING root window property. + */ +void BScreen::updateStackingList(void) { + + BlackboxWindowList stack_order; + + /* + * Get the stacking order from all of the workspaces. + * We start with the current workspace so that the sticky windows will be + * in the right order on the current workspace. + * XXX: Do we need to have sticky windows in the list once for each workspace? + */ + getCurrentWorkspace()->appendStackOrder(stack_order); + for (unsigned int i = 0; i < getWorkspaceCount(); ++i) + if (i != getCurrentWorkspaceID()) + getWorkspace(i)->appendStackOrder(stack_order); + + if (stack_order.size() > 0) { + // set the client list atoms + Window *windows = new Window[stack_order.size()]; + Window *win_it = windows; + BlackboxWindowList::iterator it = stack_order.begin(), + end = stack_order.end(); + for (; it != end; ++it, ++win_it) + *win_it = (*it)->getClientWindow(); + xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking, + XAtom::window, windows, stack_order.size()); + delete [] windows; + } else + xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking, + XAtom::window, 0, 0); +} + + +void BScreen::addSystrayWindow(Window window) { + XGrabServer(blackbox->getXDisplay()); + + XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask); + systrayWindowList.push_back(window); + xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows, + XAtom::window, + &systrayWindowList[0], systrayWindowList.size()); + blackbox->saveSystrayWindowSearch(window, this); + + XUngrabServer(blackbox->getXDisplay()); +} + + +void BScreen::removeSystrayWindow(Window window) { + XGrabServer(blackbox->getXDisplay()); + + WindowList::iterator it = systrayWindowList.begin(); + const WindowList::iterator end = systrayWindowList.end(); + for (; it != end; ++it) + if (*it == window) { + systrayWindowList.erase(it); + xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows, + XAtom::window, + &systrayWindowList[0], systrayWindowList.size()); + blackbox->removeSystrayWindowSearch(window); + XSelectInput(blackbox->getXDisplay(), window, NoEventMask); + break; + } + + assert(it != end); // not a systray window + + XUngrabServer(blackbox->getXDisplay()); +} + + +void BScreen::manageWindow(Window w) { + // is the window a KDE systray window? + Window systray; + if (xatom->getValue(w, XAtom::kde_net_wm_system_tray_window_for, + XAtom::window, systray) && systray != None) { + addSystrayWindow(w); + return; + } + + // is the window a docking app + XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), w); + if (wmhint && (wmhint->flags & StateHint) && + wmhint->initial_state == WithdrawnState) { + slit->addClient(w); + return; + } + + new BlackboxWindow(blackbox, w, this); + + BlackboxWindow *win = blackbox->searchWindow(w); + if (! win) + return; + + if (win->isDesktop()) { + desktopWindowList.push_back(win->getFrameWindow()); + } else { // if (win->isNormal()) { + // don't list desktop windows as managed windows + windowList.push_back(win); + updateClientList(); + + if (win->isTopmost()) + specialWindowList.push_back(win->getFrameWindow()); + } + + XMapRequestEvent mre; + mre.window = w; + if (blackbox->isStartup() && win->isNormal()) win->restoreAttributes(); + win->mapRequestEvent(&mre); +} + + +void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) { + // is the window a KDE systray window? + Window systray; + if (xatom->getValue(w->getClientWindow(), + XAtom::kde_net_wm_system_tray_window_for, + XAtom::window, systray) && systray != None) { + removeSystrayWindow(w->getClientWindow()); + return; + } + + w->restore(remap); + + // Remove the modality so that its parent won't try to re-focus the window + if (w->isModal()) w->setModal(False); + + if (w->getWorkspaceNumber() != BSENTINEL && + w->getWindowNumber() != BSENTINEL) { + getWorkspace(w->getWorkspaceNumber())->removeWindow(w); + if (w->isStuck()) { + for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i) + if (i != w->getWorkspaceNumber()) + getWorkspace(i)->removeWindow(w, True); + } + } else if (w->isIconic()) + removeIcon(w); + + if (w->isDesktop()) { + WindowList::iterator it = desktopWindowList.begin(); + const WindowList::iterator end = desktopWindowList.end(); + for (; it != end; ++it) + if (*it == w->getFrameWindow()) { + desktopWindowList.erase(it); + break; + } + assert(it != end); // the window wasnt a desktop window? + } else { // if (w->isNormal()) { + // we don't list desktop windows as managed windows + windowList.remove(w); + updateClientList(); + + if (w->isTopmost()) { + WindowList::iterator it = specialWindowList.begin(); + const WindowList::iterator end = specialWindowList.end(); + for (; it != end; ++it) + if (*it == w->getFrameWindow()) { + specialWindowList.erase(it); + break; + } + assert(it != end); // the window wasnt a special window? + } + } + + if (blackbox->getFocusedWindow() == w) + blackbox->setFocusedWindow((BlackboxWindow *) 0); + + removeNetizen(w->getClientWindow()); + + /* + some managed windows can also be window group controllers. when + unmanaging such windows, we should also delete the window group. + */ + BWindowGroup *group = blackbox->searchGroup(w->getClientWindow()); + delete group; + + delete w; +} + + +void BScreen::addNetizen(Netizen *n) { + netizenList.push_back(n); + + n->sendWorkspaceCount(); + n->sendCurrentWorkspace(); + + WorkspaceList::iterator it = workspacesList.begin(); + const WorkspaceList::iterator end = workspacesList.end(); + for (; it != end; ++it) + (*it)->sendWindowList(*n); + + Window f = ((blackbox->getFocusedWindow()) ? + blackbox->getFocusedWindow()->getClientWindow() : None); + n->sendWindowFocus(f); +} + + +void BScreen::removeNetizen(Window w) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) { + if ((*it)->getWindowID() == w) { + delete *it; + netizenList.erase(it); + break; + } + } +} + + +void BScreen::updateWorkArea(void) { + if (workspacesList.size() > 0) { + unsigned long *dims = new unsigned long[4 * workspacesList.size()]; + for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) { + // XXX: this could be different for each workspace + const Rect &area = availableArea(); + dims[(i * 4) + 0] = area.x(); + dims[(i * 4) + 1] = area.y(); + dims[(i * 4) + 2] = area.width(); + dims[(i * 4) + 3] = area.height(); + } + xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal, + dims, 4 * workspacesList.size()); + delete [] dims; + } else + xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal, + 0, 0); +} + + +void BScreen::updateNetizenCurrentWorkspace(void) { + std::for_each(netizenList.begin(), netizenList.end(), + std::mem_fun(&Netizen::sendCurrentWorkspace)); +} + + +void BScreen::updateNetizenWorkspaceCount(void) { + xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops, + XAtom::cardinal, workspacesList.size()); + + updateWorkArea(); + + std::for_each(netizenList.begin(), netizenList.end(), + std::mem_fun(&Netizen::sendWorkspaceCount)); +} + + +void BScreen::updateNetizenWindowFocus(void) { + Window f = ((blackbox->getFocusedWindow()) ? + blackbox->getFocusedWindow()->getClientWindow() : None); + + xatom->setValue(getRootWindow(), XAtom::net_active_window, + XAtom::window, f); + + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) + (*it)->sendWindowFocus(f); +} + + +void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) { + (*it)->sendWindowAdd(w, p); + } +} + + +void BScreen::updateNetizenWindowDel(Window w) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) + (*it)->sendWindowDel(w); +} + + +void BScreen::updateNetizenWindowRaise(Window w) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) + (*it)->sendWindowRaise(w); +} + + +void BScreen::updateNetizenWindowLower(Window w) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) + (*it)->sendWindowLower(w); +} + + +void BScreen::updateNetizenConfigNotify(XEvent *e) { + NetizenList::iterator it = netizenList.begin(); + for (; it != netizenList.end(); ++it) + (*it)->sendConfigNotify(e); +} + + +void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) { + // the 13 represents the number of blackbox windows such as menus + int bbwins = 15; +#ifdef XINERAMA + ++bbwins; +#endif // XINERAMA +#ifdef XFT + ++bbwins; +#endif // XFT + + Window *session_stack = new + Window[(num + workspacesList.size() + rootmenuList.size() + + specialWindowList.size() + bbwins)]; + unsigned int i = 0, k = num; + + XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID()); + *(session_stack + i++) = iconmenu->getWindowID(); + + WorkspaceList::iterator wit = workspacesList.begin(); + const WorkspaceList::iterator w_end = workspacesList.end(); + for (; wit != w_end; ++wit) + *(session_stack + i++) = (*wit)->getMenu()->getWindowID(); + + *(session_stack + i++) = workspacemenu->getWindowID(); + + *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID(); + *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = configmenu->getWindowSnapmenu()->getWindowID(); + *(session_stack + i++) = configmenu->getEdgeSnapmenu()->getWindowID(); +#ifdef XINERAMA + *(session_stack + i++) = configmenu->getXineramamenu()->getWindowID(); +#endif // XINERAMA +#ifdef XFT + *(session_stack + i++) = configmenu->getXftmenu()->getWindowID(); +#endif // XFT + *(session_stack + i++) = configmenu->getWindowID(); + + *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID(); + *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = slit->getMenu()->getWindowID(); + + *(session_stack + i++) = + toolbar->getMenu()->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = toolbar->getMenu()->getWindowID(); + + RootmenuList::iterator rit = rootmenuList.begin(); + for (; rit != rootmenuList.end(); ++rit) + *(session_stack + i++) = (*rit)->getWindowID(); + *(session_stack + i++) = rootmenu->getWindowID(); + + if (toolbar->isOnTop()) + *(session_stack + i++) = toolbar->getWindowID(); + + if (slit->isOnTop()) + *(session_stack + i++) = slit->getWindowID(); + + WindowList::iterator sit, send = specialWindowList.end(); + for (sit = specialWindowList.begin(); sit != send; ++sit) + *(session_stack + i++) = *sit; + + while (k--) + *(session_stack + i++) = *(workspace_stack + k); + + XRestackWindows(blackbox->getXDisplay(), session_stack, i); + + delete [] session_stack; + + updateStackingList(); +} + + +void BScreen::lowerWindows(Window *workspace_stack, unsigned int num) { + assert(num > 0); // this would cause trouble in the XRaiseWindow call + + Window *session_stack = new Window[(num + desktopWindowList.size())]; + unsigned int i = 0, k = num; + + XLowerWindow(blackbox->getXDisplay(), workspace_stack[0]); + + while (k--) + *(session_stack + i++) = *(workspace_stack + k); + + WindowList::iterator dit = desktopWindowList.begin(); + const WindowList::iterator d_end = desktopWindowList.end(); + for (; dit != d_end; ++dit) + *(session_stack + i++) = *dit; + + XRestackWindows(blackbox->getXDisplay(), session_stack, i); + + delete [] session_stack; + + updateStackingList(); +} + + +void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id, + bool ignore_sticky) { + if (! w) return; + + if (wkspc_id == BSENTINEL) + wkspc_id = current_workspace->getID(); + + if (w->getWorkspaceNumber() == wkspc_id) + return; + + if (w->isIconic()) { + removeIcon(w); + getWorkspace(wkspc_id)->addWindow(w); + if (w->isStuck()) + for (unsigned int i = 0; i < getNumberOfWorkspaces(); ++i) + if (i != w->getWorkspaceNumber()) + getWorkspace(i)->addWindow(w, True); + } else if (ignore_sticky || ! w->isStuck()) { + if (w->isStuck()) + w->stick(); + getWorkspace(w->getWorkspaceNumber())->removeWindow(w); + getWorkspace(wkspc_id)->addWindow(w); + } + updateStackingList(); +} + + +void BScreen::propagateWindowName(const BlackboxWindow *bw) { + if (bw->isIconic()) { + iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle()); + iconmenu->update(); + } else { + Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu(); + clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle()); + clientmenu->update(); + + if (blackbox->getFocusedWindow() == bw) + toolbar->redrawWindowLabel(True); + } +} + + +void BScreen::nextFocus(void) const { + BlackboxWindow *focused = blackbox->getFocusedWindow(), + *next = focused; + + if (focused && + focused->getScreen()->getScreenNumber() == getScreenNumber() && + current_workspace->getCount() > 1) { + do { + next = current_workspace->getNextWindowInList(next); + } while (next != focused && ! next->setInputFocus()); + + if (next != focused) + current_workspace->raiseWindow(next); + } else if (current_workspace->getCount() > 0) { + next = current_workspace->getTopWindowOnStack(); + next->setInputFocus(); + current_workspace->raiseWindow(next); + } +} + + +void BScreen::prevFocus(void) const { + BlackboxWindow *focused = blackbox->getFocusedWindow(), + *next = focused; + + if (focused) { + // if window is not on this screen, ignore it + if (focused->getScreen()->getScreenNumber() != getScreenNumber()) + focused = (BlackboxWindow*) 0; + } + + if (focused && + focused->getScreen()->getScreenNumber() == getScreenNumber() && + current_workspace->getCount() > 1) { + // next is the next window to receive focus, current is a place holder + do { + next = current_workspace->getPrevWindowInList(next); + } while (next != focused && ! next->setInputFocus()); + + if (next != focused) + current_workspace->raiseWindow(next); + } else if (current_workspace->getCount() > 0) { + next = current_workspace->getTopWindowOnStack(); + next->setInputFocus(); + current_workspace->raiseWindow(next); + } +} + + +void BScreen::raiseFocus(void) const { + BlackboxWindow *focused = blackbox->getFocusedWindow(); + if (! focused) + return; + + // if on this Screen, raise it + if (focused->getScreen()->getScreenNumber() == getScreenNumber()) { + Workspace *workspace = getWorkspace(focused->getWorkspaceNumber()); + workspace->raiseWindow(focused); + } +} + + +void BScreen::InitMenu(void) { + if (rootmenu) { + rootmenuList.clear(); + + while (rootmenu->getCount()) + rootmenu->remove(0); + } else { + rootmenu = new Rootmenu(this); + } + bool defaultMenu = True; + + FILE *menu_file = (FILE *) 0; + const char *menu_filename = blackbox->getMenuFilename(); + + if (menu_filename) + if (! (menu_file = fopen(menu_filename, "r"))) + perror(menu_filename); + if (! menu_file) { // opening the menu file failed, try the default menu + menu_filename = DEFAULTMENU; + if (! (menu_file = fopen(menu_filename, "r"))) + perror(menu_filename); + } + + if (menu_file) { + if (feof(menu_file)) { + fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile, + "%s: Empty menu file"), + menu_filename); + } else { + char line[1024], label[1024]; + memset(line, 0, 1024); + memset(label, 0, 1024); + + while (fgets(line, 1024, menu_file) && ! feof(menu_file)) { + if (line[0] == '#') + continue; + + int i, key = 0, index = -1, len = strlen(line); + + for (i = 0; i < len; i++) { + if (line[i] == '[') index = 0; + else if (line[i] == ']') break; + else if (line[i] != ' ') + if (index++ >= 0) + key += tolower(line[i]); + } + + if (key == 517) { // [begin] + index = -1; + for (i = index; i < len; i++) { + if (line[i] == '(') index = 0; + else if (line[i] == ')') break; + else if (index++ >= 0) { + if (line[i] == '\\' && i < len - 1) i++; + label[index - 1] = line[i]; + } + } + + if (index == -1) index = 0; + label[index] = '\0'; + + rootmenu->setLabel(label); + defaultMenu = parseMenuFile(menu_file, rootmenu); + if (! defaultMenu) + blackbox->addMenuTimestamp(menu_filename); + break; + } + } + } + fclose(menu_file); + } + + if (defaultMenu) { + rootmenu->setInternalMenu(); + rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"), + BScreen::Execute, + i18n(ScreenSet, Screenxterm, "xterm")); + rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"), + BScreen::Restart); + rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"), + BScreen::Exit); + rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu, + "Openbox Menu")); + } +} + + +static +size_t string_within(char begin, char end, + const char *input, size_t start_at, size_t length, + char *output) { + bool parse = False; + size_t index = 0; + size_t i = start_at; + for (; i < length; ++i) { + if (input[i] == begin) { + parse = True; + } else if (input[i] == end) { + break; + } else if (parse) { + if (input[i] == '\\' && i < length - 1) i++; + output[index++] = input[i]; + } + } + + if (parse) + output[index] = '\0'; + else + output[0] = '\0'; + + return i; +} + + +bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) { + char line[1024], keyword[1024], label[1024], command[1024]; + bool done = False; + + while (! (done || feof(file))) { + memset(line, 0, 1024); + memset(label, 0, 1024); + memset(command, 0, 1024); + + if (! fgets(line, 1024, file)) + continue; + + if (line[0] == '#') // comment, skip it + continue; + + size_t line_length = strlen(line); + unsigned int key = 0; + + // get the keyword enclosed in []'s + size_t pos = string_within('[', ']', line, 0, line_length, keyword); + + if (keyword[0] == '\0') { // no keyword, no menu entry + continue; + } else { + size_t len = strlen(keyword); + for (size_t i = 0; i < len; ++i) { + if (keyword[i] != ' ') + key += tolower(keyword[i]); + } + } + + // get the label enclosed in ()'s + pos = string_within('(', ')', line, pos, line_length, label); + + // get the command enclosed in {}'s + pos = string_within('{', '}', line, pos, line_length, command); + + switch (key) { + case 311: // end + done = True; + + break; + + case 333: // nop + if (! *label) + label[0] = '\0'; + menu->insert(label); + + break; + + case 421: // exec + if (! (*label && *command)) { + fprintf(stderr, i18n(ScreenSet, ScreenEXECError, + "BScreen::parseMenuFile: [exec] error, " + "no menu label and/or command defined\n")); + continue; + } + + menu->insert(label, BScreen::Execute, command); + + break; + + case 442: // exit + if (! *label) { + fprintf(stderr, i18n(ScreenSet, ScreenEXITError, + "BScreen::parseMenuFile: [exit] error, " + "no menu label defined\n")); + continue; + } + + menu->insert(label, BScreen::Exit); + + break; + + case 561: { // style + if (! (*label && *command)) { + fprintf(stderr, + i18n(ScreenSet, ScreenSTYLEError, + "BScreen::parseMenuFile: [style] error, " + "no menu label and/or filename defined\n")); + continue; + } + + string style = expandTilde(command); + + menu->insert(label, BScreen::SetStyle, style.c_str()); + } + break; + + case 630: // config + if (! *label) { + fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError, + "BScreen::parseMenufile: [config] error, " + "no label defined")); + continue; + } + + menu->insert(label, configmenu); + + break; + + case 740: { // include + if (! *label) { + fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError, + "BScreen::parseMenuFile: [include] error, " + "no filename defined\n")); + continue; + } + + string newfile = expandTilde(label); + FILE *submenufile = fopen(newfile.c_str(), "r"); + + if (! submenufile) { + perror(newfile.c_str()); + continue; + } + + struct stat buf; + if (fstat(fileno(submenufile), &buf) || + ! S_ISREG(buf.st_mode)) { + fprintf(stderr, + i18n(ScreenSet, ScreenINCLUDEErrorReg, + "BScreen::parseMenuFile: [include] error: " + "'%s' is not a regular file\n"), newfile.c_str()); + break; + } + + if (! feof(submenufile)) { + if (! parseMenuFile(submenufile, menu)) + blackbox->addMenuTimestamp(newfile); + + fclose(submenufile); + } + } + + break; + + case 767: { // submenu + if (! *label) { + fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError, + "BScreen::parseMenuFile: [submenu] error, " + "no menu label defined\n")); + continue; + } + + Rootmenu *submenu = new Rootmenu(this); + + if (*command) + submenu->setLabel(command); + else + submenu->setLabel(label); + + parseMenuFile(file, submenu); + submenu->update(); + menu->insert(label, submenu); + rootmenuList.push_back(submenu); + } + + break; + + case 773: { // restart + if (! *label) { + fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError, + "BScreen::parseMenuFile: [restart] error, " + "no menu label defined\n")); + continue; + } + + if (*command) + menu->insert(label, BScreen::RestartOther, command); + else + menu->insert(label, BScreen::Restart); + } + + break; + + case 845: { // reconfig + if (! *label) { + fprintf(stderr, + i18n(ScreenSet, ScreenRECONFIGError, + "BScreen::parseMenuFile: [reconfig] error, " + "no menu label defined\n")); + continue; + } + + menu->insert(label, BScreen::Reconfigure); + } + + break; + + case 995: // stylesdir + case 1113: { // stylesmenu + bool newmenu = ((key == 1113) ? True : False); + + if (! *label || (! *command && newmenu)) { + fprintf(stderr, + i18n(ScreenSet, ScreenSTYLESDIRError, + "BScreen::parseMenuFile: [stylesdir/stylesmenu]" + " error, no directory defined\n")); + continue; + } + + char *directory = ((newmenu) ? command : label); + + string stylesdir = expandTilde(directory); + + struct stat statbuf; + + if (stat(stylesdir.c_str(), &statbuf) == -1) { + fprintf(stderr, + i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist, + "BScreen::parseMenuFile: [stylesdir/stylesmenu]" + " error, %s does not exist\n"), stylesdir.c_str()); + continue; + } + if (! S_ISDIR(statbuf.st_mode)) { + fprintf(stderr, + i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir, + "BScreen::parseMenuFile:" + " [stylesdir/stylesmenu] error, %s is not a" + " directory\n"), stylesdir.c_str()); + continue; + } + + Rootmenu *stylesmenu; + + if (newmenu) + stylesmenu = new Rootmenu(this); + else + stylesmenu = menu; + + DIR *d = opendir(stylesdir.c_str()); + struct dirent *p; + std::vector ls; + + while((p = readdir(d))) + ls.push_back(p->d_name); + + closedir(d); + + std::sort(ls.begin(), ls.end()); + + std::vector::iterator it = ls.begin(), + end = ls.end(); + for (; it != end; ++it) { + const string& fname = *it; + + if (fname[fname.size()-1] == '~') + continue; + + string style = stylesdir; + style += '/'; + style += fname; + + if (! stat(style.c_str(), &statbuf) && S_ISREG(statbuf.st_mode)) + stylesmenu->insert(fname, BScreen::SetStyle, style); + } + + stylesmenu->update(); + + if (newmenu) { + stylesmenu->setLabel(label); + menu->insert(label, stylesmenu); + rootmenuList.push_back(stylesmenu); + } + + blackbox->addMenuTimestamp(stylesdir); + } + break; + + case 1090: { // workspaces + if (! *label) { + fprintf(stderr, + i18n(ScreenSet, ScreenWORKSPACESError, + "BScreen:parseMenuFile: [workspaces] error, " + "no menu label defined\n")); + continue; + } + + menu->insert(label, workspacemenu); + } + break; + } + } + + return ((menu->getCount() == 0) ? True : False); +} + + +void BScreen::shutdown(void) { + XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask); + XSync(blackbox->getXDisplay(), False); + + while(! windowList.empty()) + unmanageWindow(windowList.front(), True); + + while(! desktopWindowList.empty()) { + BlackboxWindow *win = blackbox->searchWindow(desktopWindowList.front()); + assert(win); + unmanageWindow(win, True); + } + + slit->shutdown(); +} + + +void BScreen::showPosition(int x, int y) { + if (! geom_visible) { + XMoveResizeWindow(blackbox->getXDisplay(), geom_window, + (getWidth() - geom_w) / 2, + (getHeight() - geom_h) / 2, geom_w, geom_h); + XMapWindow(blackbox->getXDisplay(), geom_window); + XRaiseWindow(blackbox->getXDisplay(), geom_window); + + geom_visible = True; + } + + char label[1024]; + + sprintf(label, i18n(ScreenSet, ScreenPositionFormat, + "X: %4d x Y: %4d"), x, y); + + XClearWindow(blackbox->getXDisplay(), geom_window); + + resource.wstyle.font->drawString(geom_window, + resource.bevel_width, resource.bevel_width, + resource.wstyle.l_text_focus, + label); +} + + +void BScreen::showGeometry(unsigned int gx, unsigned int gy) { + if (! geom_visible) { + XMoveResizeWindow(blackbox->getXDisplay(), geom_window, + (getWidth() - geom_w) / 2, + (getHeight() - geom_h) / 2, geom_w, geom_h); + XMapWindow(blackbox->getXDisplay(), geom_window); + XRaiseWindow(blackbox->getXDisplay(), geom_window); + + geom_visible = True; + } + + char label[1024]; + + sprintf(label, i18n(ScreenSet, ScreenGeometryFormat, + "W: %4d x H: %4d"), gx, gy); + + XClearWindow(blackbox->getXDisplay(), geom_window); + + resource.wstyle.font->drawString(geom_window, + resource.bevel_width, resource.bevel_width, + resource.wstyle.l_text_focus, + label); +} + + +void BScreen::hideGeometry(void) { + if (geom_visible) { + XUnmapWindow(blackbox->getXDisplay(), geom_window); + geom_visible = False; + } +} + + +void BScreen::addStrut(Strut *strut) { + strutList.push_back(strut); +} + + +void BScreen::removeStrut(Strut *strut) { + strutList.remove(strut); +} + + +const Rect& BScreen::availableArea(void) const { + if (doFullMax()) + return getRect(); // return the full screen + return usableArea; +} + + +#ifdef XINERAMA +const RectList& BScreen::allAvailableAreas(void) const { + assert(isXineramaActive()); + assert(xineramaUsableArea.size() > 0); + fprintf(stderr, "1found x %d y %d w %d h %d\n", + xineramaUsableArea[0].x(), xineramaUsableArea[0].y(), + xineramaUsableArea[0].width(), xineramaUsableArea[0].height()); + return xineramaUsableArea; +} +#endif // XINERAMA + + +void BScreen::updateAvailableArea(void) { + Rect old_area = usableArea; + usableArea = getRect(); // reset to full screen + +#ifdef XINERAMA + // reset to the full areas + if (isXineramaActive()) + xineramaUsableArea = getXineramaAreas(); +#endif // XINERAMA + + /* these values represent offsets from the screen edge + * we look for the biggest offset on each edge and then apply them + * all at once + * do not be confused by the similarity to the names of Rect's members + */ + unsigned int current_left = 0, current_right = 0, current_top = 0, + current_bottom = 0; + + StrutList::const_iterator it = strutList.begin(), end = strutList.end(); + + for(; it != end; ++it) { + Strut *strut = *it; + if (strut->left > current_left) + current_left = strut->left; + if (strut->top > current_top) + current_top = strut->top; + if (strut->right > current_right) + current_right = strut->right; + if (strut->bottom > current_bottom) + current_bottom = strut->bottom; + } + + usableArea.setPos(current_left, current_top); + usableArea.setSize(usableArea.width() - (current_left + current_right), + usableArea.height() - (current_top + current_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 != usableArea) { + BlackboxWindowList::iterator it = windowList.begin(), + end = windowList.end(); + for (; it != end; ++it) + if ((*it)->isMaximized()) (*it)->remaximize(); + } + + updateWorkArea(); +} + + +Workspace* BScreen::getWorkspace(unsigned int index) const { + assert(index < workspacesList.size()); + return workspacesList[index]; +} + + +void BScreen::buttonPressEvent(const XButtonEvent *xbutton) { + if (xbutton->button == 1) { + if (! isRootColormapInstalled()) + image_control->installRootColormap(); + + if (workspacemenu->isVisible()) + workspacemenu->hide(); + + if (rootmenu->isVisible()) + rootmenu->hide(); + // mouse wheel up + } else if ((xbutton->button == 4 && resource.root_scroll == NormalScroll) || + (xbutton->button == 5 && resource.root_scroll == ReverseScroll)) { + if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1) + changeWorkspaceID(0); + else + changeWorkspaceID(getCurrentWorkspaceID() + 1); + // mouse wheel down + } else if ((xbutton->button == 5 && resource.root_scroll == NormalScroll) || + (xbutton->button == 4 && resource.root_scroll == ReverseScroll)) { + if (getCurrentWorkspaceID() == 0) + changeWorkspaceID(getWorkspaceCount() - 1); + else + changeWorkspaceID(getCurrentWorkspaceID() - 1); + } + + if (resource.root_menu_button > 0 && + xbutton->button == resource.root_menu_button) + showRootMenu(xbutton->x_root, xbutton->y_root); + else if (resource.workspace_menu_button > 0 && + xbutton->button == resource.workspace_menu_button) + showWorkspaceMenu(xbutton->x_root, xbutton->y_root); +} + + +void BScreen::showWorkspaceMenu(int x, int y) { + int mx = x - (workspacemenu->getWidth() / 2); + int my = y - (workspacemenu->getTitleHeight() / 2); + + if (mx < 0) mx = 0; + if (my < 0) my = 0; + + if (mx + workspacemenu->getWidth() > getWidth()) + mx = getWidth() - workspacemenu->getWidth() - getBorderWidth(); + + if (my + workspacemenu->getHeight() > getHeight()) + my = getHeight() - workspacemenu->getHeight() - getBorderWidth(); + + workspacemenu->move(mx, my); + + if (! workspacemenu->isVisible()) { + workspacemenu->removeParent(); + workspacemenu->show(); + } +} + + +void BScreen::showRootMenu(int x, int y) { + int mx = x - (rootmenu->getWidth() / 2); + int my = y - (rootmenu->getTitleHeight() / 2); + + if (mx < 0) mx = 0; + if (my < 0) my = 0; + + if (mx + rootmenu->getWidth() > getWidth()) + mx = getWidth() - rootmenu->getWidth() - getBorderWidth(); + + if (my + rootmenu->getHeight() > getHeight()) + my = getHeight() - rootmenu->getHeight() - getBorderWidth(); + + rootmenu->move(mx, my); + + if (! rootmenu->isVisible()) { + blackbox->checkMenu(); + rootmenu->show(); + } +} + + +void BScreen::propertyNotifyEvent(const XPropertyEvent *pe) { + if (pe->atom == xatom->getAtom(XAtom::net_desktop_names)) { + // _NET_WM_DESKTOP_NAMES + WorkspaceList::iterator it = workspacesList.begin(); + const WorkspaceList::iterator end = workspacesList.end(); + for (; it != end; ++it) { + (*it)->readName(); // re-read its name from the window property + workspacemenu->changeWorkspaceLabel((*it)->getID(), (*it)->getName()); + } + workspacemenu->update(); + toolbar->reconfigure(); + saveWorkspaceNames(); + } +} + + +void BScreen::toggleFocusModel(FocusModel model) { + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::ungrabButtons)); + + if (model == SloppyFocus) { + saveSloppyFocus(True); + } else { + // we're cheating here to save writing the config file 3 times + resource.auto_raise = False; + resource.click_raise = False; + saveSloppyFocus(False); + } + + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::grabButtons)); +} + +#ifdef BITMAPBUTTONS +void BScreen::readDatabaseMask(const string &rname, PixmapMask &pixmapMask, + const Configuration &style) { + string s; + int hx, hy; //ignored + int ret = BitmapOpenFailed; //default to failure. + + if (style.getValue(rname, s)) + { + if (s[0] != '/' && s[0] != '~') + { + std::string xbmFile = std::string("~/.openbox/buttons/") + s; + ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(), + expandTilde(xbmFile).c_str(), &pixmapMask.w, + &pixmapMask.h, &pixmapMask.mask, &hx, &hy); + } else + ret = XReadBitmapFile(blackbox->getXDisplay(), getRootWindow(), + expandTilde(s).c_str(), &pixmapMask.w, + &pixmapMask.h, &pixmapMask.mask, &hx, &hy); + + if (ret == BitmapSuccess) + return; + } + + pixmapMask.mask = None; + pixmapMask.w = pixmapMask.h = 0; +} +#endif // BITMAPSUCCESS + +BTexture BScreen::readDatabaseTexture(const string &rname, + const string &default_color, + const Configuration &style, + bool allowNoTexture) { + BTexture texture; + string s; + + if (style.getValue(rname, s)) + texture = BTexture(s); + else if (allowNoTexture) //no default + texture.setTexture(BTexture::NoTexture); + else + texture.setTexture(BTexture::Solid | BTexture::Flat); + + // associate this texture with this screen + texture.setDisplay(getBaseDisplay(), getScreenNumber()); + texture.setImageControl(image_control); + + if (texture.texture() != BTexture::NoTexture) { + texture.setColor(readDatabaseColor(rname + ".color", default_color, + style)); + texture.setColorTo(readDatabaseColor(rname + ".colorTo", default_color, + style)); + texture.setBorderColor(readDatabaseColor(rname + ".borderColor", + default_color, style)); + } + + return texture; +} + + +BColor BScreen::readDatabaseColor(const string &rname, + const string &default_color, + const Configuration &style) { + BColor color; + string s; + if (style.getValue(rname, s)) + color = BColor(s, getBaseDisplay(), getScreenNumber()); + else + color = BColor(default_color, getBaseDisplay(), getScreenNumber()); + return color; +} + + +BFont *BScreen::readDatabaseFont(const string &rbasename, + const Configuration &style) { + string fontname; + + string s; + +#ifdef XFT + int i; + if (style.getValue(rbasename + "xft.font", s) && + style.getValue(rbasename + "xft.size", i)) { + string family = s; + bool bold = False; + bool italic = False; + bool dropShadow = False; + + if (style.getValue(rbasename + "xft.flags", s)) { + if (s.find("bold") != string::npos) + bold = True; + if (s.find("italic") != string::npos) + italic = True; + if (s.find("shadow") != string::npos) + dropShadow = True; + } + + unsigned char offset = 1; + if (style.getValue(rbasename + "xft.shadow.offset", s)) { + offset = atoi(s.c_str()); //doesn't detect errors + if (offset > CHAR_MAX) + offset = 1; + } + + unsigned char tint = 0x40; + if (style.getValue(rbasename + "xft.shadow.tint", s)) { + tint = atoi(s.c_str()); + } + + + BFont *b = new BFont(blackbox->getXDisplay(), this, family, i, bold, + italic, dropShadow && resource.shadow_fonts, offset, + tint, resource.aa_fonts); + if (b->valid()) + return b; + else + delete b; // fall back to the normal X font stuff + } +#endif // XFT + + style.getValue(rbasename + "font", s); + // if this fails, a blank string will be used, which will cause the fallback + // font to load. + + BFont *b = new BFont(blackbox->getXDisplay(), this, s); + if (! b->valid()) + exit(2); // can't continue without a font + return b; +} diff --git a/src/screen.hh b/src/screen.hh new file mode 100644 index 00000000..53fdffdd --- /dev/null +++ b/src/screen.hh @@ -0,0 +1,432 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Screen.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Screen_hh +#define __Screen_hh + +extern "C" { +#include + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else // !TIME_WITH_SYS_TIME +# ifdef HAVE_SYS_TIME_H +# include +# else // !HAVE_SYS_TIME_H +# include +# endif // HAVE_SYS_TIME_H +#endif // TIME_WITH_SYS_TIME +} + +#include +#include + +#include "color.hh" +#include "texture.hh" +#include "image.hh" +#include "configmenu.hh" +#include "iconmenu.hh" +#include "netizen.hh" +#include "rootmenu.hh" +#include "timer.hh" +#include "workspace.hh" +#include "workspacemenu.hh" +#include "blackbox.hh" + +class Slit; // forward reference +class BFont; +class XAtom; +struct Strut; + +enum TextJustify { LeftJustify = 1, RightJustify, CenterJustify }; + +#ifdef BITMAPBUTTONS +struct PixmapMask { + Pixmap mask; + unsigned int w, h; +}; +#endif // BITMAPBUTTONS + +struct WindowStyle { + BColor l_text_focus, l_text_unfocus, b_pic_focus, + b_pic_unfocus; + BTexture f_focus, f_unfocus, t_focus, t_unfocus, l_focus, l_unfocus, + h_focus, h_unfocus, b_focus, b_unfocus, b_pressed, b_pressed_focus, + b_pressed_unfocus, g_focus, g_unfocus; + +#ifdef BITMAPBUTTONS + PixmapMask close_button, max_button, icon_button, stick_button; +#endif // BITMAPBUTTONS + BFont *font; + + TextJustify justify; + + void doJustify(const std::string &text, int &start_pos, + unsigned int max_length, unsigned int modifier) const; +}; + +struct ToolbarStyle { + BColor l_text, w_text, c_text, b_pic; + BTexture toolbar, label, window, button, pressed, clock; + +#ifdef BITMAPBUTTONS + PixmapMask left_button, right_button; +#endif // BITMAPBUTTONS + + BFont *font; + + TextJustify justify; + + void doJustify(const std::string &text, int &start_pos, + unsigned int max_length, unsigned int modifier) const; +}; + +struct MenuStyle { + BColor t_text, f_text, h_text, d_text; + BTexture title, frame, hilite; + +#ifdef BITMAPBUTTONS + PixmapMask bullet_image, tick_image; +#endif // BITMAPBUTTONS + + BFont *t_font, *f_font; + + TextJustify t_justify, f_justify; + int bullet, bullet_pos; +}; + +class BScreen : public ScreenInfo { +private: + bool root_colormap_installed, managed, geom_visible; + GC opGC; + Pixmap geom_pixmap; + Window geom_window; + + Blackbox *blackbox; + BImageControl *image_control; + Configmenu *configmenu; + Iconmenu *iconmenu; + Rootmenu *rootmenu; + Configuration *config; + XAtom *xatom; + + typedef std::list RootmenuList; + RootmenuList rootmenuList; + + typedef std::list NetizenList; + NetizenList netizenList; + BlackboxWindowList iconList, windowList; + + typedef std::vector WindowList; + WindowList specialWindowList, desktopWindowList, systrayWindowList; + + Slit *slit; + Toolbar *toolbar; + Workspace *current_workspace; + Workspacemenu *workspacemenu; + + unsigned int geom_w, geom_h; + unsigned long event_mask; + + Rect usableArea; +#ifdef XINERAMA + RectList xineramaUsableArea; +#endif // XINERAMA + + typedef std::list StrutList; + StrutList strutList; + typedef std::vector WorkspaceList; + WorkspaceList workspacesList; + + struct screen_resource { + WindowStyle wstyle; + ToolbarStyle tstyle; + MenuStyle mstyle; + + bool sloppy_focus, auto_raise, auto_edge_balance, ordered_dither, + opaque_move, full_max, focus_new, focus_last, click_raise, + allow_scroll_lock, hide_toolbar, window_corner_snap, aa_fonts, + ignore_shaded, ignore_maximized, workspace_warping, shadow_fonts; + + int snap_to_windows, snap_to_edges; + unsigned int snap_offset; + + BColor border_color; + + unsigned int workspaces; + int toolbar_placement, toolbar_width_percent, placement_policy, + snap_threshold, row_direction, col_direction, root_scroll, + resistance_size; + + unsigned int handle_width, bevel_width, frame_width, border_width, + resize_zones; + + unsigned int root_menu_button, workspace_menu_button; + +#ifdef HAVE_STRFTIME + std::string strftime_format; +#else // !HAVE_STRFTIME + bool clock24hour; + int date_format; +#endif // HAVE_STRFTIME + + } resource; + std::string screenstr; + + BScreen(const BScreen&); + BScreen& operator=(const BScreen&); + + bool parseMenuFile(FILE *file, Rootmenu *menu); + +#ifdef BITMAPBUTTONS + void readDatabaseMask(const std::string &rname, + PixmapMask &pixmapMask, + const Configuration &style); +#endif // BITMAPBUTTONS + + BTexture readDatabaseTexture(const std::string &rname, + const std::string &default_color, + const Configuration &style, + bool allowNoTexture = false); + BColor readDatabaseColor(const std::string &rname, + const std::string &default_color, + const Configuration &style); + BFont *readDatabaseFont(const std::string &rbasename, + const Configuration &style); + + void InitMenu(void); + void LoadStyle(void); + + void updateWorkArea(void); +public: + enum { WindowNoSnap = 0, WindowSnap, WindowResistance }; + enum { RowSmartPlacement = 1, ColSmartPlacement, CascadePlacement, + UnderMousePlacement, ClickMousePlacement, LeftRight, RightLeft, + TopBottom, BottomTop, IgnoreShaded, IgnoreMaximized }; + enum { RoundBullet = 1, TriangleBullet, SquareBullet, NoBullet }; + enum { Restart = 1, RestartOther, Exit, Shutdown, Execute, Reconfigure, + WindowShade, WindowIconify, WindowMaximize, WindowClose, WindowRaise, + WindowLower, WindowStick, WindowKill, SetStyle }; + enum FocusModel { SloppyFocus, ClickToFocus }; + enum RootScrollDirection { NoScroll = 0, NormalScroll, ReverseScroll }; + + BScreen(Blackbox *bb, unsigned int scrn); + ~BScreen(void); + + inline bool isSloppyFocus(void) const { return resource.sloppy_focus; } + inline bool isRootColormapInstalled(void) const + { return root_colormap_installed; } + inline bool doAutoRaise(void) const { return resource.auto_raise; } + inline bool doClickRaise(void) const { return resource.click_raise; } + inline bool isScreenManaged(void) const { return managed; } + inline bool doShadowFonts(void) const { return resource.shadow_fonts; } + inline bool doAAFonts(void) const { return resource.aa_fonts; } + inline bool doImageDither(void) const { return image_control->doDither(); } + inline bool doOrderedDither(void) const { return resource.ordered_dither; } + inline bool doOpaqueMove(void) const { return resource.opaque_move; } + inline bool doFullMax(void) const { return resource.full_max; } + inline bool doFocusNew(void) const { return resource.focus_new; } + inline bool doFocusLast(void) const { return resource.focus_last; } + inline bool doHideToolbar(void) const { return resource.hide_toolbar; } + inline int getWindowToWindowSnap(void) const + { return resource.snap_to_windows; } + inline int getWindowToEdgeSnap(void) const + { return resource.snap_to_edges; } + inline bool getWindowCornerSnap(void) const + { return resource.window_corner_snap; } + inline bool allowScrollLock(void) const { return resource.allow_scroll_lock; } + inline bool doWorkspaceWarping(void) const + { return resource.workspace_warping; } + inline int rootScrollDirection(void) const { return resource.root_scroll; } + inline unsigned int rootMenuButton(void) const + { return resource.root_menu_button; } + inline unsigned int workspaceMenuButton(void) const + { return resource.workspace_menu_button; } + + inline const GC &getOpGC(void) const { return opGC; } + + inline Blackbox *getBlackbox(void) { return blackbox; } + inline BColor *getBorderColor(void) { return &resource.border_color; } + inline BImageControl *getImageControl(void) { return image_control; } + inline Rootmenu *getRootmenu(void) { return rootmenu; } + + inline Slit *getSlit(void) { return slit; } + inline Toolbar *getToolbar(void) { return toolbar; } + + Workspace *getWorkspace(unsigned int index) const; + + inline Workspace *getCurrentWorkspace(void) { return current_workspace; } + + inline Workspacemenu *getWorkspacemenu(void) { return workspacemenu; } + + inline unsigned int getHandleWidth(void) const + { return resource.handle_width; } + inline unsigned int getBevelWidth(void) const + { return resource.bevel_width; } + inline unsigned int getFrameWidth(void) const + { return resource.frame_width; } + inline unsigned int getBorderWidth(void) const + { return resource.border_width; } + inline unsigned int getResizeZones(void) const + { return resource.resize_zones; } + inline bool getPlaceIgnoreShaded(void) const + { return resource.ignore_shaded; } + inline bool getPlaceIgnoreMaximized(void) const + { return resource.ignore_maximized; } + + inline unsigned int getCurrentWorkspaceID(void) const + { return current_workspace->getID(); } + inline unsigned int getWorkspaceCount(void) const + { return workspacesList.size(); } + inline unsigned int getIconCount(void) const { return iconList.size(); } + inline unsigned int getNumberOfWorkspaces(void) const + { return resource.workspaces; } + inline int getPlacementPolicy(void) const + { return resource.placement_policy; } + inline int getSnapOffset(void) const + { return resource.snap_offset; } + inline int getSnapThreshold(void) const + { return resource.snap_threshold; } + inline int getResistanceSize(void) const + { return resource.resistance_size; } + inline int getRowPlacementDirection(void) const + { return resource.row_direction; } + inline int getColPlacementDirection(void) const + { return resource.col_direction; } + + void changeWorkspaceCount(unsigned int new_count); + + inline void setRootColormapInstalled(bool r) { root_colormap_installed = r; } + void saveSloppyFocus(bool s); + void saveAutoRaise(bool a); + void saveClickRaise(bool c); + void saveWorkspaces(unsigned int w); + void savePlacementPolicy(int p); + void saveRowPlacementDirection(int d); + void saveColPlacementDirection(int d); + void saveSnapThreshold(int t); + void saveSnapOffset(int o); + void saveResistanceSize(int s); + void saveImageDither(bool d); + void saveShadowFonts(bool f); + void saveAAFonts(bool f); + void saveOpaqueMove(bool o); + void saveFullMax(bool f); + void saveFocusNew(bool f); + void saveFocusLast(bool f); + void saveHideToolbar(bool h); + void saveWindowToEdgeSnap(int s); + void saveWindowToWindowSnap(int s); + void saveWindowCornerSnap(bool s); + void saveResizeZones(unsigned int z); + void savePlaceIgnoreShaded(bool i); + void savePlaceIgnoreMaximized(bool i); + void saveAllowScrollLock(bool a); + void saveWorkspaceWarping(bool w); + void saveRootScrollDirection(int d); + void saveRootMenuButton(unsigned int b); + void saveWorkspaceMenuButton(unsigned int b); + inline void iconUpdate(void) { iconmenu->update(); } + +#ifdef HAVE_STRFTIME + inline const char *getStrftimeFormat(void) + { return resource.strftime_format.c_str(); } + void saveStrftimeFormat(const std::string& format); +#else // !HAVE_STRFTIME + inline int getDateFormat(void) { return resource.date_format; } + inline void saveDateFormat(int f); + inline bool isClock24Hour(void) { return resource.clock24hour; } + inline void saveClock24Hour(bool c); +#endif // HAVE_STRFTIME + + inline WindowStyle *getWindowStyle(void) { return &resource.wstyle; } + inline MenuStyle *getMenuStyle(void) { return &resource.mstyle; } + inline ToolbarStyle *getToolbarStyle(void) { return &resource.tstyle; } + + BlackboxWindow *getIcon(unsigned int index); + + // allAvailableAreas should be used whenever possible instead of this function + // as then Xinerama will work correctly. + const Rect& availableArea(void) const; +#ifdef XINERAMA + const RectList& allAvailableAreas(void) const; +#endif // XINERAMA + void updateAvailableArea(void); + void addStrut(Strut *strut); + void removeStrut(Strut *strut); + + unsigned int addWorkspace(void); + unsigned int removeLastWorkspace(void); + void changeWorkspaceID(unsigned int id); + void saveWorkspaceNames(void); + + void addNetizen(Netizen *n); + void removeNetizen(Window w); + + void addSystrayWindow(Window window); + void removeSystrayWindow(Window window); + + void addIcon(BlackboxWindow *w); + void removeIcon(BlackboxWindow *w); + + void updateClientList(void); + void updateStackingList(void); + void manageWindow(Window w); + void unmanageWindow(BlackboxWindow *w, bool remap); + void raiseWindows(Window *workspace_stack, unsigned int num); + void lowerWindows(Window *workspace_stack, unsigned int num); + void reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id, + bool ignore_sticky); + void propagateWindowName(const BlackboxWindow *bw); + void prevFocus(void) const; + void nextFocus(void) const; + void raiseFocus(void) const; + void load_rc(void); + void save_rc(void); + void reconfigure(void); + void toggleFocusModel(FocusModel model); + void rereadMenu(void); + void shutdown(void); + void showPosition(int x, int y); + void showGeometry(unsigned int gx, unsigned int gy); + void hideGeometry(void); + + void showWorkspaceMenu(int x, int y); + void showRootMenu(int x, int y); + + void buttonPressEvent(const XButtonEvent *xbutton); + void propertyNotifyEvent(const XPropertyEvent *pe); + + void updateNetizenCurrentWorkspace(void); + void updateNetizenWorkspaceCount(void); + void updateNetizenWindowFocus(void); + void updateNetizenWindowAdd(Window w, unsigned long p); + void updateNetizenWindowDel(Window w); + void updateNetizenConfigNotify(XEvent *e); + void updateNetizenWindowRaise(Window w); + void updateNetizenWindowLower(Window w); +}; + + +#endif // __Screen_hh diff --git a/src/texture.cc b/src/texture.cc new file mode 100644 index 00000000..3185b2c9 --- /dev/null +++ b/src/texture.cc @@ -0,0 +1,204 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Texture.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +#ifdef HAVE_CTYPE_H +#include +#endif +} + +#include + +#include "texture.hh" +#include "basedisplay.hh" +#include "image.hh" +#include "screen.hh" +#include "blackbox.hh" + +using std::string; + + +BTexture::BTexture(const BaseDisplay * const _display, + unsigned int _screen, BImageControl* _ctrl) + : c(_display, _screen), ct(_display, _screen), + lc(_display, _screen), sc(_display, _screen), bc(_display, _screen), t(0), + dpy(_display), ctrl(_ctrl), scrn(_screen) { } + + +BTexture::BTexture(const string &d, const BaseDisplay * const _display, + unsigned int _screen, BImageControl* _ctrl) + : c(_display, _screen), ct(_display, _screen), + lc(_display, _screen), sc(_display, _screen), bc(_display, _screen), t(0), + dpy(_display), ctrl(_ctrl), scrn(_screen) { + setDescription(d); +} + + +void BTexture::setColor(const BColor &cc) { + c = cc; + c.setDisplay(display(), screen()); + + unsigned char r, g, b, rr, gg, bb; + + // calculate the light color + r = c.red(); + g = c.green(); + b = c.blue(); + rr = r + (r >> 1); + gg = g + (g >> 1); + bb = b + (b >> 1); + if (rr < r) rr = ~0; + if (gg < g) gg = ~0; + if (bb < b) bb = ~0; + lc = BColor(rr, gg, bb, display(), screen()); + + // calculate the shadow color + r = c.red(); + g = c.green(); + b = c.blue(); + rr = (r >> 2) + (r >> 1); + gg = (g >> 2) + (g >> 1); + bb = (b >> 2) + (b >> 1); + if (rr > r) rr = 0; + if (gg > g) gg = 0; + if (bb > b) bb = 0; + sc = BColor(rr, gg, bb, display(), screen()); +} + + +void BTexture::setDescription(const string &d) { + descr.erase(); + descr.reserve(d.length()); + + string::const_iterator it = d.begin(), end = d.end(); + for (; it != end; ++it) + descr += tolower(*it); + + if (descr.find("parentrelative") != string::npos) { + setTexture(BTexture::Parent_Relative); + } else { + setTexture(0); + + if (descr.find("gradient") != string::npos) { + addTexture(BTexture::Gradient); + if (descr.find("crossdiagonal") != string::npos) + addTexture(BTexture::CrossDiagonal); + else if (descr.find("rectangle") != string::npos) + addTexture(BTexture::Rectangle); + else if (descr.find("pyramid") != string::npos) + addTexture(BTexture::Pyramid); + else if (descr.find("pipecross") != string::npos) + addTexture(BTexture::PipeCross); + else if (descr.find("elliptic") != string::npos) + addTexture(BTexture::Elliptic); + else if (descr.find("horizontal") != string::npos) + addTexture(BTexture::Horizontal); + else if (descr.find("vertical") != string::npos) + addTexture(BTexture::Vertical); + else + addTexture(BTexture::Diagonal); + } else { + addTexture(BTexture::Solid); + } + + if (descr.find("sunken") != string::npos) + addTexture(BTexture::Sunken); + else if (descr.find("flat") != string::npos) + addTexture(BTexture::Flat); + else + addTexture(BTexture::Raised); + + if (texture() & BTexture::Flat) { + if (descr.find("border") != string::npos) + addTexture(BTexture::Border); + } else { + if (descr.find("bevel2") != string::npos) + addTexture(BTexture::Bevel2); + else + addTexture(BTexture::Bevel1); + } + + if (descr.find("interlaced") != string::npos) + addTexture(BTexture::Interlaced); + } +} + +void BTexture::setDisplay(const BaseDisplay * const _display, + const unsigned int _screen) { + if (_display == display() && _screen == screen()) { + // nothing to do + return; + } + + dpy = _display; + scrn = _screen; + c.setDisplay(_display, _screen); + ct.setDisplay(_display, _screen); + lc.setDisplay(_display, _screen); + sc.setDisplay(_display, _screen); + bc.setDisplay(_display, _screen); +} + + +BTexture& BTexture::operator=(const BTexture &tt) { + c = tt.c; + ct = tt.ct; + lc = tt.lc; + sc = tt.sc; + bc = tt.bc; + descr = tt.descr; + t = tt.t; + dpy = tt.dpy; + scrn = tt.scrn; + ctrl = tt.ctrl; + + return *this; +} + + +Pixmap BTexture::render(const unsigned int width, const unsigned int height, + const Pixmap old) { + assert(display() != 0); + assert(texture() != BTexture::NoTexture); + + if (texture() == (BTexture::Flat | BTexture::Solid)) + return None; + if (texture() == BTexture::Parent_Relative) + return ParentRelative; + + if (screen() == ~(0u)) + scrn = DefaultScreen(display()->getXDisplay()); + + assert(ctrl != 0); + Pixmap ret = ctrl->renderImage(width, height, *this); + + if (old) + ctrl->removeImage(old); + + return ret; +} diff --git a/src/texture.hh b/src/texture.hh new file mode 100644 index 00000000..4133e485 --- /dev/null +++ b/src/texture.hh @@ -0,0 +1,114 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Texture.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Bradley T Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef TEXTURE_HH +#define TEXTURE_HH + +#include "color.hh" +#include "util.hh" +class BImageControl; + +#include + +class BTexture { +public: + enum Type { + // No texture + NoTexture = (0), + // bevel options + Flat = (1l<<0), + Sunken = (1l<<1), + Raised = (1l<<2), + // textures + Solid = (1l<<3), + Gradient = (1l<<4), + // gradients + Horizontal = (1l<<5), + Vertical = (1l<<6), + Diagonal = (1l<<7), + CrossDiagonal = (1l<<8), + Rectangle = (1l<<9), + Pyramid = (1l<<10), + PipeCross = (1l<<11), + Elliptic = (1l<<12), + // bevel types + Bevel1 = (1l<<13), + Bevel2 = (1l<<14), + // flat border + Border = (1l<<15), + // inverted image + Invert = (1l<<16), + // parent relative image + Parent_Relative = (1l<<17), + // fake interlaced image + Interlaced = (1l<<18) + }; + + BTexture(const BaseDisplay * const _display = 0, + unsigned int _screen = ~(0u), BImageControl* _ctrl = 0); + BTexture(const std::string &_description, + const BaseDisplay * const _display = 0, + unsigned int _screen = ~(0u), BImageControl* _ctrl = 0); + + void setColor(const BColor &_color); + void setColorTo(const BColor &_colorTo) { ct = _colorTo; } + void setBorderColor(const BColor &_borderColor) { bc = _borderColor; } + + const BColor &color(void) const { return c; } + const BColor &colorTo(void) const { return ct; } + const BColor &lightColor(void) const { return lc; } + const BColor &shadowColor(void) const { return sc; } + const BColor &borderColor(void) const { return bc; } + + unsigned long texture(void) const { return t; } + void setTexture(const unsigned long _texture) { t = _texture; } + void addTexture(const unsigned long _texture) { t |= _texture; } + + BTexture &operator=(const BTexture &tt); + inline bool operator==(const BTexture &tt) + { return (c == tt.c && ct == tt.ct && lc == tt.lc && + sc == tt.sc && t == tt.t); } + inline bool operator!=(const BTexture &tt) + { return (! operator==(tt)); } + + const BaseDisplay *display(void) const { return dpy; } + unsigned int screen(void) const { return scrn; } + void setDisplay(const BaseDisplay * const _display, + const unsigned int _screen); + void setImageControl(BImageControl* _ctrl) { ctrl = _ctrl; } + const std::string &description(void) const { return descr; } + void setDescription(const std::string &d); + + Pixmap render(const unsigned int width, const unsigned int height, + const Pixmap old = 0); + +private: + BColor c, ct, lc, sc, bc; + std::string descr; + unsigned long t; + const BaseDisplay *dpy; + BImageControl *ctrl; + unsigned int scrn; +}; + +#endif // TEXTURE_HH diff --git a/src/timer.cc b/src/timer.cc new file mode 100644 index 00000000..8bf91250 --- /dev/null +++ b/src/timer.cc @@ -0,0 +1,111 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// Timer.cc for Blackbox - An X11 Window Manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "basedisplay.hh" +#include "timer.hh" +#include "util.hh" + +BTimer::BTimer(TimerQueueManager *m, TimeoutHandler *h) { + manager = m; + handler = h; + + recur = timing = False; +} + + +BTimer::~BTimer(void) { + if (timing) stop(); +} + + +void BTimer::setTimeout(long t) { + _timeout.tv_sec = t / 1000; + _timeout.tv_usec = t % 1000; + _timeout.tv_usec *= 1000; +} + + +void BTimer::setTimeout(const timeval &t) { + _timeout.tv_sec = t.tv_sec; + _timeout.tv_usec = t.tv_usec; +} + + +void BTimer::start(void) { + gettimeofday(&_start, 0); + + if (! timing) { + timing = True; + manager->addTimer(this); + } +} + + +void BTimer::stop(void) { + timing = False; + + manager->removeTimer(this); +} + + +void BTimer::halt(void) { + timing = False; +} + + +void BTimer::fireTimeout(void) { + if (handler) + handler->timeout(); +} + + +timeval BTimer::timeRemaining(const timeval &tm) const { + timeval ret = endpoint(); + + ret.tv_sec -= tm.tv_sec; + ret.tv_usec -= tm.tv_usec; + + return normalizeTimeval(ret); +} + + +timeval BTimer::endpoint(void) const { + timeval ret; + + ret.tv_sec = _start.tv_sec + _timeout.tv_sec; + ret.tv_usec = _start.tv_usec + _timeout.tv_usec; + + return normalizeTimeval(ret); +} + + +bool BTimer::shouldFire(const timeval &tm) const { + timeval end = endpoint(); + + return ! ((tm.tv_sec < end.tv_sec) || + (tm.tv_sec == end.tv_sec && tm.tv_usec < end.tv_usec)); +} diff --git a/src/timer.hh b/src/timer.hh new file mode 100644 index 00000000..f13ad4dc --- /dev/null +++ b/src/timer.hh @@ -0,0 +1,131 @@ +// -*- mode: C++; indent-tabs-mode: nil; -*- +// Timer.hh for Blackbox - An X11 Window Manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef _BLACKBOX_Timer_hh +#define _BLACKBOX_Timer_hh + +extern "C" { +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else // !TIME_WITH_SYS_TIME +# ifdef HAVE_SYS_TIME_H +# include +# else // !HAVE_SYS_TIME_H +# include +# endif // HAVE_SYS_TIME_H +#endif // TIME_WITH_SYS_TIME +} + +// forward declaration +class TimerQueueManager; + +class TimeoutHandler { +public: + virtual void timeout(void) = 0; +}; + +class BTimer { +private: + TimerQueueManager *manager; + TimeoutHandler *handler; + bool timing, recur; + + timeval _start, _timeout; + + BTimer(const BTimer&); + BTimer& operator=(const BTimer&); + +public: + BTimer(TimerQueueManager *m, TimeoutHandler *h); + virtual ~BTimer(void); + + void fireTimeout(void); + + inline bool isTiming(void) const { return timing; } + inline bool isRecurring(void) const { return recur; } + + inline const timeval &getTimeout(void) const { return _timeout; } + inline const timeval &getStartTime(void) const { return _start; } + + timeval timeRemaining(const timeval &tm) const; + bool shouldFire(const timeval &tm) const; + timeval endpoint(void) const; + + inline void recurring(bool b) { recur = b; } + + void setTimeout(long t); + void setTimeout(const timeval &t); + + void start(void); // manager acquires timer + void stop(void); // manager releases timer + void halt(void); // halts the timer + + bool operator<(const BTimer& other) const + { return shouldFire(other.endpoint()); } +}; + + +#include +#include + +template +class _timer_queue: protected std::priority_queue<_Tp, _Sequence, _Compare> { +public: + typedef std::priority_queue<_Tp, _Sequence, _Compare> _Base; + + _timer_queue(void): _Base() {} + ~_timer_queue(void) {} + + void release(const _Tp& value) { + c.erase(std::remove(c.begin(), c.end(), value), c.end()); + // after removing the item we need to make the heap again + std::make_heap(c.begin(), c.end(), comp); + } + bool empty(void) const { return _Base::empty(); } + size_t size(void) const { return _Base::size(); } + void push(const _Tp& value) { _Base::push(value); } + void pop(void) { _Base::pop(); } + const _Tp& top(void) const { return _Base::top(); } +private: + // no copying! + _timer_queue(const _timer_queue&) {} + _timer_queue& operator=(const _timer_queue&) {} +}; + +struct TimerLessThan { + bool operator()(const BTimer* const l, const BTimer* const r) const { + return *r < *l; + } +}; + +#include +typedef _timer_queue, TimerLessThan> TimerQueue; + +class TimerQueueManager { +public: + virtual void addTimer(BTimer* timer) = 0; + virtual void removeTimer(BTimer* timer) = 0; +}; + +#endif // _BLACKBOX_Timer_hh diff --git a/src/util.cc b/src/util.cc new file mode 100644 index 00000000..bd5703bc --- /dev/null +++ b/src/util.cc @@ -0,0 +1,254 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Util.cc for Blackbox - an X11 Window manager +// Copyright (c) 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else // !TIME_WITH_SYS_TIME +# ifdef HAVE_SYS_TIME_H +# include +# else // !HAVE_SYS_TIME_H +# include +# endif // HAVE_SYS_TIME_H +#endif // TIME_WITH_SYS_TIME +#ifdef HAVE_UNISTD_H +#include +#endif // HAVE_UNISTD_H +#if defined(HAVE_PROCESS_H) && defined(__EMX__) +# include +#endif // HAVE_PROCESS_H __EMX__ + +#include +} + +#include + +#include "util.hh" + +using std::string; + + +void Rect::setX(int x) { + _x2 += x - _x1; + _x1 = x; +} + + +void Rect::setY(int y) +{ + _y2 += y - _y1; + _y1 = y; +} + + +void Rect::setPos(int x, int y) { + _x2 += x - _x1; + _x1 = x; + _y2 += y - _y1; + _y1 = y; +} + + +void Rect::setWidth(unsigned int w) { + _x2 = w + _x1 - 1; +} + + +void Rect::setHeight(unsigned int h) { + _y2 = h + _y1 - 1; +} + + +void Rect::setSize(unsigned int w, unsigned int h) { + _x2 = w + _x1 - 1; + _y2 = h + _y1 - 1; +} + + +void Rect::setRect(int x, int y, unsigned int w, unsigned int h) { + *this = Rect(x, y, w, h); +} + + +void Rect::setCoords(int l, int t, int r, int b) { + _x1 = l; + _y1 = t; + _x2 = r; + _y2 = b; +} + + +Rect Rect::operator|(const Rect &a) const { + Rect b; + + b._x1 = std::min(_x1, a._x1); + b._y1 = std::min(_y1, a._y1); + b._x2 = std::max(_x2, a._x2); + b._y2 = std::max(_y2, a._y2); + + return b; +} + + +Rect Rect::operator&(const Rect &a) const { + Rect b; + + b._x1 = std::max(_x1, a._x1); + b._y1 = std::max(_y1, a._y1); + b._x2 = std::min(_x2, a._x2); + b._y2 = std::min(_y2, a._y2); + + return b; +} + + +bool Rect::intersects(const Rect &a) const { + return std::max(_x1, a._x1) <= std::min(_x2, a._x2) && + std::max(_y1, a._y1) <= std::min(_y2, a._y2); +} + + +bool Rect::contains(int x, int y) const { + return x >= _x1 && x <= _x2 && + y >= _y1 && y <= _y2; +} + + +bool Rect::contains(const Rect& a) const { + return a._x1 >= _x1 && a._x2 <= _x2 && + a._y1 >= _y1 && a._y2 <= _y2; +} + + +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(); + int ret = putenv(const_cast(displaystring.c_str())); + assert(ret != -1); + 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__ +} + + +#ifndef HAVE_BASENAME +string basename (const string& path) { + string::size_type slash = path.rfind('/'); + if (slash == string::npos) + return path; + return path.substr(slash+1); +} +#endif // HAVE_BASENAME + + +string textPropertyToString(Display *display, XTextProperty& text_prop) { + string ret; + + if (text_prop.value && text_prop.nitems > 0) { + if (text_prop.encoding == XA_STRING) { + ret = (char *) text_prop.value; + } else { + text_prop.nitems = strlen((char *) text_prop.value); + + char **list; + int num; + if (XmbTextPropertyToTextList(display, &text_prop, + &list, &num) == Success && + num > 0 && *list) { + ret = *list; + XFreeStringList(list); + } + } + } + + return ret; +} + + +timeval normalizeTimeval(const timeval &tm) { + timeval ret = tm; + + while (ret.tv_usec < 0) { + if (ret.tv_sec > 0) { + --ret.tv_sec; + ret.tv_usec += 1000000; + } else { + ret.tv_usec = 0; + } + } + + if (ret.tv_usec >= 1000000) { + ret.tv_sec += ret.tv_usec / 1000000; + ret.tv_usec %= 1000000; + } + + if (ret.tv_sec < 0) ret.tv_sec = 0; + + return ret; +} + + +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; +} diff --git a/src/util.hh b/src/util.hh new file mode 100644 index 00000000..40a2254a --- /dev/null +++ b/src/util.hh @@ -0,0 +1,120 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Util.cc for Blackbox - an X11 Window manager +// Copyright (c) 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef _BLACKBOX_UTIL_HH +#define _BLACKBOX_UTIL_HH + +#include +#include + +#include +#include + +class Rect { +public: + inline Rect(void) : _x1(0), _y1(0), _x2(0), _y2(0) { } + inline Rect(int __x, int __y, unsigned int __w, unsigned int __h) + : _x1(__x), _y1(__y), _x2(__w + __x - 1), _y2(__h + __y - 1) { } + inline explicit Rect(const XRectangle& xrect) + : _x1(xrect.x), _y1(xrect.y), _x2(xrect.width + xrect.x - 1), + _y2(xrect.height + xrect.y - 1) { } + + inline int left(void) const { return _x1; } + inline int top(void) const { return _y1; } + inline int right(void) const { return _x2; } + inline int bottom(void) const { return _y2; } + + inline int x(void) const { return _x1; } + inline int y(void) const { return _y1; } + void setX(int __x); + void setY(int __y); + void setPos(int __x, int __y); + + inline unsigned int width(void) const { return _x2 - _x1 + 1; } + inline unsigned int height(void) const { return _y2 - _y1 + 1; } + void setWidth(unsigned int __w); + void setHeight(unsigned int __h); + void setSize(unsigned int __w, unsigned int __h); + + void setRect(int __x, int __y, unsigned int __w, unsigned int __h); + + void setCoords(int __l, int __t, int __r, int __b); + + inline bool operator==(const Rect &a) + { return _x1 == a._x1 && _y1 == a._y1 && _x2 == a._x2 && _y2 == a._y2; } + inline bool operator!=(const Rect &a) { return ! operator==(a); } + + Rect operator|(const Rect &a) const; + Rect operator&(const Rect &a) const; + inline Rect &operator|=(const Rect &a) { *this = *this | a; return *this; } + inline Rect &operator&=(const Rect &a) { *this = *this & a; return *this; } + + inline bool valid(void) const { return _x2 > _x1 && _y2 > _y1; } + + bool intersects(const Rect &a) const; + bool contains(int __x, int __y) const; + bool contains(const Rect &a) const; + +private: + int _x1, _y1, _x2, _y2; +}; + +typedef std::vector RectList; + +struct Strut { + unsigned int top, bottom, left, right; + + Strut(void): top(0), bottom(0), left(0), right(0) {} +}; + +/* XXX: this needs autoconf help */ +const unsigned int BSENTINEL = 65535; + +std::string expandTilde(const std::string& s); + +void bexec(const std::string& command, const std::string& displaystring); + +#ifndef HAVE_BASENAME +std::string basename(const std::string& path); +#endif + +std::string textPropertyToString(Display *display, XTextProperty& text_prop); + +struct timeval; // forward declare to avoid the header +timeval normalizeTimeval(const timeval &tm); + +struct PointerAssassin { + template + inline void operator()(const T ptr) const { + delete ptr; + } +}; + +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); } + +#endif diff --git a/src/window.cc b/src/window.cc new file mode 100644 index 00000000..206e66c6 --- /dev/null +++ b/src/window.cc @@ -0,0 +1,4356 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Window.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000, 2002 Brad Hughes +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +#include + +#ifdef HAVE_STRING_H +# include +#endif // HAVE_STRING_H + +#ifdef DEBUG +# ifdef HAVE_STDIO_H +# include +# endif // HAVE_STDIO_H +#endif // DEBUG + +#ifdef HAVE_STDLIB_H +# include +#endif // HAVE_STDLIB_H +} + +#include "blackbox.hh" +#include "clientmenu.hh" +#include "font.hh" +#include "gccache.hh" +#include "iconmenu.hh" +#include "image.hh" +#include "screen.hh" +#include "toolbar.hh" +#include "util.hh" +#include "window.hh" +#include "windowmenu.hh" +#include "workspace.hh" +#include "slit.hh" + +using std::string; +using std::abs; + +/* + * Initializes the class with default values/the window's set initial values. + */ +BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { + // fprintf(stderr, "BlackboxWindow size: %d bytes\n", + // sizeof(BlackboxWindow)); + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w); +#endif // DEBUG + + /* + set timer to zero... it is initialized properly later, so we check + if timer is zero in the destructor, and assume that the window is not + fully constructed if timer is zero... + */ + timer = 0; + blackbox = b; + client.window = w; + screen = s; + xatom = blackbox->getXAtom(); + + if (! validateClient()) { + delete this; + return; + } + + // fetch client size and placement + XWindowAttributes wattrib; + if (! XGetWindowAttributes(blackbox->getXDisplay(), + client.window, &wattrib) || + ! wattrib.screen || wattrib.override_redirect) { +#ifdef DEBUG + fprintf(stderr, + "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n"); +#endif // DEBUG + + delete this; + return; + } + + // set the eventmask early in the game so that we make sure we get + // all the events we are interested in + XSetWindowAttributes attrib_set; + attrib_set.event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; + attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask; + XChangeWindowAttributes(blackbox->getXDisplay(), client.window, + CWEventMask|CWDontPropagate, &attrib_set); + + flags.moving = flags.resizing = flags.shaded = flags.visible = + flags.iconic = flags.focused = flags.stuck = flags.modal = + flags.send_focus_message = flags.shaped = flags.skip_taskbar = + flags.skip_pager = flags.fullscreen = False; + flags.maximized = 0; + + blackbox_attrib.workspace = window_number = BSENTINEL; + + blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l; + blackbox_attrib.decoration = DecorNormal; + blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; + blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; + + frame.border_w = 1; + frame.window = frame.plate = frame.title = frame.handle = None; + frame.close_button = frame.iconify_button = frame.maximize_button = + frame.stick_button = None; + frame.right_grip = frame.left_grip = None; + + frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel = + frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel = + frame.ubutton_pixel = frame.fbutton_pixel = frame.uborder_pixel = + frame.fborder_pixel = frame.ugrip_pixel = frame.fgrip_pixel = 0; + frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None; + frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None; + frame.ugrip = frame.fgrip = None; + + functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize; + mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border | + Decor_Iconify | Decor_Maximize; + + client.normal_hint_flags = 0; + client.window_group = None; + client.transient_for = 0; + + current_state = NormalState; + + windowmenu = 0; + + /* + set the initial size and location of client window (relative to the + _root window_). This position is the reference point used with the + window's gravity to find the window's initial position. + */ + client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height); + client.old_bw = wattrib.border_width; + + lastButtonPressTime = 0; + + timer = new BTimer(blackbox, this); + timer->setTimeout(blackbox->getAutoRaiseDelay()); + + // get size, aspect, minimum/maximum size and other hints set by the + // client + + if (! getBlackboxHints()) + getNetWMHints(); + + getWMProtocols(); + getWMHints(); + getWMNormalHints(); + + frame.window = createToplevelWindow(); + + blackbox->saveWindowSearch(frame.window, this); + + frame.plate = createChildWindow(frame.window, ExposureMask); + blackbox->saveWindowSearch(frame.plate, this); + + // determine if this is a transient window + getTransientInfo(); + + // determine the window's type, so we can decide its decorations and + // functionality, or if we should not manage it at all + if (getWindowType()) { + // adjust the window decorations/behavior based on the window type + switch (window_type) { + case Type_Desktop: + case Type_Dock: + case Type_Menu: + blackbox_attrib.workspace = 0; // we do need to belong to a workspace + flags.stuck = True; // we show up on all workspaces + case Type_Splash: + // none of these windows are manipulated by the window manager + functions = 0; + break; + + case Type_Toolbar: + case Type_Utility: + // these windows get less functionality + functions &= ~(Func_Maximize | Func_Resize | Func_Iconify); + break; + + case Type_Dialog: + // dialogs cannot be maximized + functions &= ~Func_Maximize; + break; + + case Type_Normal: + // normal windows retain all of the possible decorations and + // functionality + break; + } + } else { + getMWMHints(); + } + + // further adjeust the window's decorations/behavior based on window sizes + if ((client.normal_hint_flags & PMinSize) && + (client.normal_hint_flags & PMaxSize) && + client.max_width <= client.min_width && + client.max_height <= client.min_height) { + functions &= ~(Func_Resize | Func_Maximize); + } + + setAllowedActions(); + + setupDecor(); + + if (decorations & Decor_Titlebar) + createTitlebar(); + + if (decorations & Decor_Handle) + createHandle(); + + // apply the size and gravity hint to the frame + + upsize(); + + bool place_window = True; + if (blackbox->isStartup() || isTransient() || + client.normal_hint_flags & (PPosition|USPosition)) { + applyGravity(frame.rect); + + if (blackbox->isStartup() || client.rect.intersects(screen->getRect())) + place_window = False; + } + + // add the window's strut. note this is done *after* placing the window. + screen->addStrut(&client.strut); + updateStrut(); + + /* + the server needs to be grabbed here to prevent client's from sending + events while we are in the process of configuring their window. + We hold the grab until after we are done moving the window around. + */ + + XGrabServer(blackbox->getXDisplay()); + + associateClientWindow(); + + blackbox->saveWindowSearch(client.window, this); + + if (blackbox_attrib.workspace >= screen->getWorkspaceCount()) + screen->getCurrentWorkspace()->addWindow(this, place_window); + else + screen->getWorkspace(blackbox_attrib.workspace)-> + addWindow(this, place_window); + + if (! place_window) { + // don't need to call configure if we are letting the workspace + // place the window + configure(frame.rect.x(), frame.rect.y(), + frame.rect.width(), frame.rect.height()); + + } + + positionWindows(); + + XUngrabServer(blackbox->getXDisplay()); + +#ifdef SHAPE + if (blackbox->hasShapeExtensions() && flags.shaped) + configureShape(); +#endif // SHAPE + + // now that we know where to put the window and what it should look like + // we apply the decorations + decorate(); + + grabButtons(); + + XMapSubwindows(blackbox->getXDisplay(), frame.window); + + // this ensures the title, buttons, and other decor are properly displayed + redrawWindowFrame(); + + // preserve the window's initial state on first map, and its current state + // across a restart + unsigned long initial_state = current_state; + if (! getState()) + current_state = initial_state; + + // get sticky state from our parent window if we've got one + if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul && + client.transient_for->isStuck() != flags.stuck) + flags.stuck = True; + + if (flags.shaded) { + flags.shaded = False; + initial_state = current_state; + shade(); + + /* + At this point in the life of a window, current_state should only be set + to IconicState if the window was an *icon*, not if it was shaded. + */ + if (initial_state != IconicState) + current_state = NormalState; + } + + if (flags.stuck) { + flags.stuck = False; + stick(); + } + + if (flags.maximized && (functions & Func_Maximize)) + remaximize(); + + // create this last so it only needs to be configured once + windowmenu = new Windowmenu(this); +} + + +BlackboxWindow::~BlackboxWindow(void) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n", + client.window); +#endif // DEBUG + + if (! timer) // window not managed... + return; + + if (flags.moving) + endMove(); + + screen->removeStrut(&client.strut); + screen->updateAvailableArea(); + + // We don't need to worry about resizing because resizing always grabs the X + // server. This should only ever happen if using opaque moving. + if (flags.moving) + endMove(); + + delete timer; + + delete windowmenu; + + if (client.window_group) { + BWindowGroup *group = blackbox->searchGroup(client.window_group); + if (group) group->removeWindow(this); + } + + // remove ourselves from our transient_for + if (isTransient()) { + if (client.transient_for != (BlackboxWindow *) ~0ul) + client.transient_for->client.transientList.remove(this); + client.transient_for = (BlackboxWindow*) 0; + } + + if (client.transientList.size() > 0) { + // reset transient_for for all transients + BlackboxWindowList::iterator it, end = client.transientList.end(); + for (it = client.transientList.begin(); it != end; ++it) + (*it)->client.transient_for = (BlackboxWindow*) 0; + } + + if (frame.title) + destroyTitlebar(); + + if (frame.handle) + destroyHandle(); + + if (frame.plate) { + blackbox->removeWindowSearch(frame.plate); + XDestroyWindow(blackbox->getXDisplay(), frame.plate); + } + + if (frame.window) { + blackbox->removeWindowSearch(frame.window); + XDestroyWindow(blackbox->getXDisplay(), frame.window); + } + + blackbox->removeWindowSearch(client.window); +} + + +void BlackboxWindow::enableDecor(bool enable) { + blackbox_attrib.flags |= AttribDecoration; + blackbox_attrib.decoration = enable ? DecorNormal : DecorNone; + setupDecor(); + + // we can not be shaded if we lack a titlebar + if (! (decorations & Decor_Titlebar) && flags.shaded) + shade(); + + if (flags.visible && frame.window) { + XMapSubwindows(blackbox->getXDisplay(), frame.window); + XMapWindow(blackbox->getXDisplay(), frame.window); + } + + reconfigure(); + setState(current_state); +} + + +void BlackboxWindow::setupDecor() { + if (blackbox_attrib.decoration != DecorNone) { + // start with everything on + decorations = Decor_Close | + (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) | + (mwm_decorations & Decor_Border ? Decor_Border : 0) | + (mwm_decorations & Decor_Handle ? Decor_Handle : 0) | + (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) | + (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0); + + if (! (functions & Func_Close)) decorations &= ~Decor_Close; + if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize; + if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify; + if (! (functions & Func_Resize)) decorations &= ~Decor_Handle; + + switch (window_type) { + case Type_Desktop: + case Type_Dock: + case Type_Menu: + case Type_Splash: + // none of these windows are decorated by the window manager at all + decorations = 0; + break; + + case Type_Toolbar: + case Type_Utility: + decorations &= ~(Decor_Border); + break; + + case Type_Dialog: + decorations &= ~Decor_Handle; + break; + + case Type_Normal: + break; + } + } else { + decorations = 0; + } +} + +/* + * Creates a new top level window, with a given location, size, and border + * width. + * Returns: the newly created window + */ +Window BlackboxWindow::createToplevelWindow(void) { + XSetWindowAttributes attrib_create; + unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap | + CWOverrideRedirect | CWEventMask; + + attrib_create.background_pixmap = None; + attrib_create.colormap = screen->getColormap(); + attrib_create.override_redirect = True; + attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | + ButtonPress; + /* + We catch button presses because other wise they get passed down to the + root window, which will then cause root menus to show when you click the + window's frame. + */ + + return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(), + 0, 0, 1, 1, frame.border_w, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, + &attrib_create); +} + + +/* + * Creates a child window, and optionally associates a given cursor with + * the new window. + */ +Window BlackboxWindow::createChildWindow(Window parent, + unsigned long event_mask, + Cursor cursor) { + XSetWindowAttributes attrib_create; + unsigned long create_mask = CWBackPixmap | CWBorderPixel | + CWEventMask; + + attrib_create.background_pixmap = None; + attrib_create.event_mask = event_mask; + + if (cursor) { + create_mask |= CWCursor; + attrib_create.cursor = cursor; + } + + return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0, + screen->getDepth(), InputOutput, screen->getVisual(), + create_mask, &attrib_create); +} + + +void BlackboxWindow::associateClientWindow(void) { + XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0); + getWMName(); + getWMIconName(); + + XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert); + + XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask); + + /* + note we used to grab around this call to XReparentWindow however the + server is now grabbed before this method is called + */ + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; + XSelectInput(blackbox->getXDisplay(), client.window, + event_mask & ~StructureNotifyMask); + XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); + + XRaiseWindow(blackbox->getXDisplay(), frame.plate); + XMapSubwindows(blackbox->getXDisplay(), frame.plate); + +#ifdef SHAPE + if (blackbox->hasShapeExtensions()) { + XShapeSelectInput(blackbox->getXDisplay(), client.window, + ShapeNotifyMask); + + Bool shaped = False; + int foo; + unsigned int ufoo; + + XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped, + &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo, + &ufoo, &ufoo); + flags.shaped = shaped; + } +#endif // SHAPE +} + + +void BlackboxWindow::decorate(void) { + BTexture* texture; + + texture = &(screen->getWindowStyle()->b_focus); + frame.fbutton = texture->render(frame.button_w, frame.button_w, + frame.fbutton); + if (! frame.fbutton) + frame.fbutton_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->b_unfocus); + frame.ubutton = texture->render(frame.button_w, frame.button_w, + frame.ubutton); + if (! frame.ubutton) + frame.ubutton_pixel = texture->color().pixel(); + + unsigned char needsPressed = 0; + + texture = &(screen->getWindowStyle()->b_pressed_focus); + + if (texture->texture() != BTexture::NoTexture) { + frame.pfbutton = texture->render(frame.button_w, frame.button_w, + frame.pfbutton); + if (! frame.pfbutton) + frame.pfbutton_pixel = texture->color().pixel(); + } else { + needsPressed = 0x1; + } + + texture = &(screen->getWindowStyle()->b_pressed_unfocus); + + if (texture->texture() != BTexture::NoTexture) { + frame.pubutton = texture->render(frame.button_w, frame.button_w, + frame.pubutton); + if (! frame.pubutton) + frame.pubutton = texture->color().pixel(); + } else { + needsPressed |= 0x2; + } + + // if we either pressed unfocused, or pressed focused were undefined, + // make them inherit from the old resource. It's a hack for sure, but + // it allows for some backwards and forwards compatibility. + if (needsPressed) { + texture = &(screen->getWindowStyle()->b_pressed); + + if (needsPressed & 0x1) { + frame.pfbutton = texture->render(frame.button_w, frame.button_w, + frame.pfbutton); + if (! frame.pfbutton) + frame.pfbutton_pixel = texture->color().pixel(); + } + if (needsPressed & 0x2) { + frame.pubutton = texture->render(frame.button_w, frame.button_w, + frame.pubutton); + if (! frame.pubutton) + frame.pubutton = texture->color().pixel(); + } + + } + + if (decorations & Decor_Titlebar) { + texture = &(screen->getWindowStyle()->t_focus); + frame.ftitle = texture->render(frame.inside_w, frame.title_h, + frame.ftitle); + if (! frame.ftitle) + frame.ftitle_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->t_unfocus); + frame.utitle = texture->render(frame.inside_w, frame.title_h, + frame.utitle); + if (! frame.utitle) + frame.utitle_pixel = texture->color().pixel(); + + XSetWindowBorder(blackbox->getXDisplay(), frame.title, + screen->getBorderColor()->pixel()); + + decorateLabel(); + } + + if (decorations & Decor_Border) { + frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel(); + frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel(); + } + + if (decorations & Decor_Handle) { + texture = &(screen->getWindowStyle()->h_focus); + frame.fhandle = texture->render(frame.inside_w, frame.handle_h, + frame.fhandle); + if (! frame.fhandle) + frame.fhandle_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->h_unfocus); + frame.uhandle = texture->render(frame.inside_w, frame.handle_h, + frame.uhandle); + if (! frame.uhandle) + frame.uhandle_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->g_focus); + frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip); + if (! frame.fgrip) + frame.fgrip_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->g_unfocus); + frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip); + if (! frame.ugrip) + frame.ugrip_pixel = texture->color().pixel(); + + XSetWindowBorder(blackbox->getXDisplay(), frame.handle, + screen->getBorderColor()->pixel()); + XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip, + screen->getBorderColor()->pixel()); + XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip, + screen->getBorderColor()->pixel()); + } + + XSetWindowBorder(blackbox->getXDisplay(), frame.window, + screen->getBorderColor()->pixel()); +} + + +void BlackboxWindow::decorateLabel(void) { + BTexture *texture; + + texture = &(screen->getWindowStyle()->l_focus); + frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel); + if (! frame.flabel) + frame.flabel_pixel = texture->color().pixel(); + + texture = &(screen->getWindowStyle()->l_unfocus); + frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel); + if (! frame.ulabel) + frame.ulabel_pixel = texture->color().pixel(); +} + + +void BlackboxWindow::createHandle(void) { + frame.handle = createChildWindow(frame.window, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.handle, this); + + frame.left_grip = + createChildWindow(frame.handle, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask, + blackbox->getLowerLeftAngleCursor()); + blackbox->saveWindowSearch(frame.left_grip, this); + + frame.right_grip = + createChildWindow(frame.handle, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask, + blackbox->getLowerRightAngleCursor()); + blackbox->saveWindowSearch(frame.right_grip, this); +} + + +void BlackboxWindow::destroyHandle(void) { + if (frame.fhandle) + screen->getImageControl()->removeImage(frame.fhandle); + + if (frame.uhandle) + screen->getImageControl()->removeImage(frame.uhandle); + + if (frame.fgrip) + screen->getImageControl()->removeImage(frame.fgrip); + + if (frame.ugrip) + screen->getImageControl()->removeImage(frame.ugrip); + + blackbox->removeWindowSearch(frame.left_grip); + blackbox->removeWindowSearch(frame.right_grip); + + XDestroyWindow(blackbox->getXDisplay(), frame.left_grip); + XDestroyWindow(blackbox->getXDisplay(), frame.right_grip); + frame.left_grip = frame.right_grip = None; + + blackbox->removeWindowSearch(frame.handle); + XDestroyWindow(blackbox->getXDisplay(), frame.handle); + frame.handle = None; +} + + +void BlackboxWindow::createTitlebar(void) { + frame.title = createChildWindow(frame.window, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + frame.label = createChildWindow(frame.title, + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.title, this); + blackbox->saveWindowSearch(frame.label, this); + + if (decorations & Decor_Iconify) createIconifyButton(); + if (decorations & Decor_Maximize) createMaximizeButton(); + if (decorations & Decor_Close) createCloseButton(); +} + + +void BlackboxWindow::destroyTitlebar(void) { + if (frame.close_button) + destroyCloseButton(); + + if (frame.iconify_button) + destroyIconifyButton(); + + if (frame.maximize_button) + destroyMaximizeButton(); + + if (frame.stick_button) + destroyStickyButton(); + + if (frame.ftitle) + screen->getImageControl()->removeImage(frame.ftitle); + + if (frame.utitle) + screen->getImageControl()->removeImage(frame.utitle); + + if (frame.flabel) + screen->getImageControl()->removeImage(frame.flabel); + + if( frame.ulabel) + screen->getImageControl()->removeImage(frame.ulabel); + + if (frame.fbutton) + screen->getImageControl()->removeImage(frame.fbutton); + + if (frame.ubutton) + screen->getImageControl()->removeImage(frame.ubutton); + + blackbox->removeWindowSearch(frame.title); + blackbox->removeWindowSearch(frame.label); + + XDestroyWindow(blackbox->getXDisplay(), frame.label); + XDestroyWindow(blackbox->getXDisplay(), frame.title); + frame.title = frame.label = None; +} + + +void BlackboxWindow::createCloseButton(void) { + if (frame.title != None) { + frame.close_button = createChildWindow(frame.title, + ButtonPressMask | + ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.close_button, this); + } +} + + +void BlackboxWindow::destroyCloseButton(void) { + blackbox->removeWindowSearch(frame.close_button); + XDestroyWindow(blackbox->getXDisplay(), frame.close_button); + frame.close_button = None; +} + + +void BlackboxWindow::createIconifyButton(void) { + if (frame.title != None) { + frame.iconify_button = createChildWindow(frame.title, + ButtonPressMask | + ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.iconify_button, this); + } +} + + +void BlackboxWindow::destroyIconifyButton(void) { + blackbox->removeWindowSearch(frame.iconify_button); + XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button); + frame.iconify_button = None; +} + + +void BlackboxWindow::createMaximizeButton(void) { + if (frame.title != None) { + frame.maximize_button = createChildWindow(frame.title, + ButtonPressMask | + ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.maximize_button, this); + } +} + + +void BlackboxWindow::destroyMaximizeButton(void) { + blackbox->removeWindowSearch(frame.maximize_button); + XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button); + frame.maximize_button = None; +} + +void BlackboxWindow::createStickyButton(void) { + if (frame.title != None) { + frame.stick_button = createChildWindow(frame.title, + ButtonPressMask | + ButtonReleaseMask | + ButtonMotionMask | ExposureMask); + blackbox->saveWindowSearch(frame.stick_button, this); + } +} + +void BlackboxWindow::destroyStickyButton(void) { + blackbox->removeWindowSearch(frame.stick_button); + XDestroyWindow(blackbox->getXDisplay(), frame.stick_button); + frame.stick_button = None; +} + +void BlackboxWindow::positionButtons(bool redecorate_label) { + string layout = blackbox->getTitlebarLayout(); + string parsed; + + bool hasclose, hasiconify, hasmaximize, haslabel, hasstick; + hasclose = hasiconify = hasmaximize = haslabel = hasstick = false; + + string::const_iterator it, end; + for (it = layout.begin(), end = layout.end(); it != end; ++it) { + switch(*it) { + case 'C': + if (! hasclose && (decorations & Decor_Close)) { + hasclose = true; + parsed += *it; + } + break; + case 'I': + if (! hasiconify && (decorations & Decor_Iconify)) { + hasiconify = true; + parsed += *it; + } + break; + case 'S': + if (!hasstick) { + hasstick = true; + parsed += *it; + } + break; + case 'M': + if (! hasmaximize && (decorations & Decor_Maximize)) { + hasmaximize = true; + parsed += *it; + } + break; + case 'L': + if (! haslabel) { + haslabel = true; + parsed += *it; + } + break; + } + } + + if (! hasclose && frame.close_button) + destroyCloseButton(); + if (! hasiconify && frame.iconify_button) + destroyIconifyButton(); + if (! hasmaximize && frame.maximize_button) + destroyMaximizeButton(); + if (! hasstick && frame.stick_button) + destroyStickyButton(); + if (! haslabel) + parsed += 'L'; // require that the label be in the layout + + const unsigned int bsep = frame.bevel_w + 1; // separation between elements + const unsigned int by = frame.bevel_w + 1; + const unsigned int ty = frame.bevel_w; + + frame.label_w = frame.inside_w - bsep * 2 - + (frame.button_w + bsep) * (parsed.size() - 1); + + unsigned int x = bsep; + for (it = parsed.begin(), end = parsed.end(); it != end; ++it) { + switch(*it) { + case 'C': + if (! frame.close_button) createCloseButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'I': + if (! frame.iconify_button) createIconifyButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'S': + if (! frame.stick_button) createStickyButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.stick_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'M': + if (! frame.maximize_button) createMaximizeButton(); + XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by, + frame.button_w, frame.button_w); + x += frame.button_w + bsep; + break; + case 'L': + XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty, + frame.label_w, frame.label_h); + x += frame.label_w + bsep; + break; + } + } + + if (redecorate_label) decorateLabel(); + redrawLabel(); + redrawAllButtons(); +} + + +void BlackboxWindow::reconfigure(void) { + restoreGravity(client.rect); + upsize(); + applyGravity(frame.rect); + positionWindows(); + decorate(); + redrawWindowFrame(); + + ungrabButtons(); + grabButtons(); + + if (windowmenu) { + windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h); + windowmenu->reconfigure(); + } +} + + +void BlackboxWindow::grabButtons(void) { + mod_mask = blackbox->getMouseModMask(); + + if (! screen->isSloppyFocus() || screen->doClickRaise()) + // grab button 1 for changing focus/raising + blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, + GrabModeSync, GrabModeSync, frame.plate, None, + screen->allowScrollLock()); + + if (functions & Func_Move) + blackbox->grabButton(Button1, mod_mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, frame.window, None, + screen->allowScrollLock()); + if (functions & Func_Resize) + blackbox->grabButton(Button3, mod_mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, frame.window, None, + screen->allowScrollLock()); + // alt+middle lowers the window + blackbox->grabButton(Button2, mod_mask, frame.window, True, + ButtonReleaseMask, GrabModeAsync, GrabModeAsync, + frame.window, None, screen->allowScrollLock()); +} + + +void BlackboxWindow::ungrabButtons(void) { + blackbox->ungrabButton(Button1, 0, frame.plate); + blackbox->ungrabButton(Button1, mod_mask, frame.window); + blackbox->ungrabButton(Button2, mod_mask, frame.window); + blackbox->ungrabButton(Button3, mod_mask, frame.window); +} + + +void BlackboxWindow::positionWindows(void) { + XMoveResizeWindow(blackbox->getXDisplay(), frame.window, + frame.rect.x(), frame.rect.y(), frame.inside_w, + (flags.shaded) ? frame.title_h : frame.inside_h); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window, + frame.border_w); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate, + frame.mwm_border_w); + XMoveResizeWindow(blackbox->getXDisplay(), frame.plate, + frame.margin.left - frame.mwm_border_w - frame.border_w, + frame.margin.top - frame.mwm_border_w - frame.border_w, + client.rect.width(), client.rect.height()); + XMoveResizeWindow(blackbox->getXDisplay(), client.window, + 0, 0, client.rect.width(), client.rect.height()); + // ensure client.rect contains the real location + client.rect.setPos(frame.rect.left() + frame.margin.left, + frame.rect.top() + frame.margin.top); + + if (decorations & Decor_Titlebar) { + if (frame.title == None) createTitlebar(); + + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title, + frame.border_w); + XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w, + -frame.border_w, frame.inside_w, frame.title_h); + + positionButtons(); + XMapSubwindows(blackbox->getXDisplay(), frame.title); + XMapWindow(blackbox->getXDisplay(), frame.title); + } else if (frame.title) { + destroyTitlebar(); + } + if (decorations & Decor_Handle) { + if (frame.handle == None) createHandle(); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle, + frame.border_w); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip, + frame.border_w); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip, + frame.border_w); + + // use client.rect here so the value is correct even if shaded + XMoveResizeWindow(blackbox->getXDisplay(), frame.handle, + -frame.border_w, + client.rect.height() + frame.margin.top + + frame.mwm_border_w - frame.border_w, + frame.inside_w, frame.handle_h); + XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip, + -frame.border_w, -frame.border_w, + frame.grip_w, frame.handle_h); + XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip, + frame.inside_w - frame.grip_w - frame.border_w, + -frame.border_w, frame.grip_w, frame.handle_h); + + XMapSubwindows(blackbox->getXDisplay(), frame.handle); + XMapWindow(blackbox->getXDisplay(), frame.handle); + } else if (frame.handle) { + destroyHandle(); + } + XSync(blackbox->getXDisplay(), False); +} + + +void BlackboxWindow::updateStrut(void) { + unsigned long num = 4; + unsigned long *data; + if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal, + num, &data)) + return; + + if (num == 4) { + client.strut.left = data[0]; + client.strut.right = data[1]; + client.strut.top = data[2]; + client.strut.bottom = data[3]; + + screen->updateAvailableArea(); + } + + delete [] data; +} + + +bool BlackboxWindow::getWindowType(void) { + window_type = (WindowType) -1; + + unsigned long *val; + unsigned long num = (unsigned) -1; + if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom, + num, &val)) { + for (unsigned long i = 0; i < num; ++i) { + if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop)) + window_type = Type_Desktop; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock)) + window_type = Type_Dock; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar)) + window_type = Type_Toolbar; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu)) + window_type = Type_Menu; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility)) + window_type = Type_Utility; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash)) + window_type = Type_Splash; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog)) + window_type = Type_Dialog; + else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal)) + window_type = Type_Normal; + else if (val[i] == + xatom->getAtom(XAtom::kde_net_wm_window_type_override)) + mwm_decorations = 0; // prevent this window from getting any decor + } + delete val; + } + + if (window_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 (isTransient()) + window_type = Type_Dialog; + else + window_type = Type_Normal; + + return False; + } + + return True; +} + + +void BlackboxWindow::getWMName(void) { + if (xatom->getValue(client.window, XAtom::net_wm_name, + XAtom::utf8, client.title) && + !client.title.empty()) { + xatom->eraseValue(client.window, XAtom::net_wm_visible_name); + return; + } + //fall through to using WM_NAME + if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title) + && !client.title.empty()) { + xatom->eraseValue(client.window, XAtom::net_wm_visible_name); + return; + } + // fall back to an internal default + client.title = i18n(WindowSet, WindowUnnamed, "Unnamed"); + xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8, + client.title); + +#ifdef DEBUG_WITH_ID + // the 16 is the 8 chars of the debug text plus the number + char *tmp = new char[client.title.length() + 16]; + sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window); + client.title = tmp; + delete tmp; +#endif +} + + +void BlackboxWindow::getWMIconName(void) { + if (xatom->getValue(client.window, XAtom::net_wm_icon_name, + XAtom::utf8, client.icon_title) && + !client.icon_title.empty()) { + xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name); + return; + } + //fall through to using WM_ICON_NAME + if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi, + client.icon_title) && + !client.icon_title.empty()) { + xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name); + return; + } + // fall back to using the main name + client.icon_title = client.title; + xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8, + client.icon_title); +} + + +/* + * Retrieve which WM Protocols are supported by the client window. + * If the WM_DELETE_WINDOW protocol is supported, add the close button to the + * window's decorations and allow the close behavior. + * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates + * this. + */ +void BlackboxWindow::getWMProtocols(void) { + Atom *proto; + int num_return = 0; + + if (XGetWMProtocols(blackbox->getXDisplay(), client.window, + &proto, &num_return)) { + for (int i = 0; i < num_return; ++i) { + if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) { + decorations |= Decor_Close; + functions |= Func_Close; + } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus)) + flags.send_focus_message = True; + else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages)) + screen->addNetizen(new Netizen(screen, client.window)); + } + + XFree(proto); + } +} + + +/* + * Gets the value of the WM_HINTS property. + * If the property is not set, then use a set of default values. + */ +void BlackboxWindow::getWMHints(void) { + focus_mode = F_Passive; + + // remove from current window group + if (client.window_group) { + BWindowGroup *group = blackbox->searchGroup(client.window_group); + if (group) group->removeWindow(this); + } + client.window_group = None; + + XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window); + if (! wmhint) { + return; + } + + if (wmhint->flags & InputHint) { + if (wmhint->input == True) { + if (flags.send_focus_message) + focus_mode = F_LocallyActive; + } else { + if (flags.send_focus_message) + focus_mode = F_GloballyActive; + else + focus_mode = F_NoInput; + } + } + + if (wmhint->flags & StateHint) + current_state = wmhint->initial_state; + + if (wmhint->flags & WindowGroupHint) { + client.window_group = wmhint->window_group; + + // add window to the appropriate group + BWindowGroup *group = blackbox->searchGroup(client.window_group); + if (! group) { // no group found, create it! + new BWindowGroup(blackbox, client.window_group); + group = blackbox->searchGroup(client.window_group); + } + if (group) + group->addWindow(this); + } + + XFree(wmhint); +} + + +/* + * Gets the value of the WM_NORMAL_HINTS property. + * If the property is not set, then use a set of default values. + */ +void BlackboxWindow::getWMNormalHints(void) { + long icccm_mask; + XSizeHints sizehint; + + client.min_width = client.min_height = + client.width_inc = client.height_inc = 1; + client.base_width = client.base_height = 0; + client.win_gravity = NorthWestGravity; +#if 0 + client.min_aspect_x = client.min_aspect_y = + client.max_aspect_x = client.max_aspect_y = 1; +#endif + + // don't limit the size of a window, the default max width is the biggest + // possible + client.max_width = (unsigned) -1; + client.max_height = (unsigned) -1; + + + if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window, + &sizehint, &icccm_mask)) + return; + + client.normal_hint_flags = sizehint.flags; + + if (sizehint.flags & PMinSize) { + if (sizehint.min_width >= 0) + client.min_width = sizehint.min_width; + if (sizehint.min_height >= 0) + client.min_height = sizehint.min_height; + } + + if (sizehint.flags & PMaxSize) { + if (sizehint.max_width > static_cast(client.min_width)) + client.max_width = sizehint.max_width; + else + client.max_width = client.min_width; + + if (sizehint.max_height > static_cast(client.min_height)) + client.max_height = sizehint.max_height; + else + client.max_height = client.min_height; + } + + if (sizehint.flags & PResizeInc) { + client.width_inc = sizehint.width_inc; + client.height_inc = sizehint.height_inc; + } + +#if 0 // we do not support this at the moment + if (sizehint.flags & PAspect) { + client.min_aspect_x = sizehint.min_aspect.x; + client.min_aspect_y = sizehint.min_aspect.y; + client.max_aspect_x = sizehint.max_aspect.x; + client.max_aspect_y = sizehint.max_aspect.y; + } +#endif + + if (sizehint.flags & PBaseSize) { + client.base_width = sizehint.base_width; + client.base_height = sizehint.base_height; + } + + if (sizehint.flags & PWinGravity) + client.win_gravity = sizehint.win_gravity; +} + + +/* + * Gets the NETWM hints for the class' contained window. + */ +void BlackboxWindow::getNetWMHints(void) { + unsigned long workspace; + + if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, + workspace)) { + if (workspace == 0xffffffff) + flags.stuck = True; + else + blackbox_attrib.workspace = workspace; + } + + unsigned long *state; + unsigned long num = (unsigned) -1; + if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom, + num, &state)) { + bool vert = False, + horz = False; + for (unsigned long i = 0; i < num; ++i) { + if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) + flags.modal = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded)) + flags.shaded = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) + flags.skip_taskbar = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager)) + flags.skip_pager = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen)) + flags.fullscreen = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden)) + setState(IconicState); + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert)) + vert = True; + else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz)) + horz = True; + } + if (vert && horz) + flags.maximized = 1; + else if (vert) + flags.maximized = 2; + else if (horz) + flags.maximized = 3; + + delete [] state; + } +} + + +/* + * Gets the MWM hints for the class' contained window. + * This is used while initializing the window to its first state, and not + * thereafter. + * Returns: true if the MWM hints are successfully retreived and applied; + * false if they are not. + */ +void BlackboxWindow::getMWMHints(void) { + unsigned long num; + MwmHints *mwm_hint; + + num = PropMwmHintsElements; + if (! xatom->getValue(client.window, XAtom::motif_wm_hints, + XAtom::motif_wm_hints, num, + (unsigned long **)&mwm_hint)) + return; + if (num < PropMwmHintsElements) { + delete [] mwm_hint; + return; + } + + if (mwm_hint->flags & MwmHintsDecorations) { + if (mwm_hint->decorations & MwmDecorAll) { + mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border | + Decor_Iconify | Decor_Maximize; + } else { + mwm_decorations = 0; + + if (mwm_hint->decorations & MwmDecorBorder) + mwm_decorations |= Decor_Border; + if (mwm_hint->decorations & MwmDecorHandle) + mwm_decorations |= Decor_Handle; + if (mwm_hint->decorations & MwmDecorTitle) + mwm_decorations |= Decor_Titlebar; + if (mwm_hint->decorations & MwmDecorIconify) + mwm_decorations |= Decor_Iconify; + if (mwm_hint->decorations & MwmDecorMaximize) + mwm_decorations |= Decor_Maximize; + } + } + + if (mwm_hint->flags & MwmHintsFunctions) { + if (mwm_hint->functions & MwmFuncAll) { + functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize | + Func_Close; + } else { + functions = 0; + + if (mwm_hint->functions & MwmFuncResize) + functions |= Func_Resize; + if (mwm_hint->functions & MwmFuncMove) + functions |= Func_Move; + if (mwm_hint->functions & MwmFuncIconify) + functions |= Func_Iconify; + if (mwm_hint->functions & MwmFuncMaximize) + functions |= Func_Maximize; + if (mwm_hint->functions & MwmFuncClose) + functions |= Func_Close; + } + } + delete [] mwm_hint; +} + + +/* + * Gets the blackbox hints from the class' contained window. + * This is used while initializing the window to its first state, and not + * thereafter. + * Returns: true if the hints are successfully retreived and applied; false if + * they are not. + */ +bool BlackboxWindow::getBlackboxHints(void) { + unsigned long num; + BlackboxHints *blackbox_hint; + + num = PropBlackboxHintsElements; + if (! xatom->getValue(client.window, XAtom::blackbox_hints, + XAtom::blackbox_hints, num, + (unsigned long **)&blackbox_hint)) + return False; + if (num < PropBlackboxHintsElements) { + delete [] blackbox_hint; + return False; + } + + if (blackbox_hint->flags & AttribShaded) + flags.shaded = (blackbox_hint->attrib & AttribShaded); + + if ((blackbox_hint->flags & AttribMaxHoriz) && + (blackbox_hint->flags & AttribMaxVert)) + flags.maximized = (blackbox_hint->attrib & + (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; + else if (blackbox_hint->flags & AttribMaxVert) + flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0; + else if (blackbox_hint->flags & AttribMaxHoriz) + flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0; + + if (blackbox_hint->flags & AttribOmnipresent) + flags.stuck = (blackbox_hint->attrib & AttribOmnipresent); + + if (blackbox_hint->flags & AttribWorkspace) + blackbox_attrib.workspace = blackbox_hint->workspace; + + // if (blackbox_hint->flags & AttribStack) + // don't yet have always on top/bottom for blackbox yet... working + // on that + + if (blackbox_hint->flags & AttribDecoration) { + switch (blackbox_hint->decoration) { + case DecorNone: + blackbox_attrib.decoration = DecorNone; + break; + + case DecorTiny: + case DecorTool: + case DecorNormal: + default: + // blackbox_attrib.decoration defaults to DecorNormal + break; + } + } + + delete [] blackbox_hint; + + return True; +} + + +void BlackboxWindow::getTransientInfo(void) { + if (client.transient_for && + client.transient_for != (BlackboxWindow *) ~0ul) { + // reset transient_for in preparation of looking for a new owner + client.transient_for->client.transientList.remove(this); + } + + // we have no transient_for until we find a new one + client.transient_for = (BlackboxWindow *) 0; + + Window trans_for; + if (! XGetTransientForHint(blackbox->getXDisplay(), client.window, + &trans_for)) { + // transient_for hint not set + return; + } + + if (trans_for == client.window) { + // wierd client... treat this window as a normal window + return; + } + + if (trans_for == None || trans_for == screen->getRootWindow()) { + // this is an undocumented interpretation of the ICCCM. a transient + // associated with None/Root/itself is assumed to be a modal root + // transient. we don't support the concept of a global transient, + // so we just associate this transient with nothing, and perhaps + // we will add support later for global modality. + client.transient_for = (BlackboxWindow *) ~0ul; + flags.modal = True; + return; + } + + client.transient_for = blackbox->searchWindow(trans_for); + if (! client.transient_for && + client.window_group && trans_for == client.window_group) { + // no direct transient_for, perhaps this is a group transient? + BWindowGroup *group = blackbox->searchGroup(client.window_group); + if (group) client.transient_for = group->find(screen); + } + + if (! client.transient_for || client.transient_for == this) { + // no transient_for found, or we have a wierd client that wants to be + // a transient for itself, so we treat this window as a normal window + client.transient_for = (BlackboxWindow*) 0; + return; + } + + // Check for a circular transient state: this can lock up Blackbox + // when it tries to find the non-transient window for a transient. + BlackboxWindow *w = this; + while(w->client.transient_for && + w->client.transient_for != (BlackboxWindow *) ~0ul) { + if(w->client.transient_for == this) { + client.transient_for = (BlackboxWindow*) 0; + break; + } + w = w->client.transient_for; + } + + if (client.transient_for && + client.transient_for != (BlackboxWindow *) ~0ul) { + // register ourselves with our new transient_for + client.transient_for->client.transientList.push_back(this); + flags.stuck = client.transient_for->flags.stuck; + } +} + + +BlackboxWindow *BlackboxWindow::getTransientFor(void) const { + if (client.transient_for && + client.transient_for != (BlackboxWindow*) ~0ul) + return client.transient_for; + return 0; +} + + +/* + * This function is responsible for updating both the client and the frame + * rectangles. + * According to the ICCCM a client message is not sent for a resize, only a + * move. + */ +void BlackboxWindow::configure(int dx, int dy, + unsigned int dw, unsigned int dh) { + bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) && + ! flags.moving); + + if (dw != frame.rect.width() || dh != frame.rect.height()) { + frame.rect.setRect(dx, dy, dw, dh); + frame.inside_w = frame.rect.width() - (frame.border_w * 2); + frame.inside_h = frame.rect.height() - (frame.border_w * 2); + + if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0) + frame.rect.setPos(0, 0); + + client.rect.setCoords(frame.rect.left() + frame.margin.left, + frame.rect.top() + frame.margin.top, + frame.rect.right() - frame.margin.right, + frame.rect.bottom() - frame.margin.bottom); + +#ifdef SHAPE + if (blackbox->hasShapeExtensions() && flags.shaped) { + configureShape(); + } +#endif // SHAPE + + positionWindows(); + decorate(); + redrawWindowFrame(); + } else { + frame.rect.setPos(dx, dy); + + XMoveWindow(blackbox->getXDisplay(), frame.window, + frame.rect.x(), frame.rect.y()); + /* + we may have been called just after an opaque window move, so even though + the old coords match the new ones no ConfigureNotify has been sent yet. + There are likely other times when this will be relevant as well. + */ + if (! flags.moving) send_event = True; + } + + if (send_event) { + // if moving, the update and event will occur when the move finishes + client.rect.setPos(frame.rect.left() + frame.margin.left, + frame.rect.top() + frame.margin.top); + + XEvent event; + event.type = ConfigureNotify; + + event.xconfigure.display = blackbox->getXDisplay(); + event.xconfigure.event = client.window; + event.xconfigure.window = client.window; + event.xconfigure.x = client.rect.x(); + event.xconfigure.y = client.rect.y(); + event.xconfigure.width = client.rect.width(); + event.xconfigure.height = client.rect.height(); + event.xconfigure.border_width = client.old_bw; + event.xconfigure.above = frame.window; + event.xconfigure.override_redirect = False; + + XSendEvent(blackbox->getXDisplay(), client.window, False, + StructureNotifyMask, &event); + screen->updateNetizenConfigNotify(&event); + XFlush(blackbox->getXDisplay()); + } +} + + +#ifdef SHAPE +void BlackboxWindow::configureShape(void) { + XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding, + frame.margin.left - frame.border_w, + frame.margin.top - frame.border_w, + client.window, ShapeBounding, ShapeSet); + + int num = 0; + XRectangle xrect[2]; + + if (decorations & Decor_Titlebar) { + xrect[0].x = xrect[0].y = -frame.border_w; + xrect[0].width = frame.rect.width(); + xrect[0].height = frame.title_h + (frame.border_w * 2); + ++num; + } + + if (decorations & Decor_Handle) { + xrect[1].x = -frame.border_w; + xrect[1].y = frame.rect.height() - frame.margin.bottom + + frame.mwm_border_w - frame.border_w; + xrect[1].width = frame.rect.width(); + xrect[1].height = frame.handle_h + (frame.border_w * 2); + ++num; + } + + XShapeCombineRectangles(blackbox->getXDisplay(), frame.window, + ShapeBounding, 0, 0, xrect, num, + ShapeUnion, Unsorted); +} + + +void BlackboxWindow::clearShape(void) { + XShapeCombineMask(blackbox->getXDisplay(), frame.window, ShapeBounding, + frame.margin.left - frame.border_w, + frame.margin.top - frame.border_w, + None, ShapeSet); +} +#endif // SHAPE + + +bool BlackboxWindow::setInputFocus(void) { + if (flags.focused) return True; + + assert(flags.stuck || // window must be on the current workspace or sticky + blackbox_attrib.workspace == screen->getCurrentWorkspaceID()); + + /* + We only do this check for normal windows and dialogs because other windows + do this on purpose, such as kde's kicker, and we don't want to go moving + it. + */ + if (window_type == Type_Normal || window_type == Type_Dialog) + if (! frame.rect.intersects(screen->getRect())) { + // client is outside the screen, move it to the center + configure((screen->getWidth() - frame.rect.width()) / 2, + (screen->getHeight() - frame.rect.height()) / 2, + frame.rect.width(), frame.rect.height()); + } + + if (client.transientList.size() > 0) { + // transfer focus to any modal transients + BlackboxWindowList::iterator it, end = client.transientList.end(); + for (it = client.transientList.begin(); it != end; ++it) + if ((*it)->flags.modal) return (*it)->setInputFocus(); + } + + bool ret = True; + if (focus_mode == F_LocallyActive || focus_mode == F_Passive) { + XSetInputFocus(blackbox->getXDisplay(), client.window, + RevertToPointerRoot, CurrentTime); + } else { + /* we could set the focus to none, since the window doesn't accept focus, + * but we shouldn't set focus to nothing since this would surely make + * someone angry + */ + ret = False; + } + + if (flags.send_focus_message) { + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols); + ce.xclient.display = blackbox->getXDisplay(); + ce.xclient.window = client.window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus); + ce.xclient.data.l[1] = blackbox->getLastTime(); + ce.xclient.data.l[2] = 0l; + ce.xclient.data.l[3] = 0l; + ce.xclient.data.l[4] = 0l; + XSendEvent(blackbox->getXDisplay(), client.window, False, + NoEventMask, &ce); + XFlush(blackbox->getXDisplay()); + } + + return ret; +} + + +void BlackboxWindow::iconify(void) { + if (flags.iconic || ! (functions & Func_Iconify)) return; + + // We don't need to worry about resizing because resizing always grabs the X + // server. This should only ever happen if using opaque moving. + if (flags.moving) + endMove(); + + if (windowmenu) windowmenu->hide(); + + /* + * we don't want this XUnmapWindow call to generate an UnmapNotify event, so + * we need to clear the event mask on client.window for a split second. + * HOWEVER, since X11 is asynchronous, the window could be destroyed in that + * split second, leaving us with a ghost window... so, we need to do this + * while the X server is grabbed + */ + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; + XGrabServer(blackbox->getXDisplay()); + XSelectInput(blackbox->getXDisplay(), client.window, + event_mask & ~StructureNotifyMask); + XUnmapWindow(blackbox->getXDisplay(), client.window); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); + XUngrabServer(blackbox->getXDisplay()); + + XUnmapWindow(blackbox->getXDisplay(), frame.window); + flags.visible = False; + flags.iconic = True; + + setState(IconicState); + + screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this); + if (flags.stuck) { + for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) + if (i != blackbox_attrib.workspace) + screen->getWorkspace(i)->removeWindow(this, True); + } + + if (isTransient()) { + if (client.transient_for != (BlackboxWindow *) ~0ul && + ! client.transient_for->flags.iconic) { + // iconify our transient_for + client.transient_for->iconify(); + } + } + + screen->addIcon(this); + + if (client.transientList.size() > 0) { + // iconify all transients + BlackboxWindowList::iterator it, end = client.transientList.end(); + for (it = client.transientList.begin(); it != end; ++it) { + if (! (*it)->flags.iconic) (*it)->iconify(); + } + } + screen->updateStackingList(); +} + + +void BlackboxWindow::show(void) { + flags.visible = True; + flags.iconic = False; + + current_state = (flags.shaded) ? IconicState : NormalState; + setState(current_state); + + XMapWindow(blackbox->getXDisplay(), client.window); + XMapSubwindows(blackbox->getXDisplay(), frame.window); + XMapWindow(blackbox->getXDisplay(), frame.window); + +#if 0 + int real_x, real_y; + Window child; + XTranslateCoordinates(blackbox->getXDisplay(), client.window, + screen->getRootWindow(), + 0, 0, &real_x, &real_y, &child); + fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(), + client.rect.left(), client.rect.top(), real_x, real_y); + assert(client.rect.left() == real_x && client.rect.top() == real_y); +#endif +} + + +void BlackboxWindow::deiconify(bool reassoc, bool raise) { + if (flags.iconic || reassoc) + screen->reassociateWindow(this, BSENTINEL, False); + else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) + return; + + show(); + + // reassociate and deiconify all transients + if (reassoc && client.transientList.size() > 0) { + BlackboxWindowList::iterator it, end = client.transientList.end(); + for (it = client.transientList.begin(); it != end; ++it) + (*it)->deiconify(True, False); + } + + if (raise) + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); +} + + +void BlackboxWindow::close(void) { + if (! (functions & Func_Close)) return; + + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols); + ce.xclient.display = blackbox->getXDisplay(); + ce.xclient.window = client.window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = xatom->getAtom(XAtom::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(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce); + XFlush(blackbox->getXDisplay()); +} + + +void BlackboxWindow::withdraw(void) { + // We don't need to worry about resizing because resizing always grabs the X + // server. This should only ever happen if using opaque moving. + if (flags.moving) + endMove(); + + flags.visible = False; + flags.iconic = False; + + setState(current_state); + + XUnmapWindow(blackbox->getXDisplay(), frame.window); + + XGrabServer(blackbox->getXDisplay()); + + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; + XSelectInput(blackbox->getXDisplay(), client.window, + event_mask & ~StructureNotifyMask); + XUnmapWindow(blackbox->getXDisplay(), client.window); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); + + XUngrabServer(blackbox->getXDisplay()); + + if (windowmenu) windowmenu->hide(); +} + + +void BlackboxWindow::maximize(unsigned int button) { + if (! (functions & Func_Maximize)) return; + + // We don't need to worry about resizing because resizing always grabs the X + // server. This should only ever happen if using opaque moving. + if (flags.moving) + endMove(); + + // handle case where menu is open then the max button is used instead + if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); + + if (flags.maximized) { + flags.maximized = 0; + + blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert); + blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert); + + /* + when a resize finishes, maximize(0) is called to clear any maximization + flags currently set. Otherwise it still thinks it is maximized. + so we do not need to call configure() because resizing will handle it + */ + if (! flags.resizing) + configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y, + blackbox_attrib.premax_w, blackbox_attrib.premax_h); + + blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; + blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; + + redrawAllButtons(); // in case it is not called in configure() + setState(current_state); + return; + } + + blackbox_attrib.premax_x = frame.rect.x(); + blackbox_attrib.premax_y = frame.rect.y(); + blackbox_attrib.premax_w = frame.rect.width(); + // use client.rect so that clients can be restored even if shaded + blackbox_attrib.premax_h = + client.rect.height() + frame.margin.top + frame.margin.bottom; + +#ifdef XINERAMA + if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) { + // find the area to use + RectList availableAreas = screen->allAvailableAreas(); + RectList::iterator it, end = availableAreas.end(); + + for (it = availableAreas.begin(); it != end; ++it) + if (it->intersects(frame.rect)) break; + if (it == end) // the window isn't inside an area + it = availableAreas.begin(); // so just default to the first one + + frame.changing = *it; + } else +#endif // XINERAMA + frame.changing = screen->availableArea(); + + switch(button) { + case 1: + blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert; + blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert; + break; + + case 2: + blackbox_attrib.flags |= AttribMaxVert; + blackbox_attrib.attrib |= AttribMaxVert; + + frame.changing.setX(frame.rect.x()); + frame.changing.setWidth(frame.rect.width()); + break; + + case 3: + blackbox_attrib.flags |= AttribMaxHoriz; + blackbox_attrib.attrib |= AttribMaxHoriz; + + frame.changing.setY(frame.rect.y()); + frame.changing.setHeight(frame.rect.height()); + break; + } + + constrain(TopLeft); + + if (flags.shaded) { + blackbox_attrib.flags ^= AttribShaded; + blackbox_attrib.attrib ^= AttribShaded; + flags.shaded = False; + } + + flags.maximized = button; + + configure(frame.changing.x(), frame.changing.y(), + frame.changing.width(), frame.changing.height()); + if (flags.focused) + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + redrawAllButtons(); // in case it is not called in configure() + setState(current_state); +} + + +// re-maximizes the window to take into account availableArea changes +void BlackboxWindow::remaximize(void) { + if (flags.shaded) { + // we only update the window's attributes otherwise we lose the shade bit + switch(flags.maximized) { + case 1: + blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert; + blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert; + break; + + case 2: + blackbox_attrib.flags |= AttribMaxVert; + blackbox_attrib.attrib |= AttribMaxVert; + break; + + case 3: + blackbox_attrib.flags |= AttribMaxHoriz; + blackbox_attrib.attrib |= AttribMaxHoriz; + break; + } + return; + } + + // save the original dimensions because maximize will wipe them out + int premax_x = blackbox_attrib.premax_x, + premax_y = blackbox_attrib.premax_y, + premax_w = blackbox_attrib.premax_w, + premax_h = blackbox_attrib.premax_h; + + unsigned int button = flags.maximized; + flags.maximized = 0; // trick maximize() into working + maximize(button); + + // restore saved values + blackbox_attrib.premax_x = premax_x; + blackbox_attrib.premax_y = premax_y; + blackbox_attrib.premax_w = premax_w; + blackbox_attrib.premax_h = premax_h; +} + + +void BlackboxWindow::setWorkspace(unsigned int n) { + blackbox_attrib.flags |= AttribWorkspace; + blackbox_attrib.workspace = n; + if (n == BSENTINEL) { // iconified window + /* + we set the workspace to 'all workspaces' so that taskbars will show the + window. otherwise, it made uniconifying a window imposible without the + blackbox workspace menu + */ + n = 0xffffffff; + } + xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n); +} + + +void BlackboxWindow::shade(void) { + if (flags.shaded) { + XResizeWindow(blackbox->getXDisplay(), frame.window, + frame.inside_w, frame.inside_h); + flags.shaded = False; + blackbox_attrib.flags ^= AttribShaded; + blackbox_attrib.attrib ^= AttribShaded; + + setState(NormalState); + + // set the frame rect to the normal size + frame.rect.setHeight(client.rect.height() + frame.margin.top + + frame.margin.bottom); + } else { + if (! (decorations & Decor_Titlebar)) + return; // can't shade it without a titlebar! + + XResizeWindow(blackbox->getXDisplay(), frame.window, + frame.inside_w, frame.title_h); + flags.shaded = True; + blackbox_attrib.flags |= AttribShaded; + blackbox_attrib.attrib |= AttribShaded; + + setState(IconicState); + + // set the frame rect to the shaded size + frame.rect.setHeight(frame.title_h + (frame.border_w * 2)); + } +} + + +/* + * (Un)Sticks a window and its relatives. + */ +void BlackboxWindow::stick(void) { + if (flags.stuck) { + blackbox_attrib.flags ^= AttribOmnipresent; + blackbox_attrib.attrib ^= AttribOmnipresent; + + flags.stuck = False; + + for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) + if (i != blackbox_attrib.workspace) + screen->getWorkspace(i)->removeWindow(this, True); + + if (! flags.iconic) + screen->reassociateWindow(this, BSENTINEL, True); + // temporary fix since sticky windows suck. set the hint to what we + // actually hold in our data. + xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, + blackbox_attrib.workspace); + + setState(current_state); + } else { + flags.stuck = True; + + blackbox_attrib.flags |= AttribOmnipresent; + blackbox_attrib.attrib |= AttribOmnipresent; + + // temporary fix since sticky windows suck. set the hint to a different + // value than that contained in the class' data. + xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, + 0xffffffff); + + for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i) + if (i != blackbox_attrib.workspace) + screen->getWorkspace(i)->addWindow(this, False, True); + + setState(current_state); + } + + redrawAllButtons(); + + // go up the chain + if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul && + client.transient_for->isStuck() != flags.stuck) + client.transient_for->stick(); + // go down the chain + BlackboxWindowList::iterator it; + const BlackboxWindowList::iterator end = client.transientList.end(); + for (it = client.transientList.begin(); it != end; ++it) + if ((*it)->isStuck() != flags.stuck) + (*it)->stick(); +} + + +void BlackboxWindow::redrawWindowFrame(void) const { + if (decorations & Decor_Titlebar) { + if (flags.focused) { + if (frame.ftitle) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.title, frame.ftitle); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.title, frame.ftitle_pixel); + } else { + if (frame.utitle) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.title, frame.utitle); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.title, frame.utitle_pixel); + } + XClearWindow(blackbox->getXDisplay(), frame.title); + + redrawLabel(); + redrawAllButtons(); + } + + if (decorations & Decor_Handle) { + if (flags.focused) { + if (frame.fhandle) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.handle, frame.fhandle); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.handle, frame.fhandle_pixel); + + if (frame.fgrip) { + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.left_grip, frame.fgrip); + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.right_grip, frame.fgrip); + } else { + XSetWindowBackground(blackbox->getXDisplay(), + frame.left_grip, frame.fgrip_pixel); + XSetWindowBackground(blackbox->getXDisplay(), + frame.right_grip, frame.fgrip_pixel); + } + } else { + if (frame.uhandle) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.handle, frame.uhandle); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.handle, frame.uhandle_pixel); + + if (frame.ugrip) { + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.left_grip, frame.ugrip); + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.right_grip, frame.ugrip); + } else { + XSetWindowBackground(blackbox->getXDisplay(), + frame.left_grip, frame.ugrip_pixel); + XSetWindowBackground(blackbox->getXDisplay(), + frame.right_grip, frame.ugrip_pixel); + } + } + XClearWindow(blackbox->getXDisplay(), frame.handle); + XClearWindow(blackbox->getXDisplay(), frame.left_grip); + XClearWindow(blackbox->getXDisplay(), frame.right_grip); + } + + if (decorations & Decor_Border) { + if (flags.focused) + XSetWindowBorder(blackbox->getXDisplay(), + frame.plate, frame.fborder_pixel); + else + XSetWindowBorder(blackbox->getXDisplay(), + frame.plate, frame.uborder_pixel); + } +} + + +void BlackboxWindow::setFocusFlag(bool focus) { + // only focus a window if it is visible + if (focus && ! flags.visible) + return; + + flags.focused = focus; + + redrawWindowFrame(); + + if (flags.focused) + blackbox->setFocusedWindow(this); + + if (! flags.iconic) { + // iconic windows arent in a workspace menu! + if (flags.stuck) + screen->getCurrentWorkspace()->setFocused(this, isFocused()); + else + screen->getWorkspace(blackbox_attrib.workspace)-> + setFocused(this, flags.focused); + } +} + + +void BlackboxWindow::installColormap(bool install) { + int i = 0, ncmap = 0; + Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(), + client.window, &ncmap); + if (cmaps) { + XWindowAttributes wattrib; + if (XGetWindowAttributes(blackbox->getXDisplay(), + client.window, &wattrib)) { + if (install) { + // install the window's colormap + for (i = 0; i < ncmap; i++) { + if (*(cmaps + i) == wattrib.colormap) + // this window is using an installed color map... do not install + install = False; + } + // otherwise, install the window's colormap + if (install) + XInstallColormap(blackbox->getXDisplay(), wattrib.colormap); + } else { + // uninstall the window's colormap + for (i = 0; i < ncmap; i++) { + if (*(cmaps + i) == wattrib.colormap) + // we found the colormap to uninstall + XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap); + } + } + } + + XFree(cmaps); + } +} + + +void BlackboxWindow::setAllowedActions(void) { + Atom actions[7]; + int num = 0; + + actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade); + actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop); + actions[num++] = xatom->getAtom(XAtom::net_wm_action_close); + + if (functions & Func_Move) + actions[num++] = xatom->getAtom(XAtom::net_wm_action_move); + if (functions & Func_Resize) + actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize); + if (functions & Func_Maximize) { + actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz); + actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert); + } + + xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom, + actions, num); +} + + +void BlackboxWindow::setState(unsigned long new_state) { + current_state = new_state; + + unsigned long state[2]; + state[0] = current_state; + state[1] = None; + xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2); + + xatom->setValue(client.window, XAtom::blackbox_attributes, + XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib, + PropBlackboxAttributesElements); + + Atom netstate[8]; + int num = 0; + if (flags.modal) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal); + if (flags.shaded) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded); + if (flags.iconic) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden); + if (flags.skip_taskbar) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar); + if (flags.skip_pager) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager); + if (flags.fullscreen) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen); + if (flags.maximized == 1 || flags.maximized == 2) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert); + if (flags.maximized == 1 || flags.maximized == 3) + netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz); + xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom, + netstate, num); +} + + +bool BlackboxWindow::getState(void) { + bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state, + current_state); + if (! ret) current_state = 0; + return ret; +} + + +void BlackboxWindow::restoreAttributes(void) { + unsigned long num = PropBlackboxAttributesElements; + BlackboxAttributes *net; + if (! xatom->getValue(client.window, XAtom::blackbox_attributes, + XAtom::blackbox_attributes, num, + (unsigned long **)&net)) + return; + if (num < PropBlackboxAttributesElements) { + delete [] net; + return; + } + + if (net->flags & AttribShaded && net->attrib & AttribShaded) { + flags.shaded = False; + unsigned long orig_state = current_state; + shade(); + + /* + At this point in the life of a window, current_state should only be set + to IconicState if the window was an *icon*, not if it was shaded. + */ + if (orig_state != IconicState) + current_state = WithdrawnState; + } + + if (net->workspace != screen->getCurrentWorkspaceID() && + net->workspace < screen->getWorkspaceCount()) + screen->reassociateWindow(this, net->workspace, True); + + if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) && + (blackbox_attrib.workspace < screen->getWorkspaceCount())) { + // set to WithdrawnState so it will be mapped on the new workspace + if (current_state == NormalState) current_state = WithdrawnState; + } else if (current_state == WithdrawnState) { + // the window is on this workspace and is Withdrawn, so it is waiting to + // be mapped + current_state = NormalState; + } + + if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent && + ! flags.stuck) { + stick(); + + // if the window was on another workspace, it was going to be hidden. this + // specifies that the window should be mapped since it is sticky. + if (current_state == WithdrawnState) current_state = NormalState; + } + + if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) { + int x = net->premax_x, y = net->premax_y; + unsigned int w = net->premax_w, h = net->premax_h; + flags.maximized = 0; + + unsigned int m = 0; + if ((net->flags & AttribMaxHoriz) && + (net->flags & AttribMaxVert)) + m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; + else if (net->flags & AttribMaxVert) + m = (net->attrib & AttribMaxVert) ? 2 : 0; + else if (net->flags & AttribMaxHoriz) + m = (net->attrib & AttribMaxHoriz) ? 3 : 0; + + if (m) maximize(m); + + blackbox_attrib.premax_x = x; + blackbox_attrib.premax_y = y; + blackbox_attrib.premax_w = w; + blackbox_attrib.premax_h = h; + } + + if (net->flags & AttribDecoration) { + switch (net->decoration) { + case DecorNone: + enableDecor(False); + break; + + /* since tools only let you toggle this anyways, we'll just make that all + it supports for now. + */ + default: + case DecorNormal: + case DecorTiny: + case DecorTool: + enableDecor(True); + break; + } + } + + // with the state set it will then be the map event's job to read the + // window's state and behave accordingly + + delete [] net; +} + + +/* + * Positions the Rect r according the the client window position and + * window gravity. + */ +void BlackboxWindow::applyGravity(Rect &r) { + // apply horizontal window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case SouthWestGravity: + case WestGravity: + r.setX(client.rect.x()); + break; + + case NorthGravity: + case SouthGravity: + case CenterGravity: + r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2); + break; + + case NorthEastGravity: + case SouthEastGravity: + case EastGravity: + r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setX(client.rect.x() - frame.margin.left); + break; + } + + // apply vertical window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case NorthEastGravity: + case NorthGravity: + r.setY(client.rect.y()); + break; + + case CenterGravity: + case EastGravity: + case WestGravity: + r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2); + break; + + case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setY(client.rect.y() - frame.margin.top); + break; + } +} + + +/* + * The reverse of the applyGravity function. + * + * Positions the Rect r according to the frame window position and + * window gravity. + */ +void BlackboxWindow::restoreGravity(Rect &r) { + // restore horizontal window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case SouthWestGravity: + case WestGravity: + r.setX(frame.rect.x()); + break; + + case NorthGravity: + case SouthGravity: + case CenterGravity: + r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2); + break; + + case NorthEastGravity: + case SouthEastGravity: + case EastGravity: + r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setX(frame.rect.x() + frame.margin.left); + break; + } + + // restore vertical window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case NorthEastGravity: + case NorthGravity: + r.setY(frame.rect.y()); + break; + + case CenterGravity: + case EastGravity: + case WestGravity: + r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2); + break; + + case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setY(frame.rect.y() + frame.margin.top); + break; + } +} + + +void BlackboxWindow::redrawLabel(void) const { + if (flags.focused) { + if (frame.flabel) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.label, frame.flabel); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.label, frame.flabel_pixel); + } else { + if (frame.ulabel) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), + frame.label, frame.ulabel); + else + XSetWindowBackground(blackbox->getXDisplay(), + frame.label, frame.ulabel_pixel); + } + XClearWindow(blackbox->getXDisplay(), frame.label); + + WindowStyle *style = screen->getWindowStyle(); + + int pos = frame.bevel_w * 2; + style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4); + style->font->drawString(frame.label, pos, 1, + (flags.focused ? style->l_text_focus : + style->l_text_unfocus), + client.title); +} + + +void BlackboxWindow::redrawAllButtons(void) const { + if (frame.iconify_button) redrawIconifyButton(False); + if (frame.maximize_button) redrawMaximizeButton(flags.maximized); + if (frame.close_button) redrawCloseButton(False); + if (frame.stick_button) redrawStickyButton(flags.stuck); +} + + +void BlackboxWindow::redrawButton(bool pressed, Window win, + Pixmap fppix, unsigned long fppixel, + Pixmap uppix, unsigned long uppixel, + Pixmap fpix, unsigned long fpixel, + Pixmap upix, unsigned long upixel) const { + Pixmap p; + unsigned long pix; + + if (pressed) { + if (flags.focused) { + p = fppix; + pix = fppixel; + } else { + p = uppix; + pix = uppixel; + } + } else { + if (flags.focused) { + p = fpix; + pix = fpixel; + } else { + p = upix; + pix = upixel; + } + } + + if (p) + XSetWindowBackgroundPixmap(blackbox->getXDisplay(), win, p); + else + XSetWindowBackground(blackbox->getXDisplay(), win, pix); + +} + +void BlackboxWindow::redrawIconifyButton(bool pressed) const { + redrawButton(pressed, frame.iconify_button, + frame.pfbutton, frame.pfbutton_pixel, + frame.pubutton, frame.pubutton_pixel, + frame.fbutton, frame.fbutton_pixel, + frame.ubutton, frame.ubutton_pixel); + + XClearWindow(blackbox->getXDisplay(), frame.iconify_button); + BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : + screen->getWindowStyle()->b_pic_unfocus); + +#ifdef BITMAPBUTTONS + PixmapMask pm = screen->getWindowStyle()->icon_button; + + if (screen->getWindowStyle()->icon_button.mask != None) { + XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); + + XFillRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, + (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); + + XSetClipMask(blackbox->getXDisplay(), pen.gc(), None); + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0); + } else { +#endif // BITMAPBUTTONS + XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(), + 2, (frame.button_w - 5), (frame.button_w - 5), 2); +#ifdef BITMAPBUTTONS + } +#endif // BITMAPBUTTONS +} + + +void BlackboxWindow::redrawMaximizeButton(bool pressed) const { + redrawButton(pressed, frame.maximize_button, + frame.pfbutton, frame.pfbutton_pixel, + frame.pubutton, frame.pubutton_pixel, + frame.fbutton, frame.fbutton_pixel, + frame.ubutton, frame.ubutton_pixel); + + XClearWindow(blackbox->getXDisplay(), frame.maximize_button); + + BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : + screen->getWindowStyle()->b_pic_unfocus); + +#ifdef BITMAPBUTTONS + PixmapMask pm = screen->getWindowStyle()->max_button; + + if (pm.mask != None) { + XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); + + XFillRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, + (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); + + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); + XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); + } else { +#endif // BITMAPBUTTONS + XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), + 2, 2, (frame.button_w - 5), (frame.button_w - 5)); + XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(), + 2, 3, (frame.button_w - 3), 3); +#ifdef BITMAPBUTTONS + } +#endif // BITMAPBUTTONS +} + + +void BlackboxWindow::redrawCloseButton(bool pressed) const { + redrawButton(pressed, frame.close_button, + frame.pfbutton, frame.pfbutton_pixel, + frame.pubutton, frame.pubutton_pixel, + frame.fbutton, frame.fbutton_pixel, + frame.ubutton, frame.ubutton_pixel); + + XClearWindow(blackbox->getXDisplay(), frame.close_button); + + BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : + screen->getWindowStyle()->b_pic_unfocus); + +#ifdef BITMAPBUTTONS + PixmapMask pm = screen->getWindowStyle()->close_button; + + if (pm.mask != None) { + XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); + + XFillRectangle(blackbox->getXDisplay(), frame.close_button, pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, + (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); + + + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); + XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); + } else { +#endif // BITMAPBUTTONS + XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(), + 2, 2, (frame.button_w - 3), (frame.button_w - 3)); + XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(), + 2, (frame.button_w - 3), (frame.button_w - 3), 2); +#ifdef BITMAPBUTTONS + } +#endif // BITMAPBUTTONS +} + +void BlackboxWindow::redrawStickyButton(bool pressed) const { + redrawButton(pressed, frame.stick_button, + frame.pfbutton, frame.pfbutton_pixel, + frame.pubutton, frame.pubutton_pixel, + frame.fbutton, frame.fbutton_pixel, + frame.ubutton, frame.ubutton_pixel); + + XClearWindow(blackbox->getXDisplay(), frame.stick_button); + + BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus : + screen->getWindowStyle()->b_pic_unfocus); + +#ifdef BITMAPBUTTONS + PixmapMask pm = screen->getWindowStyle()->stick_button; + + if (pm.mask != None) { + XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask); + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2); + + XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(), + (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2, + (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2); + + + XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 ); + XSetClipMask( blackbox->getXDisplay(), pen.gc(), None ); + } else { +#endif // BITMAPBUTTONS + XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(), + frame.button_w/2 - 1, frame.button_w/2 -1, 2, 2 ); +#ifdef BITMAPBUTTONS + } +#endif +} + +void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { + if (re->window != client.window) + return; + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n", + client.window); +#endif // DEBUG + + /* + Even though the window wants to be shown, if it is not on the current + workspace, then it isn't going to be shown right now. + */ + if (! flags.stuck && + blackbox_attrib.workspace != screen->getCurrentWorkspaceID() && + blackbox_attrib.workspace < screen->getWorkspaceCount()) + if (current_state == NormalState) current_state = WithdrawnState; + + switch (current_state) { + case IconicState: + iconify(); + break; + + case WithdrawnState: + withdraw(); + break; + + case NormalState: + case InactiveState: + case ZoomState: + default: + show(); + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + if (isNormal()) { + if (! blackbox->isStartup()) { + XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped + if (screen->doFocusNew() || (isTransient() && getTransientFor() && + getTransientFor()->isFocused())) { + setInputFocus(); + } + if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) { + int x, y, rx, ry; + Window c, r; + unsigned int m; + XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(), + &r, &c, &rx, &ry, &x, &y, &m); + beginMove(rx, ry); + } + } + } + break; + } +} + + +void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) { + if (ue->window != client.window) + return; + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n", + client.window); +#endif // DEBUG + + screen->unmanageWindow(this, False); +} + + +void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) { + if (de->window != client.window) + return; + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n", + client.window); +#endif // DEBUG + + screen->unmanageWindow(this, False); +} + + +void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) { + if (re->window != client.window || re->parent == frame.plate) + return; + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to " + "0x%lx.\n", client.window, re->parent); +#endif // DEBUG + + XEvent ev; + ev.xreparent = *re; + XPutBackEvent(blackbox->getXDisplay(), &ev); + screen->unmanageWindow(this, True); +} + + +void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { + if (pe->state == PropertyDelete || ! validateClient()) + return; + +#if 0 + fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n", + client.window); +#endif + + switch(pe->atom) { + case XA_WM_CLASS: + case XA_WM_CLIENT_MACHINE: + case XA_WM_COMMAND: + break; + + case XA_WM_TRANSIENT_FOR: { + bool s = flags.stuck; + + // determine if this is a transient window + getTransientInfo(); + + if (flags.stuck != s) stick(); + + // adjust the window decorations based on transience + if (isTransient()) { + functions &= ~Func_Maximize; + setAllowedActions(); + setupDecor(); + } + + reconfigure(); + } + break; + + case XA_WM_HINTS: + getWMHints(); + break; + + case XA_WM_ICON_NAME: + getWMIconName(); + if (flags.iconic) screen->propagateWindowName(this); + break; + + case XAtom::net_wm_name: + case XA_WM_NAME: + getWMName(); + + if (decorations & Decor_Titlebar) + redrawLabel(); + + screen->propagateWindowName(this); + break; + + case XA_WM_NORMAL_HINTS: { + getWMNormalHints(); + + if ((client.normal_hint_flags & PMinSize) && + (client.normal_hint_flags & PMaxSize)) { + // the window now can/can't resize itself, so the buttons need to be + // regrabbed. + ungrabButtons(); + if (client.max_width <= client.min_width && + client.max_height <= client.min_height) { + functions &= ~(Func_Resize | Func_Maximize); + } else { + if (! isTransient()) + functions |= Func_Maximize; + functions |= Func_Resize; + } + grabButtons(); + setAllowedActions(); + setupDecor(); + } + + Rect old_rect = frame.rect; + + upsize(); + + if (old_rect != frame.rect) + reconfigure(); + + break; + } + + default: + if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) { + getWMProtocols(); + + if ((decorations & Decor_Close) && (! frame.close_button)) { + createCloseButton(); + if (decorations & Decor_Titlebar) { + positionButtons(True); + XMapSubwindows(blackbox->getXDisplay(), frame.title); + } + if (windowmenu) windowmenu->reconfigure(); + } + } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) { + updateStrut(); + } + + break; + } +} + + +void BlackboxWindow::exposeEvent(const XExposeEvent *ee) { +#if 0 + fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window); +#endif + + if (frame.label == ee->window && (decorations & Decor_Titlebar)) + redrawLabel(); + else if (frame.close_button == ee->window) + redrawCloseButton(False); + else if (frame.maximize_button == ee->window) + redrawMaximizeButton(flags.maximized); + else if (frame.iconify_button == ee->window) + redrawIconifyButton(False); + else if (frame.stick_button == ee->window) + redrawStickyButton(flags.stuck); +} + + +void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { + if (cr->window != client.window || flags.iconic) + return; + + if (cr->value_mask & CWBorderWidth) + client.old_bw = cr->border_width; + + if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) { + frame.changing = frame.rect; + + if (cr->value_mask & (CWX | CWY)) { + if (cr->value_mask & CWX) + client.rect.setX(cr->x); + if (cr->value_mask & CWY) + client.rect.setY(cr->y); + + applyGravity(frame.changing); + } + + if (cr->value_mask & (CWWidth | CWHeight)) { + if (cr->value_mask & CWWidth) + frame.changing.setWidth(cr->width + + frame.margin.left + frame.margin.right); + + if (cr->value_mask & CWHeight) + frame.changing.setHeight(cr->height + + frame.margin.top + frame.margin.bottom); + + /* + if a position change has been specified, then that position will be + used instead of determining a position based on the window's gravity. + */ + if (! (cr->value_mask & (CWX | CWY))) { + Corner corner; + switch (client.win_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; + } + constrain(corner); + } + } + + configure(frame.changing.x(), frame.changing.y(), + frame.changing.width(), frame.changing.height()); + } + + if (cr->value_mask & CWStackMode && !isDesktop()) { + switch (cr->detail) { + case Below: + case BottomIf: + screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this); + break; + + case Above: + case TopIf: + default: + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + break; + } + } +} + + +void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n", + client.window); +#endif + + if (frame.maximize_button == be->window && be->button <= 3) { + redrawMaximizeButton(True); + } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) { + if (! flags.focused) + setInputFocus(); + + if (frame.iconify_button == be->window) { + redrawIconifyButton(True); + } else if (frame.close_button == be->window) { + redrawCloseButton(True); + } else if (frame.stick_button == be->window) { + redrawStickyButton(True); + } else if (frame.plate == be->window) { + if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); + + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + + XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time); + } else { + if (frame.title == be->window || frame.label == be->window) { + if (((be->time - lastButtonPressTime) <= + blackbox->getDoubleClickInterval()) || + (be->state == ControlMask)) { + lastButtonPressTime = 0; + shade(); + } else { + lastButtonPressTime = be->time; + } + } + + if (windowmenu && windowmenu->isVisible()) windowmenu->hide(); + + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + } + } else if (be->button == 2 && (be->window != frame.iconify_button) && + (be->window != frame.close_button) && + (be->window != frame.stick_button)) { + screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this); + } else if (windowmenu && be->button == 3 && + (frame.title == be->window || frame.label == be->window || + frame.handle == be->window || frame.window == be->window)) { + if (windowmenu->isVisible()) { + windowmenu->hide(); + } else { + int mx = be->x_root - windowmenu->getWidth() / 2, + my = be->y_root - windowmenu->getHeight() / 2; + + // snap the window menu into a corner/side if necessary + int left_edge, right_edge, top_edge, bottom_edge; + + /* + the " + (frame.border_w * 2) - 1" bits are to get the proper width + and height of the menu, as the sizes returned by it do not include + the borders. + */ + left_edge = frame.rect.x(); + right_edge = frame.rect.right() - + (windowmenu->getWidth() + (frame.border_w * 2) - 1); + top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w); + bottom_edge = client.rect.bottom() - + (windowmenu->getHeight() + (frame.border_w * 2) - 1) + + (frame.border_w + frame.mwm_border_w); + + if (mx < left_edge) + mx = left_edge; + else if (mx > right_edge) + mx = right_edge; + if (my < top_edge) + my = top_edge; + else if (my > bottom_edge) + my = bottom_edge; + + if (my + windowmenu->getHeight() > screen->getHeight()) + my = screen->getHeight() - windowmenu->getHeight() - + (screen->getBorderWidth() * 2); + + windowmenu->move(mx, my); + windowmenu->show(); + XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID()); + XRaiseWindow(blackbox->getXDisplay(), + windowmenu->getSendToMenu()->getWindowID()); + } + // mouse wheel up + } else if (be->button == 4) { + if ((be->window == frame.label || + be->window == frame.title || + be->window == frame.maximize_button || + be->window == frame.iconify_button || + be->window == frame.close_button || + be->window == frame.stick_button) && + ! flags.shaded) + shade(); + // mouse wheel down + } else if (be->button == 5) { + if ((be->window == frame.label || + be->window == frame.title || + be->window == frame.maximize_button || + be->window == frame.iconify_button || + be->window == frame.close_button || + be->window == frame.stick_button) && + flags.shaded) + shade(); + } +} + + +void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n", + client.window); +#endif + + if (re->window == frame.maximize_button && + re->button >= 1 && re->button <= 3) { + if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && + (re->y >= 0 && re->y <= static_cast(frame.button_w))) { + maximize(re->button); + } else { + redrawMaximizeButton(flags.maximized); + } + } else if (re->window == frame.iconify_button && re->button == 1) { + if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && + (re->y >= 0 && re->y <= static_cast(frame.button_w))) { + iconify(); + } else { + redrawIconifyButton(False); + } + } else if (re->window == frame.stick_button && re->button == 1) { + if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && + (re->y >= 0 && re->y <= static_cast(frame.button_w))) { + stick(); + } else { + redrawStickyButton(False); + } + } else if (re->window == frame.close_button & re->button == 1) { + if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && + (re->y >= 0 && re->y <= static_cast(frame.button_w))) + close(); + redrawCloseButton(False); + } else if (flags.moving) { + endMove(); + } else if (flags.resizing) { + endResize(); + } else if (re->window == frame.window) { + if (re->button == 2 && re->state == mod_mask) + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + } +} + + + +void BlackboxWindow::beginMove(int x_root, int y_root) { + if (! (functions & Func_Move)) return; + + assert(! (flags.resizing || flags.moving)); + + /* + Only one window can be moved/resized at a time. If another window is already + being moved or resized, then stop it before whating to work with this one. + */ + BlackboxWindow *changing = blackbox->getChangingWindow(); + if (changing && changing != this) { + if (changing->flags.moving) + changing->endMove(); + else // if (changing->flags.resizing) + changing->endResize(); + } + + XGrabPointer(blackbox->getXDisplay(), frame.window, False, + PointerMotionMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, + None, blackbox->getMoveCursor(), CurrentTime); + + if (windowmenu && windowmenu->isVisible()) + windowmenu->hide(); + + flags.moving = True; + blackbox->setChangingWindow(this); + + if (! screen->doOpaqueMove()) { + XGrabServer(blackbox->getXDisplay()); + + frame.changing = frame.rect; + screen->showPosition(frame.changing.x(), frame.changing.y()); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), + frame.changing.x(), + frame.changing.y(), + frame.changing.width() - 1, + frame.changing.height() - 1); + } + + frame.grab_x = x_root - frame.rect.x() - frame.border_w; + frame.grab_y = y_root - frame.rect.y() - frame.border_w; +} + + +void BlackboxWindow::doMove(int x_root, int y_root) { + assert(flags.moving); + assert(blackbox->getChangingWindow() == this); + + int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y; + dx -= frame.border_w; + dy -= frame.border_w; + + doWindowSnapping(dx, dy); + + if (screen->doOpaqueMove()) { + if (screen->doWorkspaceWarping()) + doWorkspaceWarping(x_root, y_root, dx); + + configure(dx, dy, frame.rect.width(), frame.rect.height()); + } else { + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), + frame.changing.x(), + frame.changing.y(), + frame.changing.width() - 1, + frame.changing.height() - 1); + + if (screen->doWorkspaceWarping()) + doWorkspaceWarping(x_root, y_root, dx); + + frame.changing.setPos(dx, dy); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), + frame.changing.x(), + frame.changing.y(), + frame.changing.width() - 1, + frame.changing.height() - 1); + } + + screen->showPosition(dx, dy); +} + + +void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) { + // workspace warping + bool warp = False; + unsigned int dest = screen->getCurrentWorkspaceID(); + if (x_root <= 0) { + warp = True; + + if (dest > 0) dest--; + else dest = screen->getNumberOfWorkspaces() - 1; + + } else if (x_root >= screen->getRect().right()) { + warp = True; + + if (dest < screen->getNumberOfWorkspaces() - 1) dest++; + else dest = 0; + } + if (! warp) + return; + + bool focus = flags.focused; // had focus while moving? + + int dest_x = x_root; + if (x_root <= 0) { + dest_x += screen->getRect().width() - 1; + dx += screen->getRect().width() - 1; + } else { + dest_x -= screen->getRect().width() - 1; + dx -= screen->getRect().width() - 1; + } + + if (! flags.stuck) + screen->reassociateWindow(this, dest, False); + screen->changeWorkspaceID(dest); + + if (screen->doOpaqueMove()) + XGrabServer(blackbox->getXDisplay()); + + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + XWarpPointer(blackbox->getXDisplay(), None, + screen->getRootWindow(), 0, 0, 0, 0, + dest_x, y_root); + XGrabPointer(blackbox->getXDisplay(), frame.window, False, + PointerMotionMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, + None, blackbox->getMoveCursor(), CurrentTime); + + if (screen->doOpaqueMove()) + XUngrabServer(blackbox->getXDisplay()); + + if (focus) + setInputFocus(); + +} + + +void BlackboxWindow::doWindowSnapping(int &dx, int &dy) { + // how much resistance to edges to provide + const int resistance_size = screen->getResistanceSize(); + + // how far away to snap + const int snap_distance = screen->getSnapThreshold(); + + // how to snap windows + const int snap_to_windows = screen->getWindowToWindowSnap(); + const int snap_to_edges = screen->getWindowToEdgeSnap(); + // the amount of space away from the edge to provide resistance/snap + const int snap_offset = screen->getSnapOffset(); + + // find the geomeetery where the moving window currently is + const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing; + + // window corners + const int wleft = dx, + wright = dx + frame.rect.width() - 1, + wtop = dy, + wbottom = dy + frame.rect.height() - 1; + + if (snap_to_windows) { + RectList rectlist; + + Workspace *w = screen->getWorkspace(getWorkspaceNumber()); + assert(w); + + // add windows on the workspace to the rect list + const BlackboxWindowList& stack_list = w->getStackingList(); + BlackboxWindowList::const_iterator st_it, st_end = stack_list.end(); + for (st_it = stack_list.begin(); st_it != st_end; ++st_it) + if (*st_it != this) // don't snap to ourself + rectlist.push_back( (*st_it)->frameRect() ); + + // add the toolbar and the slit to the rect list. + // (only if they are not hidden) + Toolbar *tbar = screen->getToolbar(); + Slit *slit = screen->getSlit(); + Rect tbar_rect, slit_rect; + unsigned int bwidth = screen->getBorderWidth() * 2; + + if (! (screen->doHideToolbar() || tbar->isHidden())) { + tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth, + tbar->getHeight() + bwidth); + rectlist.push_back(tbar_rect); + } + + if (! slit->isHidden()) { + slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth, + slit->getHeight() + bwidth); + rectlist.push_back(slit_rect); + } + + RectList::const_iterator it, end = rectlist.end(); + for (it = rectlist.begin(); it != end; ++it) { + bool snapped = False; + const Rect &winrect = *it; + Rect offsetrect; + offsetrect.setCoords(winrect.left() - snap_offset, + winrect.top() - snap_offset, + winrect.right() + snap_offset, + winrect.bottom() + snap_offset); + + if (snap_to_windows == BScreen::WindowResistance) + // if the window is already over top of this snap target, then + // resistance is futile, so just ignore it + if (winrect.intersects(moving)) + continue; + + int dleft, dright, dtop, dbottom; + + // if the windows are in the same plane vertically + if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) && + wtop < (signed)(winrect.y() + winrect.height() - 1)) { + + if (snap_to_windows == BScreen::WindowResistance) { + dleft = wright - offsetrect.left(); + dright = offsetrect.right() - wleft; + + // snap left of other window? + if (dleft >= 0 && dleft < resistance_size && + dleft < (wright - wleft)) { + dx = offsetrect.left() - frame.rect.width(); + snapped = True; + } + // snap right of other window? + else if (dright >= 0 && dright < resistance_size && + dright < (wright - wleft)) { + dx = offsetrect.right() + 1; + snapped = True; + } + } else { // BScreen::WindowSnap + dleft = abs(wright - offsetrect.left()); + dright = abs(wleft - offsetrect.right()); + + // snap left of other window? + if (dleft < snap_distance && dleft <= dright) { + dx = offsetrect.left() - frame.rect.width(); + snapped = True; + } + // snap right of other window? + else if (dright < snap_distance) { + dx = offsetrect.right() + 1; + snapped = True; + } + } + + if (snapped) { + if (screen->getWindowCornerSnap()) { + // try corner-snap to its other sides + if (snap_to_windows == BScreen::WindowResistance) { + dtop = winrect.top() - wtop; + dbottom = wbottom - winrect.bottom(); + if (dtop > 0 && dtop < resistance_size) { + // if we're already past the top edge, then don't provide + // resistance + if (moving.top() >= winrect.top()) + dy = winrect.top(); + } else if (dbottom > 0 && dbottom < resistance_size) { + // if we're already past the bottom edge, then don't provide + // resistance + if (moving.bottom() <= winrect.bottom()) + dy = winrect.bottom() - frame.rect.height() + 1; + } + } else { // BScreen::WindowSnap + dtop = abs(wtop - winrect.top()); + dbottom = abs(wbottom - winrect.bottom()); + if (dtop < snap_distance && dtop <= dbottom) + dy = winrect.top(); + else if (dbottom < snap_distance) + dy = winrect.bottom() - frame.rect.height() + 1; + } + } + + continue; + } + } + + // if the windows are on the same plane horizontally + if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) && + wleft < (signed)(winrect.x() + winrect.width() - 1)) { + + if (snap_to_windows == BScreen::WindowResistance) { + dtop = wbottom - offsetrect.top(); + dbottom = offsetrect.bottom() - wtop; + + // snap top of other window? + if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) { + dy = offsetrect.top() - frame.rect.height(); + snapped = True; + } + // snap bottom of other window? + else if (dbottom >= 0 && dbottom < resistance_size && + dbottom < (wbottom - wtop)) { + dy = offsetrect.bottom() + 1; + snapped = True; + } + } else { // BScreen::WindowSnap + dtop = abs(wbottom - offsetrect.top()); + dbottom = abs(wtop - offsetrect.bottom()); + + // snap top of other window? + if (dtop < snap_distance && dtop <= dbottom) { + dy = offsetrect.top() - frame.rect.height(); + snapped = True; + } + // snap bottom of other window? + else if (dbottom < snap_distance) { + dy = offsetrect.bottom() + 1; + snapped = True; + } + + } + + if (snapped) { + if (screen->getWindowCornerSnap()) { + // try corner-snap to its other sides + if (snap_to_windows == BScreen::WindowResistance) { + dleft = winrect.left() - wleft; + dright = wright - winrect.right(); + if (dleft > 0 && dleft < resistance_size) { + // if we're already past the left edge, then don't provide + // resistance + if (moving.left() >= winrect.left()) + dx = winrect.left(); + } else if (dright > 0 && dright < resistance_size) { + // if we're already past the right edge, then don't provide + // resistance + if (moving.right() <= winrect.right()) + dx = winrect.right() - frame.rect.width() + 1; + } + } else { // BScreen::WindowSnap + dleft = abs(wleft - winrect.left()); + dright = abs(wright - winrect.right()); + if (dleft < snap_distance && dleft <= dright) + dx = winrect.left(); + else if (dright < snap_distance) + dx = winrect.right() - frame.rect.width() + 1; + } + } + + continue; + } + } + } + } + + if (snap_to_edges) { + RectList rectlist; + + // snap to the screen edges (and screen boundaries for xinerama) +#ifdef XINERAMA + if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) { + rectlist.insert(rectlist.begin(), + screen->getXineramaAreas().begin(), + screen->getXineramaAreas().end()); + } else +#endif // XINERAMA + rectlist.push_back(screen->getRect()); + + RectList::const_iterator it, end = rectlist.end(); + for (it = rectlist.begin(); it != end; ++it) { + const Rect &srect = *it; + Rect offsetrect; + offsetrect.setCoords(srect.left() + snap_offset, + srect.top() + snap_offset, + srect.right() - snap_offset, + srect.bottom() - snap_offset); + + if (snap_to_edges == BScreen::WindowResistance) { + // if we're not in the rectangle then don't snap to it. + if (! srect.contains(moving)) + continue; + } else { // BScreen::WindowSnap + // if we're not in the rectangle then don't snap to it. + if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(), + frame.rect.height()))) + continue; + } + + if (snap_to_edges == BScreen::WindowResistance) { + int dleft = offsetrect.left() - wleft, + dright = wright - offsetrect.right(), + dtop = offsetrect.top() - wtop, + dbottom = wbottom - offsetrect.bottom(); + + // snap left? + if (dleft > 0 && dleft < resistance_size) + dx = offsetrect.left(); + // snap right? + else if (dright > 0 && dright < resistance_size) + dx = offsetrect.right() - frame.rect.width() + 1; + + // snap top? + if (dtop > 0 && dtop < resistance_size) + dy = offsetrect.top(); + // snap bottom? + else if (dbottom > 0 && dbottom < resistance_size) + dy = offsetrect.bottom() - frame.rect.height() + 1; + } else { // BScreen::WindowSnap + int dleft = abs(wleft - offsetrect.left()), + dright = abs(wright - offsetrect.right()), + dtop = abs(wtop - offsetrect.top()), + dbottom = abs(wbottom - offsetrect.bottom()); + + // snap left? + if (dleft < snap_distance && dleft <= dright) + dx = offsetrect.left(); + // snap right? + else if (dright < snap_distance) + dx = offsetrect.right() - frame.rect.width() + 1; + + // snap top? + if (dtop < snap_distance && dtop <= dbottom) + dy = offsetrect.top(); + // snap bottom? + else if (dbottom < snap_distance) + dy = offsetrect.bottom() - frame.rect.height() + 1; + } + } + } +} + + +void BlackboxWindow::endMove(void) { + assert(flags.moving); + assert(blackbox->getChangingWindow() == this); + + flags.moving = False; + blackbox->setChangingWindow(0); + + if (! screen->doOpaqueMove()) { + /* when drawing the rubber band, we need to make sure we only draw inside + * the frame... frame.changing_* contain the new coords for the window, + * so we need to subtract 1 from changing_w/changing_h every where we + * draw the rubber band (for both moving and resizing) + */ + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + XUngrabServer(blackbox->getXDisplay()); + + configure(frame.changing.x(), frame.changing.y(), + frame.changing.width(), frame.changing.height()); + } else { + configure(frame.rect.x(), frame.rect.y(), + frame.rect.width(), frame.rect.height()); + } + screen->hideGeometry(); + + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + + // if there are any left over motions from the move, drop them now + XSync(blackbox->getXDisplay(), false); // make sure we don't miss any + XEvent e; + while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window, + MotionNotify, &e)); +} + + +void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) { + if (! (functions & Func_Resize)) return; + + assert(! (flags.resizing || flags.moving)); + + /* + Only one window can be moved/resized at a time. If another window is + already being moved or resized, then stop it before whating to work with + this one. + */ + BlackboxWindow *changing = blackbox->getChangingWindow(); + if (changing && changing != this) { + if (changing->flags.moving) + changing->endMove(); + else // if (changing->flags.resizing) + changing->endResize(); + } + + resize_dir = dir; + + Cursor cursor; + Corner anchor; + + switch (resize_dir) { + case BottomLeft: + anchor = TopRight; + cursor = blackbox->getLowerLeftAngleCursor(); + break; + + case BottomRight: + anchor = TopLeft; + cursor = blackbox->getLowerRightAngleCursor(); + break; + + case TopLeft: + anchor = BottomRight; + cursor = blackbox->getUpperLeftAngleCursor(); + break; + + case TopRight: + anchor = BottomLeft; + cursor = blackbox->getUpperRightAngleCursor(); + break; + + default: + assert(false); // unhandled Corner + return; // unreachable, for the compiler + } + + XGrabServer(blackbox->getXDisplay()); + XGrabPointer(blackbox->getXDisplay(), frame.window, False, + PointerMotionMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); + + flags.resizing = True; + blackbox->setChangingWindow(this); + + unsigned int gw, gh; + frame.changing = frame.rect; + + constrain(anchor, &gw, &gh); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + + screen->showGeometry(gw, gh); + + frame.grab_x = x_root; + frame.grab_y = y_root; +} + + +void BlackboxWindow::doResize(int x_root, int y_root) { + assert(flags.resizing); + assert(blackbox->getChangingWindow() == this); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + + unsigned int gw, gh; + Corner anchor; + int dx, dy; // the amount of change in the size of the window + + switch (resize_dir) { + case BottomLeft: + anchor = TopRight; + dx = - (x_root - frame.grab_x); + dy = + (y_root - frame.grab_y); + break; + case BottomRight: + anchor = TopLeft; + dx = + (x_root - frame.grab_x); + dy = + (y_root - frame.grab_y); + break; + case TopLeft: + anchor = BottomRight; + dx = - (x_root - frame.grab_x); + dy = - (y_root - frame.grab_y); + break; + case TopRight: + anchor = BottomLeft; + dx = + (x_root - frame.grab_x); + dy = - (y_root - frame.grab_y); + break; + + default: + assert(false); // unhandled Corner + return; // unreachable, for the compiler + } + + // make sure the user cant resize the window smaller than 0, which makes it + // wrap around and become huge + if (dx < -(signed)client.rect.width()) dx = -(signed)client.rect.width(); + if (dy < -(signed)client.rect.height()) dy = -(signed)client.rect.height(); + + frame.changing.setSize(frame.rect.width() + dx, frame.rect.height() + dy); + + constrain(anchor, &gw, &gh); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + + screen->showGeometry(gw, gh); +} + + +void BlackboxWindow::endResize(void) { + assert(flags.resizing); + assert(blackbox->getChangingWindow() == this); + + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + XUngrabServer(blackbox->getXDisplay()); + + // unset maximized state after resized when fully maximized + if (flags.maximized == 1) + maximize(0); + + flags.resizing = False; + blackbox->setChangingWindow(0); + + configure(frame.changing.x(), frame.changing.y(), + frame.changing.width(), frame.changing.height()); + screen->hideGeometry(); + + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + + // if there are any left over motions from the resize, drop them now + XSync(blackbox->getXDisplay(), false); // make sure we don't miss any + XEvent e; + while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window, + MotionNotify, &e)); +} + + +void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { +#if 0 + fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n", + client.window); +#endif + + if (flags.moving) { + doMove(me->x_root, me->y_root); + } else if (flags.resizing) { + doResize(me->x_root, me->y_root); + } else { + if ((functions & Func_Move) && + (me->state & Button1Mask) && + (frame.title == me->window || frame.label == me->window || + frame.handle == me->window || frame.window == me->window)) { + beginMove(me->x_root, me->y_root); + } else if ((functions & Func_Resize) && + ((me->state & Button1Mask) && + (me->window == frame.right_grip || + me->window == frame.left_grip)) || + ((me->state & Button3Mask) && (me->state & mod_mask) && + (frame.title == me->window || frame.label == me->window || + frame.handle == me->window || frame.window == me->window || + frame.right_grip == me->window || + frame.left_grip == me->window))) { + unsigned int zones = screen->getResizeZones(); + Corner corner; + + if (me->window == frame.left_grip) { + corner = BottomLeft; + } else if (me->window == frame.right_grip || zones == 1) { + corner = BottomRight; + } else { + bool top; + bool left = (me->x_root - frame.rect.x() <= + static_cast(frame.rect.width() / 2)); + if (zones == 2) + top = False; + else // (zones == 4) + top = (me->y_root - frame.rect.y() <= + static_cast(frame.rect.height() / 2)); + corner = (top ? (left ? TopLeft : TopRight) : + (left ? BottomLeft : BottomRight)); + } + + beginResize(me->x_root, me->y_root, corner); + } + } +} + + +void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) { + if (! (screen->isSloppyFocus() && isVisible() && isNormal())) + return; + + XEvent e; + bool leave = False, inferior = False; + + while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window, + LeaveNotify, &e)) { + if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) { + leave = True; + inferior = (e.xcrossing.detail == NotifyInferior); + } + } + + if (! leave || inferior) { + if (! isFocused()) { + bool success = setInputFocus(); + if (success) // if focus succeeded install the colormap + installColormap(True); // XXX: shouldnt we honour no install? + + /* + We only auto-raise when the window wasn't focused because otherwise + we run into problems with gtk+ drop-down lists. The window ends up + raising over the list. + */ + if (screen->doAutoRaise()) + timer->start(); + } + } +} + + +void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) { + if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal())) + return; + + installColormap(False); + + if (timer->isTiming()) + timer->stop(); +} + + +#ifdef SHAPE +void BlackboxWindow::shapeEvent(XShapeEvent *e) { + if (blackbox->hasShapeExtensions()) { + if (! e->shaped && flags.shaped) { + clearShape(); + flags.shaped = False; + } else if (e->shaped) { + configureShape(); + flags.shaped = True; + } + } +} +#endif // SHAPE + + +bool BlackboxWindow::validateClient(void) const { + XSync(blackbox->getXDisplay(), False); + + XEvent e; + if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, + DestroyNotify, &e) || + XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, + UnmapNotify, &e)) { + XPutBackEvent(blackbox->getXDisplay(), &e); + + return False; + } + + return True; +} + + +void BlackboxWindow::restore(bool remap) { + XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete); + XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); + XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask); + + // do not leave a shaded window as an icon unless it was an icon + if (flags.shaded && ! flags.iconic) + setState(NormalState); + + // erase the netwm stuff that we read when a window maps, so that it + // doesn't persist between mappings. + // (these are the ones read in getNetWMFlags().) + xatom->eraseValue(client.window, XAtom::net_wm_desktop); + xatom->eraseValue(client.window, XAtom::net_wm_state); + + restoreGravity(client.rect); + + XUnmapWindow(blackbox->getXDisplay(), frame.window); + XUnmapWindow(blackbox->getXDisplay(), client.window); + + XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw); + + XEvent ev; + if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window, + ReparentNotify, &ev)) { + remap = True; + } else { + // according to the ICCCM - if the client doesn't reparent to + // root, then we have to do it for them + XReparentWindow(blackbox->getXDisplay(), client.window, + screen->getRootWindow(), + client.rect.x(), client.rect.y()); + } + + if (remap) XMapWindow(blackbox->getXDisplay(), client.window); +} + + +// timer for autoraise +void BlackboxWindow::timeout(void) { + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); +} + + +void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) { + if ((net->flags & AttribShaded) && + ((blackbox_attrib.attrib & AttribShaded) != + (net->attrib & AttribShaded))) + shade(); + + if (flags.visible && // watch out for requests when we can not be seen + (net->flags & (AttribMaxVert | AttribMaxHoriz)) && + ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) != + (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) { + if (flags.maximized) { + maximize(0); + } else { + int button = 0; + + if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert)) + button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0); + else if (net->flags & AttribMaxVert) + button = ((net->attrib & AttribMaxVert) ? 2 : 0); + else if (net->flags & AttribMaxHoriz) + button = ((net->attrib & AttribMaxHoriz) ? 3 : 0); + + maximize(button); + } + } + + if ((net->flags & AttribOmnipresent) && + ((blackbox_attrib.attrib & AttribOmnipresent) != + (net->attrib & AttribOmnipresent))) + stick(); + + if ((net->flags & AttribWorkspace) && + (blackbox_attrib.workspace != net->workspace)) { + screen->reassociateWindow(this, net->workspace, True); + + if (screen->getCurrentWorkspaceID() != net->workspace) { + withdraw(); + } else { + show(); + screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); + } + } + + if (net->flags & AttribDecoration) { + switch (net->decoration) { + case DecorNone: + enableDecor(False); + break; + + default: + case DecorNormal: + case DecorTiny: + case DecorTool: + enableDecor(True); + break; + } + } +} + + +/* + * Set the sizes of all components of the window frame + * (the window decorations). + * These values are based upon the current style settings and the client + * window's dimensions. + */ +void BlackboxWindow::upsize(void) { + frame.bevel_w = screen->getBevelWidth(); + + if (decorations & Decor_Border) { + frame.border_w = screen->getBorderWidth(); + if (! isTransient()) + frame.mwm_border_w = screen->getFrameWidth(); + else + frame.mwm_border_w = 0; + } else { + frame.mwm_border_w = frame.border_w = 0; + } + + if (decorations & Decor_Titlebar) { + // the height of the titlebar is based upon the height of the font being + // used to display the window's title + WindowStyle *style = screen->getWindowStyle(); + frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2; + + frame.label_h = frame.title_h - (frame.bevel_w * 2); + frame.button_w = (frame.label_h - 2); + + // set the top frame margin + frame.margin.top = frame.border_w + frame.title_h + + frame.border_w + frame.mwm_border_w; + } else { + frame.title_h = 0; + frame.label_h = 0; + frame.button_w = 0; + + // set the top frame margin + frame.margin.top = frame.border_w + frame.mwm_border_w; + } + + // set the left/right frame margin + frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w; + + if (decorations & Decor_Handle) { + frame.grip_w = frame.button_w * 2; + frame.handle_h = screen->getHandleWidth(); + + // set the bottom frame margin + frame.margin.bottom = frame.border_w + frame.handle_h + + frame.border_w + frame.mwm_border_w; + } else { + frame.handle_h = 0; + frame.grip_w = 0; + + // set the bottom frame margin + frame.margin.bottom = frame.border_w + frame.mwm_border_w; + } + + /* + We first get the normal dimensions and use this to define the inside_w/h + then we modify the height if shading is in effect. + If the shade state is not considered then frame.rect gets reset to the + normal window size on a reconfigure() call resulting in improper + dimensions appearing in move/resize and other events. + */ + unsigned int + height = client.rect.height() + frame.margin.top + frame.margin.bottom, + width = client.rect.width() + frame.margin.left + frame.margin.right; + + frame.inside_w = width - (frame.border_w * 2); + frame.inside_h = height - (frame.border_w * 2); + + if (flags.shaded) + height = frame.title_h + (frame.border_w * 2); + frame.rect.setSize(width, height); +} + + +/* + * Calculate the size of the client window and constrain it to the + * size specified by the size hints of the client window. + * + * The logical width and height are placed into pw and ph, if they + * are non-zero. Logical size refers to the users perception of + * the window size (for example an xterm resizes in cells, not in pixels). + * pw and ph are then used to display the geometry during window moves, resize, + * etc. + * + * The physical geometry is placed into frame.changing_{x,y,width,height}. + * Physical geometry refers to the geometry of the window in pixels. + */ +void BlackboxWindow::constrain(Corner anchor, + unsigned int *pw, unsigned int *ph) { + // frame.changing represents the requested frame size, we need to + // strip the frame margin off and constrain the client size + frame.changing.setCoords(frame.changing.left() + frame.margin.left, + frame.changing.top() + frame.margin.top, + frame.changing.right() - frame.margin.right, + frame.changing.bottom() - frame.margin.bottom); + + unsigned int dw = frame.changing.width(), dh = frame.changing.height(), + base_width = (client.base_width) ? client.base_width : client.min_width, + base_height = (client.base_height) ? client.base_height : + client.min_height; + + // constrain, but only if the min/max are being used. if they aren't, then + // this resize is going to be from a ConfigureRequest because the window + // isn't allowed to be resized by the user. And in that case, we don't want + // to limit what the app can do + if (client.max_width > client.min_width || + client.max_height > client.min_height) { + if (dw < client.min_width) dw = client.min_width; + if (dh < client.min_height) dh = client.min_height; + if (dw > client.max_width) dw = client.max_width; + if (dh > client.max_height) dh = client.max_height; + } + + if (client.width_inc > 1) { + dw -= base_width; + dw /= client.width_inc; + } + if (client.height_inc > 1) { + dh -= base_height; + dh /= client.height_inc; + } + + if (pw) + *pw = dw; + + if (ph) + *ph = dh; + + if (client.width_inc > 1) { + dw *= client.width_inc; + dw += base_width; + } + if (client.height_inc > 1) { + dh *= client.height_inc; + dh += base_height; + } + + frame.changing.setSize(dw, dh); + + // add the frame margin back onto frame.changing + frame.changing.setCoords(frame.changing.left() - frame.margin.left, + frame.changing.top() - frame.margin.top, + frame.changing.right() + frame.margin.right, + frame.changing.bottom() + frame.margin.bottom); + + // move frame.changing to the specified anchor + int dx = 0, + dy = 0; + switch (anchor) { + case TopLeft: + break; + + case TopRight: + dx = frame.rect.right() - frame.changing.right(); + break; + + case BottomLeft: + dy = frame.rect.bottom() - frame.changing.bottom(); + break; + + case BottomRight: + dx = frame.rect.right() - frame.changing.right(); + dy = frame.rect.bottom() - frame.changing.bottom(); + break; + + default: + assert(false); // unhandled corner + } + frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy); +} + + +void WindowStyle::doJustify(const std::string &text, int &start_pos, + unsigned int max_length, + unsigned int modifier) const { + size_t text_len = text.size(); + unsigned int length; + + do { + length = font->measureString(string(text, 0, text_len)) + modifier; + } while (length > max_length && text_len-- > 0); + + switch (justify) { + case RightJustify: + start_pos += max_length - length; + break; + + case CenterJustify: + start_pos += (max_length - length) / 2; + break; + + case LeftJustify: + default: + break; + } +} + + +BWindowGroup::BWindowGroup(Blackbox *b, Window _group) + : blackbox(b), group(_group) { + XWindowAttributes wattrib; + if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) { + // group window doesn't seem to exist anymore + delete this; + return; + } + + XSelectInput(blackbox->getXDisplay(), group, + PropertyChangeMask | FocusChangeMask | StructureNotifyMask); + + blackbox->saveGroupSearch(group, this); +} + + +BWindowGroup::~BWindowGroup(void) { + blackbox->removeGroupSearch(group); +} + + +BlackboxWindow * +BWindowGroup::find(BScreen *screen, bool allow_transients) const { + BlackboxWindow *ret = blackbox->getFocusedWindow(); + + // does the focus window match (or any transient_fors)? + for (; ret; ret = ret->getTransientFor()) { + if (ret->getScreen() == screen && ret->getGroupWindow() == group && + (! ret->isTransient() || allow_transients)) + break; + } + + if (ret) return ret; + + // the focus window didn't match, look in the group's window list + BlackboxWindowList::const_iterator it, end = windowList.end(); + for (it = windowList.begin(); it != end; ++it) { + ret = *it; + if (ret->getScreen() == screen && ret->getGroupWindow() == group && + (! ret->isTransient() || allow_transients)) + break; + } + + return ret; +} diff --git a/src/window.hh b/src/window.hh new file mode 100644 index 00000000..e8249b08 --- /dev/null +++ b/src/window.hh @@ -0,0 +1,436 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Window.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Window_hh +#define __Window_hh + +extern "C" { +#include +#include +#ifdef SHAPE +# include +#endif // SHAPE +} + +#include + +#include "basedisplay.hh" +#include "timer.hh" +#include "util.hh" +#include "windowmenu.hh" + +#define MwmHintsFunctions (1l << 0) +#define MwmHintsDecorations (1l << 1) + +#define MwmFuncAll (1l << 0) +#define MwmFuncResize (1l << 1) +#define MwmFuncMove (1l << 2) +#define MwmFuncIconify (1l << 3) +#define MwmFuncMaximize (1l << 4) +#define MwmFuncClose (1l << 5) + +#define MwmDecorAll (1l << 0) +#define MwmDecorBorder (1l << 1) +#define MwmDecorHandle (1l << 2) +#define MwmDecorTitle (1l << 3) +#define MwmDecorMenu (1l << 4) // not used +#define MwmDecorIconify (1l << 5) +#define MwmDecorMaximize (1l << 6) + +// this structure only contains 3 elements... the Motif 2.0 structure contains +// 5... we only need the first 3... so that is all we will define +typedef struct MwmHints { + unsigned long flags, functions, decorations; +} MwmHints; + +#define PropMwmHintsElements 3 + +class BWindowGroup { +private: + Blackbox *blackbox; + Window group; + BlackboxWindowList windowList; + +public: + BWindowGroup(Blackbox *b, Window _group); + ~BWindowGroup(void); + + inline Window groupWindow(void) const { return group; } + + inline bool empty(void) const { return windowList.empty(); } + + void addWindow(BlackboxWindow *w) { windowList.push_back(w); } + void removeWindow(BlackboxWindow *w) { windowList.remove(w); } + + /* + find a window on the specified screen. the focused window (if any) is + checked first, otherwise the first matching window found is returned. + transients are returned only if allow_transients is True. + */ + BlackboxWindow *find(BScreen *screen, bool allow_transients = False) const; +}; + + +class BlackboxWindow : public TimeoutHandler { +public: + enum Function { Func_Resize = (1l << 0), + Func_Move = (1l << 1), + Func_Iconify = (1l << 2), + Func_Maximize = (1l << 3), + Func_Close = (1l << 4) }; + typedef unsigned char FunctionFlags; + + enum Decoration { Decor_Titlebar = (1l << 0), + Decor_Handle = (1l << 1), + Decor_Border = (1l << 2), + Decor_Iconify = (1l << 3), + Decor_Maximize = (1l << 4), + Decor_Close = (1l << 5) }; + typedef unsigned char DecorationFlags; + + enum WindowType { Type_Desktop, + Type_Dock, + Type_Toolbar, + Type_Menu, + Type_Utility, + Type_Splash, + Type_Dialog, + Type_Normal }; + + enum Corner { TopLeft, + TopRight, + BottomLeft, + BottomRight }; + +private: + Blackbox *blackbox; + BScreen *screen; + XAtom *xatom; + BTimer *timer; + BlackboxAttributes blackbox_attrib; + + Time lastButtonPressTime; // used for double clicks, when were we clicked + Windowmenu *windowmenu; + + unsigned int window_number; + unsigned long current_state; + unsigned int mod_mask; // the mod mask used to grab buttons + + enum FocusMode { F_NoInput = 0, F_Passive, + F_LocallyActive, F_GloballyActive }; + FocusMode focus_mode; + + struct _flags { + bool moving, // is moving? + resizing, // is resizing? + shaded, // is shaded? + visible, // is visible? + iconic, // is iconified? + focused, // has focus? + stuck, // is omnipresent? + modal, // is modal? (must be dismissed to continue) + skip_taskbar, // skipped by taskbars? + skip_pager, // skipped by pagers? + fullscreen, // a fullscreen window? + send_focus_message, // should we send focus messages to our client? + shaped; // does the frame use the shape extension? + unsigned int maximized; // maximize is special, the number corresponds + // with a mouse button + // if 0, not maximized + // 1 = HorizVert, 2 = Vertical, 3 = Horizontal + } flags; + + struct _client { + Window window, // the client's window + window_group; + BlackboxWindow *transient_for; // which window are we a transient for? + BlackboxWindowList transientList; // which windows are our transients? + + std::string title, icon_title; + + Rect rect; + Strut strut; + + int old_bw; // client's borderwidth + + unsigned int + min_width, min_height, // can not be resized smaller + max_width, max_height, // can not be resized larger + width_inc, height_inc, // increment step +#if 0 // not supported at the moment + min_aspect_x, min_aspect_y, // minimum aspect ratio + max_aspect_x, max_aspect_y, // maximum aspect ratio +#endif + base_width, base_height, + win_gravity; + + unsigned long initial_state, normal_hint_flags; + } client; + + FunctionFlags functions; + /* + * what decorations do we have? + * this is based on the type of the client window as well as user input + */ + DecorationFlags decorations; + DecorationFlags mwm_decorations; + Corner resize_dir; + WindowType window_type; + + /* + * client window = the application's window + * frame window = the window drawn around the outside of the client window + * by the window manager which contains items like the + * titlebar and close button + * title = the titlebar drawn above the client window, it displays the + * window's name and any buttons for interacting with the window, + * such as iconify, maximize, and close + * label = the window in the titlebar where the title is drawn + * buttons = maximize, iconify, close + * handle = the bar drawn at the bottom of the window, which contains the + * left and right grips used for resizing the window + * grips = the smaller reactangles in the handle, one of each side of it. + * When clicked and dragged, these resize the window interactively + * border = the line drawn around the outside edge of the frame window, + * between the title, the bordered client window, and the handle. + * Also drawn between the grips and the handle + */ + + struct _frame { + // u -> unfocused, f -> has focus, p -> pressed + unsigned long ulabel_pixel, flabel_pixel, utitle_pixel, + ftitle_pixel, uhandle_pixel, fhandle_pixel, ubutton_pixel, + fbutton_pixel, pfbutton_pixel, pubutton_pixel, + uborder_pixel, fborder_pixel, ugrip_pixel, fgrip_pixel; + Pixmap ulabel, flabel, utitle, ftitle, uhandle, fhandle, + ubutton, fbutton, pfbutton, pubutton, ugrip, fgrip; + + Window window, // the frame + plate, // holds the client + title, + label, + handle, + close_button, iconify_button, maximize_button, stick_button, + right_grip, left_grip; + + /* + * size and location of the box drawn while the window dimensions or + * location is being changed, ie. resized or moved + */ + Rect changing; + + Rect rect; // frame geometry + Strut margin; // margins between the frame and client + + int grab_x, grab_y; // where was the window when it was grabbed? + + unsigned int inside_w, inside_h, // window w/h without border_w + title_h, label_w, label_h, handle_h, + button_w, grip_w, mwm_border_w, border_w, + bevel_w; + } frame; + + BlackboxWindow(const BlackboxWindow&); + BlackboxWindow& operator=(const BlackboxWindow&); + + bool getState(void); + Window createToplevelWindow(); + Window createChildWindow(Window parent, unsigned long event_mask, + Cursor = None); + + bool getWindowType(void); + void updateStrut(void); + void getWMName(void); + void getWMIconName(void); + void getWMNormalHints(void); + void getWMProtocols(void); + void getWMHints(void); + void getNetWMHints(void); + void getMWMHints(void); + bool getBlackboxHints(void); + void getTransientInfo(void); + void setNetWMAttributes(void); + void associateClientWindow(void); + void decorate(void); + void decorateLabel(void); + void positionButtons(bool redecorate_label = False); + void positionWindows(void); + void createHandle(void); + void destroyHandle(void); + void createTitlebar(void); + void destroyTitlebar(void); + void createCloseButton(void); + void destroyCloseButton(void); + void createIconifyButton(void); + void destroyIconifyButton(void); + void createMaximizeButton(void); + void destroyMaximizeButton(void); + void createStickyButton(void); + void destroyStickyButton(void); + void redrawWindowFrame(void) const; + void redrawLabel(void) const; + void redrawAllButtons(void) const; + void BlackboxWindow::redrawButton(bool pressed, Window win, + Pixmap fppix, unsigned long fppixel, + Pixmap uppix, unsigned long uppixel, + Pixmap fpix, unsigned long fpixel, + Pixmap upix, unsigned long upixel) const; + void redrawCloseButton(bool pressed) const; + void redrawIconifyButton(bool pressed) const; + void redrawMaximizeButton(bool pressed) const; + void redrawStickyButton(bool pressed) const; + void applyGravity(Rect &r); + void restoreGravity(Rect &r); + void setAllowedActions(void); + void setState(unsigned long new_state); + void upsize(void); + void doMove(int x_root, int y_root); + void doWorkspaceWarping(int x_root, int y_root, int &dx); + void doWindowSnapping(int &dx, int &dy); + void endMove(void); + void doResize(int x_root, int y_root); + void endResize(void); + + void constrain(Corner anchor, unsigned int *pw = 0, unsigned int *ph = 0); + +public: + BlackboxWindow(Blackbox *b, Window w, BScreen *s); + virtual ~BlackboxWindow(void); + + inline bool isTransient(void) const { return client.transient_for != 0; } + inline bool isFocused(void) const { return flags.focused; } + inline bool isVisible(void) const { return flags.visible; } + inline bool isIconic(void) const { return flags.iconic; } + inline bool isShaded(void) const { return flags.shaded; } + inline bool isMaximized(void) const { return flags.maximized; } + inline bool isMaximizedHoriz(void) const { return flags.maximized == 3; } + inline bool isMaximizedVert(void) const { return flags.maximized == 2; } + inline bool isMaximizedFull(void) const { return flags.maximized == 1; } + inline bool isStuck(void) const { return flags.stuck; } + inline bool isModal(void) const { return flags.modal; } + inline bool isIconifiable(void) const { return functions & Func_Iconify; } + inline bool isMaximizable(void) const { return functions & Func_Maximize; } + inline bool isResizable(void) const { return functions & Func_Resize; } + inline bool isClosable(void) const { return functions & Func_Close; } + + // is a 'normal' window? meaning, a standard client application + inline bool isNormal(void) const + { return window_type == Type_Dialog || window_type == Type_Normal || + window_type == Type_Toolbar || window_type == Type_Utility; } + inline bool isTopmost(void) const + { return window_type == Type_Toolbar || window_type == Type_Utility; } + inline bool isDesktop(void) const { return window_type == Type_Desktop; } + + inline bool hasTitlebar(void) const { return decorations & Decor_Titlebar; } + + inline const BlackboxWindowList &getTransients(void) const + { return client.transientList; } + BlackboxWindow *getTransientFor(void) const; + + inline BScreen *getScreen(void) const { return screen; } + + inline Window getFrameWindow(void) const { return frame.window; } + inline Window getClientWindow(void) const { return client.window; } + inline Window getGroupWindow(void) const { return client.window_group; } + + inline Windowmenu * getWindowmenu(void) const { return windowmenu; } + + inline const char *getTitle(void) const + { return client.title.c_str(); } + inline const char *getIconTitle(void) const + { return client.icon_title.c_str(); } + + inline unsigned int getWorkspaceNumber(void) const + { return blackbox_attrib.workspace; } + inline unsigned int getWindowNumber(void) const { return window_number; } + + inline const Rect &frameRect(void) const { return frame.rect; } + inline const Rect &clientRect(void) const { return client.rect; } + + inline unsigned int getTitleHeight(void) const + { return frame.title_h; } + + inline void setWindowNumber(int n) { window_number = n; } + + bool validateClient(void) const; + bool setInputFocus(void); + + // none of these are used by the window manager, they are here to persist + // them properly in the window's netwm state property. + inline bool skipTaskbar(void) const { return flags.skip_taskbar; } + inline void setSkipTaskbar(const bool s) { flags.skip_taskbar = s; } + inline bool skipPager(void) const { return flags.skip_pager; } + inline void setSkipPager(const bool s) { flags.skip_pager = s; } + inline bool isFullscreen(void) const { return flags.fullscreen; } + inline void setFullscreen(const bool f) { flags.fullscreen = f; } + + inline void setModal(const bool m) { flags.modal = m; } + + void beginMove(int x_root, int y_root); + void beginResize(int x_root, int y_root, Corner dir); + void enableDecor(bool enable); + void setupDecor(); + void setFocusFlag(bool focus); + void iconify(void); + void deiconify(bool reassoc = True, bool raise = True); + void show(void); + void close(void); + void withdraw(void); + void maximize(unsigned int button); + void remaximize(void); + void shade(void); + void stick(void); + void reconfigure(void); + void grabButtons(void); + void ungrabButtons(void); + void installColormap(bool install); + void restore(bool remap); + void configure(int dx, int dy, unsigned int dw, unsigned int dh); + void setWorkspace(unsigned int n); + void changeBlackboxHints(const BlackboxHints *net); + void restoreAttributes(void); + + void buttonPressEvent(const XButtonEvent *be); + void buttonReleaseEvent(const XButtonEvent *re); + void motionNotifyEvent(const XMotionEvent *me); + void destroyNotifyEvent(const XDestroyWindowEvent* /*unused*/); + void mapRequestEvent(const XMapRequestEvent *mre); + void unmapNotifyEvent(const XUnmapEvent* /*unused*/); + void reparentNotifyEvent(const XReparentEvent* /*unused*/); + void propertyNotifyEvent(const XPropertyEvent *pe); + void exposeEvent(const XExposeEvent *ee); + void configureRequestEvent(const XConfigureRequestEvent *cr); + void enterNotifyEvent(const XCrossingEvent *ce); + void leaveNotifyEvent(const XCrossingEvent* /*unused*/); + +#ifdef SHAPE + void configureShape(void); + void clearShape(void); + void shapeEvent(XShapeEvent * /*unused*/); +#endif // SHAPE + + virtual void timeout(void); +}; + + +#endif // __Window_hh diff --git a/src/workspace.cc b/src/workspace.cc new file mode 100644 index 00000000..8c44adab --- /dev/null +++ b/src/workspace.cc @@ -0,0 +1,840 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Workspace.cc for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +extern "C" { +#include +#include + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef HAVE_STRING_H +# include +#endif // HAVE_STRING_H +} + +#include + +#include +#include + +using std::string; + +#include "blackbox.hh" +#include "clientmenu.hh" +#include "font.hh" +#include "netizen.hh" +#include "screen.hh" +#include "toolbar.hh" +#include "util.hh" +#include "window.hh" +#include "workspace.hh" +#include "windowmenu.hh" +#include "xatom.hh" + + +Workspace::Workspace(BScreen *scrn, unsigned int i) { + screen = scrn; + xatom = screen->getBlackbox()->getXAtom(); + + cascade_x = cascade_y = 0; +#ifdef XINERAMA + cascade_region = 0; +#endif // XINERAMA + + id = i; + + clientmenu = new Clientmenu(this); + + lastfocus = (BlackboxWindow *) 0; + + readName(); +} + + +void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) { + assert(w != 0); + + if (place) placeWindow(w); + + stackingList.push_front(w); + + if (! sticky) + w->setWorkspace(id); + + if (! w->isNormal()) { + if (! sticky) { + // just give it some number, else bad things happen as it is assumed to + // not be on a workspace + w->setWindowNumber(0); + } + } else { + if (! sticky) + w->setWindowNumber(windowList.size()); + + windowList.push_back(w); + + clientmenu->insert(w->getTitle()); + clientmenu->update(); + + if (! sticky) + screen->updateNetizenWindowAdd(w->getClientWindow(), id); + + if (screen->doFocusNew() || (w->isTransient() && w->getTransientFor() && + w->getTransientFor()->isFocused())) { + if (id != screen->getCurrentWorkspaceID()) { + /* + not on the focused workspace, so the window is not going to get focus + but if the user wants new windows focused, then it should get focus + when this workspace does become focused. + */ + lastfocus = w; + } + } + } + + if (! w->isDesktop()) + raiseWindow(w); + else + lowerWindow(w); +} + + +void Workspace::removeWindow(BlackboxWindow *w, bool sticky) { + assert(w != 0); + + stackingList.remove(w); + + // pass focus to the next appropriate window + if ((w->isFocused() || w == lastfocus) && + ! screen->getBlackbox()->doShutdown()) { + focusFallback(w); + } + + if (! w->isNormal()) return; + + BlackboxWindowList::iterator it, end = windowList.end(); + int i; + for (i = 0, it = windowList.begin(); it != end; ++it, ++i) + if (*it == w) + break; + assert(it != end); + + windowList.erase(it); + clientmenu->remove(i); + clientmenu->update(); + + if (! sticky) { + screen->updateNetizenWindowDel(w->getClientWindow()); + + BlackboxWindowList::iterator it = windowList.begin(); + const BlackboxWindowList::iterator end = windowList.end(); + unsigned int i = 0; + for (; it != end; ++it, ++i) + (*it)->setWindowNumber(i); + } + + if (i == 0) { + cascade_x = cascade_y = 0; +#ifdef XINERAMA + cascade_region = 0; +#endif // XINERAMA + } +} + + +void Workspace::focusFallback(const BlackboxWindow *old_window) { + BlackboxWindow *newfocus = 0; + + if (id == screen->getCurrentWorkspaceID()) { + // The window is on the visible workspace. + + // if it's a transient, then try to focus its parent + if (old_window && old_window->isTransient()) { + newfocus = old_window->getTransientFor(); + + if (! newfocus || + newfocus->isIconic() || // do not focus icons + newfocus->getWorkspaceNumber() != id || // or other workspaces + ! newfocus->setInputFocus()) + newfocus = 0; + } + + if (! newfocus) { + BlackboxWindowList::iterator it = stackingList.begin(), + end = stackingList.end(); + for (; it != end; ++it) { + BlackboxWindow *tmp = *it; + if (tmp && tmp->isNormal() && tmp->setInputFocus()) { + // we found our new focus target + newfocus = tmp; + break; + } + } + } + + screen->getBlackbox()->setFocusedWindow(newfocus); + } else { + // The window is not on the visible workspace. + + if (old_window && lastfocus == old_window) { + // The window was the last-focus target, so we need to replace it. + BlackboxWindow *win = (BlackboxWindow*) 0; + if (! stackingList.empty()) + win = stackingList.front(); + setLastFocusedWindow(win); + } + } +} + + +void Workspace::setFocused(const BlackboxWindow *w, bool focused) { + BlackboxWindowList::iterator it, end = windowList.end(); + int i; + for (i = 0, it = windowList.begin(); it != end; ++it, ++i) + if (*it == w) + break; + // if its == end, then a window thats not in the windowList + // got focused, such as a !isNormal() window. + if (it != end) + clientmenu->setItemSelected(i, focused); +} + + +void Workspace::removeAll(void) { + while (! windowList.empty()) + windowList.front()->iconify(); +} + +void Workspace::showAll(void) { + BlackboxWindowList::iterator it = stackingList.begin(); + const BlackboxWindowList::iterator end = stackingList.end(); + for (; it != end; ++it) { + BlackboxWindow *bw = *it; + // sticky windows arent unmapped on a workspace change so we don't have ot + // map them, but sometimes on a restart, another app can unmap our sticky + // windows, so we map on startup always + if (! bw->isStuck() || screen->getBlackbox()->isStartup()) + bw->show(); + } +} + + +void Workspace::hideAll(void) { + // withdraw in reverse order to minimize the number of Expose events + + BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend()); + + BlackboxWindowList::iterator it = lst.begin(); + const BlackboxWindowList::iterator end = lst.end(); + for (; it != end; ++it) { + BlackboxWindow *bw = *it; + // don't hide sticky windows, or they'll end up flickering on a workspace + // change + if (! bw->isStuck()) + bw->withdraw(); + } +} + + + +/* + * returns the number of transients for win, plus the number of transients + * associated with each transient of win + */ +static unsigned int countTransients(const BlackboxWindow * const win) { + BlackboxWindowList transients = win->getTransients(); + if (transients.empty()) return 0; + + unsigned int ret = transients.size(); + BlackboxWindowList::const_iterator it = transients.begin(), + end = transients.end(); + for (; it != end; ++it) + ret += countTransients(*it); + + return ret; +} + + +/* + * puts the transients of win into the stack. windows are stacked above + * the window before it in the stackvector being iterated, meaning + * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above + * stack[1], etc... + */ +void Workspace::raiseTransients(const BlackboxWindow * const win, + StackVector::iterator &stack) { + if (win->getTransients().empty()) return; // nothing to do + + // put win's transients in the stack + BlackboxWindowList::const_iterator it, end = win->getTransients().end(); + for (it = win->getTransients().begin(); it != end; ++it) { + BlackboxWindow *w = *it; + *stack++ = w->getFrameWindow(); + screen->updateNetizenWindowRaise(w->getClientWindow()); + + if (! w->isIconic()) { + Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber()); + wkspc->stackingList.remove(w); + wkspc->stackingList.push_front(w); + } + } + + // put transients of win's transients in the stack + for (it = win->getTransients().begin(); it != end; ++it) + raiseTransients(*it, stack); +} + + +void Workspace::lowerTransients(const BlackboxWindow * const win, + StackVector::iterator &stack) { + if (win->getTransients().empty()) return; // nothing to do + + // put transients of win's transients in the stack + BlackboxWindowList::const_reverse_iterator it, + end = win->getTransients().rend(); + for (it = win->getTransients().rbegin(); it != end; ++it) + lowerTransients(*it, stack); + + // put win's transients in the stack + for (it = win->getTransients().rbegin(); it != end; ++it) { + BlackboxWindow *w = *it; + *stack++ = w->getFrameWindow(); + screen->updateNetizenWindowLower(w->getClientWindow()); + + if (! w->isIconic()) { + Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber()); + wkspc->stackingList.remove(w); + wkspc->stackingList.push_back(w); + } + } +} + + +void Workspace::raiseWindow(BlackboxWindow *w) { + BlackboxWindow *win = w; + + if (win->isDesktop()) return; + + // walk up the transient_for's to the window that is not a transient + while (win->isTransient() && win->getTransientFor()) + win = win->getTransientFor(); + + // get the total window count (win and all transients) + unsigned int i = 1 + countTransients(win); + + // stack the window with all transients above + StackVector stack_vector(i); + StackVector::iterator stack = stack_vector.begin(); + + *(stack++) = win->getFrameWindow(); + screen->updateNetizenWindowRaise(win->getClientWindow()); + if (! (win->isIconic() || win->isDesktop())) { + Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList.remove(win); + wkspc->stackingList.push_front(win); + } + + raiseTransients(win, stack); + + screen->raiseWindows(&stack_vector[0], stack_vector.size()); +} + + +void Workspace::lowerWindow(BlackboxWindow *w) { + BlackboxWindow *win = w; + + // walk up the transient_for's to the window that is not a transient + while (win->isTransient() && win->getTransientFor()) + win = win->getTransientFor(); + + // get the total window count (win and all transients) + unsigned int i = 1 + countTransients(win); + + // stack the window with all transients above + StackVector stack_vector(i); + StackVector::iterator stack = stack_vector.begin(); + + lowerTransients(win, stack); + + *(stack++) = win->getFrameWindow(); + screen->updateNetizenWindowLower(win->getClientWindow()); + if (! (win->isIconic() || win->isDesktop())) { + Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList.remove(win); + wkspc->stackingList.push_back(win); + } + + screen->lowerWindows(&stack_vector[0], stack_vector.size()); +} + + +void Workspace::reconfigure(void) { + clientmenu->reconfigure(); + std::for_each(windowList.begin(), windowList.end(), + std::mem_fun(&BlackboxWindow::reconfigure)); +} + + +BlackboxWindow *Workspace::getWindow(unsigned int index) { + if (index < windowList.size()) { + BlackboxWindowList::iterator it = windowList.begin(); + while (index-- > 0) // increment to index + ++it; + return *it; + } + + return 0; +} + + +BlackboxWindow* +Workspace::getNextWindowInList(BlackboxWindow *w) { + BlackboxWindowList::iterator it = std::find(windowList.begin(), + windowList.end(), + w); + assert(it != windowList.end()); // window must be in list + ++it; // next window + if (it == windowList.end()) + return windowList.front(); // if we walked off the end, wrap around + + return *it; +} + + +BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) { + BlackboxWindowList::iterator it = std::find(windowList.begin(), + windowList.end(), + w); + assert(it != windowList.end()); // window must be in list + if (it == windowList.begin()) + return windowList.back(); // if we walked of the front, wrap around + + return *(--it); +} + + +BlackboxWindow* Workspace::getTopWindowOnStack(void) const { + assert(! stackingList.empty()); + return stackingList.front(); +} + + +void Workspace::sendWindowList(Netizen &n) { + BlackboxWindowList::iterator it = windowList.begin(), + end = windowList.end(); + for(; it != end; ++it) + n.sendWindowAdd((*it)->getClientWindow(), getID()); +} + + +unsigned int Workspace::getCount(void) const { + return windowList.size(); +} + + +void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const { + BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin(); + const BlackboxWindowList::const_reverse_iterator end = stackingList.rend(); + for (; it != end; ++it) + // don't add desktop wnidows, or sticky windows more than once + if (! ( (*it)->isDesktop() || + ((*it)->isStuck() && id != screen->getCurrentWorkspaceID()))) + stack_order.push_back(*it); +} + + +bool Workspace::isCurrent(void) const { + return (id == screen->getCurrentWorkspaceID()); +} + + +bool Workspace::isLastWindow(const BlackboxWindow* const w) const { + return (w == windowList.back()); +} + + +void Workspace::setCurrent(void) { + screen->changeWorkspaceID(id); +} + + +void Workspace::readName(void) { + XAtom::StringVect namesList; + unsigned long numnames = id + 1; + + // attempt to get from the _NET_WM_DESKTOP_NAMES property + if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names, + XAtom::utf8, numnames, namesList) && + namesList.size() > id) { + name = namesList[id]; + + clientmenu->setLabel(name); + clientmenu->update(); + } else { + /* + Use a default name. This doesn't actually change the class. That will + happen after the setName changes the root property, and that change + makes its way back to this function. + */ + string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat, + "Workspace %d"); + assert(tmp.length() < 32); + char default_name[32]; + sprintf(default_name, tmp.c_str(), id + 1); + + setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property + } +} + + +void Workspace::setName(const string& new_name) { + // set the _NET_WM_DESKTOP_NAMES property with the new name + XAtom::StringVect namesList; + unsigned long numnames = (unsigned) -1; + if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names, + XAtom::utf8, numnames, namesList) && + namesList.size() > id) + namesList[id] = new_name; + else + namesList.push_back(new_name); + + xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names, + XAtom::utf8, namesList); +} + + +/* + * Calculate free space available for window placement. + */ +Workspace::rectList Workspace::calcSpace(const Rect &win, + const rectList &spaces) const { + Rect isect, extra; + rectList result; + rectList::const_iterator siter, end = spaces.end(); + for (siter = spaces.begin(); siter != end; ++siter) { + const Rect &curr = *siter; + + if(! win.intersects(curr)) { + result.push_back(curr); + continue; + } + + /* Use an intersection of win and curr to determine the space around + * curr that we can use. + * + * NOTE: the spaces calculated can overlap. + */ + isect = curr & win; + + // left + extra.setCoords(curr.left(), curr.top(), + isect.left() - screen->getSnapOffset(), curr.bottom()); + if (extra.valid()) result.push_back(extra); + + // top + extra.setCoords(curr.left(), curr.top(), + curr.right(), isect.top() - screen->getSnapOffset()); + if (extra.valid()) result.push_back(extra); + + // right + extra.setCoords(isect.right() + screen->getSnapOffset(), curr.top(), + curr.right(), curr.bottom()); + if (extra.valid()) result.push_back(extra); + + // bottom + extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(), + curr.right(), curr.bottom()); + if (extra.valid()) result.push_back(extra); + } + return result; +} + + +static bool rowRLBT(const Rect &first, const Rect &second) { + if (first.bottom() == second.bottom()) + return first.right() > second.right(); + return first.bottom() > second.bottom(); +} + +static bool rowRLTB(const Rect &first, const Rect &second) { + if (first.y() == second.y()) + return first.right() > second.right(); + return first.y() < second.y(); +} + +static bool rowLRBT(const Rect &first, const Rect &second) { + if (first.bottom() == second.bottom()) + return first.x() < second.x(); + return first.bottom() > second.bottom(); +} + +static bool rowLRTB(const Rect &first, const Rect &second) { + if (first.y() == second.y()) + return first.x() < second.x(); + return first.y() < second.y(); +} + +static bool colLRTB(const Rect &first, const Rect &second) { + if (first.x() == second.x()) + return first.y() < second.y(); + return first.x() < second.x(); +} + +static bool colLRBT(const Rect &first, const Rect &second) { + if (first.x() == second.x()) + return first.bottom() > second.bottom(); + return first.x() < second.x(); +} + +static bool colRLTB(const Rect &first, const Rect &second) { + if (first.right() == second.right()) + return first.y() < second.y(); + return first.right() > second.right(); +} + +static bool colRLBT(const Rect &first, const Rect &second) { + if (first.right() == second.right()) + return first.bottom() > second.bottom(); + return first.right() > second.right(); +} + + +bool Workspace::smartPlacement(Rect& win) { + rectList spaces; + + //initially the entire screen is free +#ifdef XINERAMA + if (screen->isXineramaActive() && + screen->getBlackbox()->doXineramaPlacement()) { + RectList availableAreas = screen->allAvailableAreas(); + RectList::iterator it, end = availableAreas.end(); + + for (it = availableAreas.begin(); it != end; ++it) { + Rect r = *it; + r.setRect(r.x() + screen->getSnapOffset(), + r.y() + screen->getSnapOffset(), + r.width() - screen->getSnapOffset(), + r.height() - screen->getSnapOffset()); + spaces.push_back(*it); + } + } else +#endif // XINERAMA + { + Rect r = screen->availableArea(); + r.setRect(r.x() + screen->getSnapOffset(), + r.y() + screen->getSnapOffset(), + r.width() - screen->getSnapOffset(), + r.height() - screen->getSnapOffset()); + spaces.push_back(r); + } + + //Find Free Spaces + BlackboxWindowList::const_iterator wit = windowList.begin(), + end = windowList.end(); + Rect tmp; + for (; wit != end; ++wit) { + const BlackboxWindow* const curr = *wit; + + // watch for shaded windows and full-maxed windows + if (curr->isShaded()) { + if (screen->getPlaceIgnoreShaded()) continue; + } else if (curr->isMaximizedFull()) { + if (screen->getPlaceIgnoreMaximized()) continue; + } + + tmp.setRect(curr->frameRect().x(), curr->frameRect().y(), + curr->frameRect().width() + screen->getBorderWidth(), + curr->frameRect().height() + screen->getBorderWidth()); + + spaces = calcSpace(tmp, spaces); + } + + if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) { + if(screen->getColPlacementDirection() == BScreen::TopBottom) + std::sort(spaces.begin(), spaces.end(), rowLRTB); + else + std::sort(spaces.begin(), spaces.end(), rowLRBT); + } else { + if(screen->getColPlacementDirection() == BScreen::TopBottom) + std::sort(spaces.begin(), spaces.end(), rowRLTB); + else + std::sort(spaces.begin(), spaces.end(), rowRLBT); + } + } else { + if(screen->getColPlacementDirection() == BScreen::TopBottom) { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) + std::sort(spaces.begin(), spaces.end(), colLRTB); + else + std::sort(spaces.begin(), spaces.end(), colRLTB); + } else { + if(screen->getRowPlacementDirection() == BScreen::LeftRight) + std::sort(spaces.begin(), spaces.end(), colLRBT); + else + std::sort(spaces.begin(), spaces.end(), colRLBT); + } + } + + rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end(); + for(; sit != spaces_end; ++sit) { + if (sit->width() >= win.width() && sit->height() >= win.height()) + break; + } + + if (sit == spaces_end) + return False; + + //set new position based on the empty space found + const Rect& where = *sit; + win.setX(where.x()); + win.setY(where.y()); + + // adjust the location() based on left/right and top/bottom placement + if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) { + if (screen->getRowPlacementDirection() == BScreen::RightLeft) + win.setX(where.right() - win.width()); + if (screen->getColPlacementDirection() == BScreen::BottomTop) + win.setY(where.bottom() - win.height()); + } else { + if (screen->getColPlacementDirection() == BScreen::BottomTop) + win.setY(win.y() + where.height() - win.height()); + if (screen->getRowPlacementDirection() == BScreen::RightLeft) + win.setX(win.x() + where.width() - win.width()); + } + return True; +} + + +bool Workspace::underMousePlacement(Rect &win) { + int x, y, rx, ry; + Window c, r; + unsigned int m; + XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(), + &r, &c, &rx, &ry, &x, &y, &m); + + Rect area; +#ifdef XINERAMA + if (screen->isXineramaActive() && + screen->getBlackbox()->doXineramaPlacement()) { + RectList availableAreas = screen->allAvailableAreas(); + RectList::iterator it, end = availableAreas.end(); + + for (it = availableAreas.begin(); it != end; ++it) + if (it->contains(rx, ry)) break; + assert(it != end); // the mouse isn't inside an area? + area = *it; + } else +#endif // XINERAMA + area = screen->availableArea(); + + x = rx - win.width() / 2; + y = ry - win.height() / 2; + + if (x < area.x()) + x = area.x(); + if (y < area.y()) + y = area.y(); + if (x + win.width() > area.x() + area.width()) + x = area.x() + area.width() - win.width(); + if (y + win.height() > area.y() + area.height()) + y = area.y() + area.height() - win.height(); + + win.setX(x); + win.setY(y); + + return True; +} + + +bool Workspace::cascadePlacement(Rect &win, const int offset) { + Rect area; + +#ifdef XINERAMA + if (screen->isXineramaActive() && + screen->getBlackbox()->doXineramaPlacement()) { + area = screen->allAvailableAreas()[cascade_region]; + } else +#endif // XINERAMA + area = screen->availableArea(); + + if ((static_cast(cascade_x + win.width()) > area.right() + 1) || + (static_cast(cascade_y + win.height()) > area.bottom() + 1)) { + cascade_x = cascade_y = 0; +#ifdef XINERAMA + if (screen->isXineramaActive() && + screen->getBlackbox()->doXineramaPlacement()) { + // go to the next xinerama region, and use its area + if (++cascade_region >= screen->allAvailableAreas().size()) + cascade_region = 0; + area = screen->allAvailableAreas()[cascade_region]; + } +#endif // XINERAMA + } + + if (cascade_x == 0) { + cascade_x = area.x() + offset; + cascade_y = area.y() + offset; + } + + win.setPos(cascade_x, cascade_y); + + cascade_x += offset; + cascade_y += offset; + + return True; +} + + +void Workspace::placeWindow(BlackboxWindow *win) { + Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height()); + bool placed = False; + + switch (screen->getPlacementPolicy()) { + case BScreen::RowSmartPlacement: + case BScreen::ColSmartPlacement: + placed = smartPlacement(new_win); + break; + case BScreen::UnderMousePlacement: + case BScreen::ClickMousePlacement: + placed = underMousePlacement(new_win); + default: + break; // handled below + } // switch + + if (placed == False) + cascadePlacement(new_win, (win->getTitleHeight() + + screen->getBorderWidth() * 2)); + + if (new_win.right() > screen->availableArea().right()) + new_win.setX(screen->availableArea().left()); + if (new_win.bottom() > screen->availableArea().bottom()) + new_win.setY(screen->availableArea().top()); + + win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height()); +} diff --git a/src/workspace.hh b/src/workspace.hh new file mode 100644 index 00000000..df0411e1 --- /dev/null +++ b/src/workspace.hh @@ -0,0 +1,123 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +// Workspace.hh for Blackbox - an X11 Window manager +// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry +// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __Workspace_hh +#define __Workspace_hh + +extern "C" { +#include +} + +#include +#include +#include + +class BScreen; +class Clientmenu; +class Workspace; +class BlackboxWindow; +class Netizen; + +typedef std::list BlackboxWindowList; +typedef std::vector StackVector; + +class Workspace { +private: + BScreen *screen; + BlackboxWindow *lastfocus; + Clientmenu *clientmenu; + XAtom *xatom; + + BlackboxWindowList stackingList, windowList; + + std::string name; + unsigned int id; + unsigned int cascade_x, cascade_y; +#ifdef XINERAMA + unsigned int cascade_region; +#endif // XINERAMA + + Workspace(const Workspace&); + Workspace& operator=(const Workspace&); + + void raiseTransients(const BlackboxWindow * const win, + StackVector::iterator &stack); + void lowerTransients(const BlackboxWindow * const win, + StackVector::iterator &stack); + + typedef std::vector rectList; + rectList calcSpace(const Rect &win, const rectList &spaces) const; + + void placeWindow(BlackboxWindow *win); + bool cascadePlacement(Rect& win, const int offset); + bool smartPlacement(Rect& win); + bool underMousePlacement(Rect& win); + +public: + Workspace(BScreen *scrn, unsigned int i = 0); + + inline BScreen *getScreen(void) { return screen; } + + inline BlackboxWindow *getLastFocusedWindow(void) { return lastfocus; } + + inline Clientmenu *getMenu(void) { return clientmenu; } + + inline const std::string& getName(void) const { return name; } + + inline unsigned int getID(void) const { return id; } + + inline void setLastFocusedWindow(BlackboxWindow *w) { lastfocus = w; } + + inline const BlackboxWindowList& getStackingList() const + { return stackingList; } + + BlackboxWindow* getWindow(unsigned int index); + BlackboxWindow* getNextWindowInList(BlackboxWindow *w); + BlackboxWindow* getPrevWindowInList(BlackboxWindow *w); + BlackboxWindow* getTopWindowOnStack(void) const; + void sendWindowList(Netizen &n); + void focusFallback(const BlackboxWindow *old_window); + void setFocused(const BlackboxWindow *w, bool focused); + + bool isCurrent(void) const; + bool isLastWindow(const BlackboxWindow* w) const; + + void addWindow(BlackboxWindow *w, bool place = False, bool sticky = False); + void removeWindow(BlackboxWindow *w, bool sticky = False); + unsigned int getCount(void) const; + void appendStackOrder(BlackboxWindowList &stack_order) const; + + void showAll(void); + void hideAll(void); + void removeAll(void); + void raiseWindow(BlackboxWindow *w); + void lowerWindow(BlackboxWindow *w); + void reconfigure(void); + void setCurrent(void); + void readName(); + void setName(const std::string& new_name); +}; + + +#endif // __Workspace_hh + diff --git a/src/xatom.cc b/src/xatom.cc new file mode 100644 index 00000000..59e8b164 --- /dev/null +++ b/src/xatom.cc @@ -0,0 +1,526 @@ +// XAtom.cc for Openbox +// Copyright (c) 2002 - 2002 Ben Jansens (xor at orodu.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#include "../config.h" + +#include + +#include "xatom.hh" +#include "screen.hh" +#include "util.hh" + +XAtom::XAtom(Display *d) { + _display = d; + + // 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_string] = create("UTF8_STRING"); + +#ifdef HAVE_GETPID + _atoms[blackbox_pid] = create("_BLACKBOX_PID"); +#endif // HAVE_GETPID + + _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[motif_wm_hints] = create("_MOTIF_WM_HINTS"); + _atoms[blackbox_hints] = create("_BLACKBOX_HINTS"); + _atoms[blackbox_attributes] = create("_BLACKBOX_ATTRIBUTES"); + _atoms[blackbox_change_attributes] = create("_BLACKBOX_CHANGE_ATTRIBUTES"); + _atoms[blackbox_structure_messages] = create("_BLACKBOX_STRUCTURE_MESSAGES"); + _atoms[blackbox_notify_startup] = create("_BLACKBOX_NOTIFY_STARTUP"); + _atoms[blackbox_notify_window_add] = create("_BLACKBOX_NOTIFY_WINDOW_ADD"); + _atoms[blackbox_notify_window_del] = create("_BLACKBOX_NOTIFY_WINDOW_DEL"); + _atoms[blackbox_notify_current_workspace] = + create("_BLACKBOX_NOTIFY_CURRENT_WORKSPACE"); + _atoms[blackbox_notify_workspace_count] = + create("_BLACKBOX_NOTIFY_WORKSPACE_COUNT"); + _atoms[blackbox_notify_window_focus] = + create("_BLACKBOX_NOTIFY_WINDOW_FOCUS"); + _atoms[blackbox_notify_window_raise] = + create("_BLACKBOX_NOTIFY_WINDOW_RAISE"); + _atoms[blackbox_notify_window_lower] = + create("_BLACKBOX_NOTIFY_WINDOW_LOWER"); + + _atoms[blackbox_change_workspace] = create("_BLACKBOX_CHANGE_WORKSPACE"); + _atoms[blackbox_change_window_focus] = + create("_BLACKBOX_CHANGE_WINDOW_FOCUS"); + _atoms[blackbox_cycle_window_focus] = create("_BLACKBOX_CYCLE_WINDOW_FOCUS"); + + _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_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_shade] = create("_NET_WM_ACTION_SHADE"); + _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_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_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[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"); +} + + +/* + * clean up the class' members + */ +XAtom::~XAtom() { + while (!_support_windows.empty()) { + // make sure we aren't fucking with this somewhere + assert(_support_windows.back() != None); + XDestroyWindow(_display, _support_windows.back()); + _support_windows.pop_back(); + } +} + + +/* + * Returns an atom from the Xserver, creating it if necessary. + */ +Atom XAtom::create(const char *name) const { + return XInternAtom(_display, name, False); +} + + +/* + * Sets which atoms are supported for NETWM, by Openbox, on the root window. + */ +void XAtom::setSupported(const ScreenInfo *screen) { + Window root = screen->getRootWindow(); + + // create the netwm support window + Window w = XCreateSimpleWindow(_display, root, 0, 0, 1, 1, 0, 0, 0); + assert(w != None); + _support_windows.push_back(w); + + // set supporting window + setValue(root, net_supporting_wm_check, window, w); + + //set properties on the supporting window + setValue(w, net_wm_name, utf8, "Openbox"); + setValue(w, net_supporting_wm_check, window, w); + + // we don't support any yet.. + // yes we do! + + Atom supported[] = { + _atoms[net_current_desktop], + _atoms[net_number_of_desktops], + _atoms[net_desktop_geometry], + _atoms[net_desktop_viewport], + _atoms[net_active_window], + _atoms[net_workarea], + _atoms[net_client_list], + _atoms[net_client_list_stacking], + _atoms[net_desktop_names], + _atoms[net_close_window], + _atoms[net_wm_name], + _atoms[net_wm_visible_name], + _atoms[net_wm_icon_name], + _atoms[net_wm_visible_icon_name], + _atoms[net_wm_desktop], + _atoms[net_wm_strut], + _atoms[net_wm_window_type], + _atoms[net_wm_window_type_desktop], + _atoms[net_wm_window_type_dock], + _atoms[net_wm_window_type_toolbar], + _atoms[net_wm_window_type_menu], + _atoms[net_wm_window_type_utility], + _atoms[net_wm_window_type_splash], + _atoms[net_wm_window_type_dialog], + _atoms[net_wm_window_type_normal], + _atoms[net_wm_moveresize], + _atoms[net_wm_moveresize_size_topleft], + _atoms[net_wm_moveresize_size_topright], + _atoms[net_wm_moveresize_size_bottomleft], + _atoms[net_wm_moveresize_size_bottomright], + _atoms[net_wm_moveresize_move], + _atoms[net_wm_allowed_actions], + _atoms[net_wm_action_move], + _atoms[net_wm_action_resize], + _atoms[net_wm_action_shade], + _atoms[net_wm_action_maximize_horz], + _atoms[net_wm_action_maximize_vert], + _atoms[net_wm_action_change_desktop], + _atoms[net_wm_action_close], + _atoms[net_wm_state], + _atoms[net_wm_state_modal], + _atoms[net_wm_state_maximized_vert], + _atoms[net_wm_state_maximized_horz], + _atoms[net_wm_state_shaded], + _atoms[net_wm_state_skip_taskbar], + _atoms[net_wm_state_skip_pager], + _atoms[net_wm_state_hidden], + _atoms[net_wm_state_fullscreen], + }; + const int num_supported = sizeof(supported)/sizeof(Atom); + + setValue(root, net_supported, atom, supported, num_supported); +} + + +/* + * Internal setValue. + * Sets a window property on a window, optionally appending to the existing + * value. + */ +void XAtom::setValue(Window win, Atom atom, Atom type, + unsigned char* data, int size, int nelements, + bool append) const { + 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); +} + + +/* + * Set a 32-bit property value on a window. + */ +void XAtom::setValue(Window win, Atoms atom, Atoms type, + unsigned long value) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_ATOMS); + setValue(win, _atoms[atom], _atoms[type], + reinterpret_cast(&value), 32, 1, False); +} + + +/* + * Set an array of 32-bit properties value on a window. + */ +void XAtom::setValue(Window win, Atoms atom, Atoms type, + unsigned long value[], int elements) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_ATOMS); + setValue(win, _atoms[atom], _atoms[type], + reinterpret_cast(value), 32, elements, False); +} + + +/* + * Set an string property value on a window. + */ +void XAtom::setValue(Window win, Atoms atom, StringType type, + const std::string &value) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_STRING_TYPE); + + Atom t; + switch (type) { + case ansi: t = _atoms[string]; break; + case utf8: t = _atoms[utf8_string]; break; + default: assert(False); return; // unhandled StringType + } + setValue(win, _atoms[atom], t, + reinterpret_cast(const_cast(value.c_str())), + 8, value.size() + 1, False); // add 1 to the size to include the null +} + + +/* + * Set an array of string property values on a window. + */ +void XAtom::setValue(Window win, Atoms atom, StringType type, + const StringVect &strings) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_STRING_TYPE); + + Atom t; + switch (type) { + case ansi: t = _atoms[string]; break; + case utf8: t = _atoms[utf8_string]; break; + default: assert(False); return; // unhandled StringType + } + + std::string value; + + StringVect::const_iterator it = strings.begin(); + const StringVect::const_iterator end = strings.end(); + for (; it != end; ++it) + value += *it + '\0'; + + setValue(win, _atoms[atom], t, + reinterpret_cast(const_cast(value.c_str())), + 8, value.size(), False); +} + + +/* + * Internal getValue function used by all of the typed getValue functions. + * Gets an property's value from a window. + * Returns True if the property was successfully retrieved; False if the + * property did not exist on the window, or has a different type/size format + * than the user tried to retrieve. + */ +bool XAtom::getValue(Window win, Atom atom, Atom type, + unsigned long &nelements, unsigned char **value, + int size) const { + assert(win != None); assert(atom != None); assert(type != None); + assert(size == 8 || size == 16 || size == 32); + assert(nelements > 0); + 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; + unsigned long maxread = nelements; + 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 || maxread <= nelements) { + // 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. + int remain = (ret_bytes - 1)/sizeof(long) + 1 + 1; + if (remain > size/8 * (signed)maxread) // dont get more than the max + remain = size/8 * (signed)maxread; + 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 && + ret_bytes == 0); + /* + 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 getValue(win, atom, type, maxread, 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; +} + + +/* + * Gets a 32-bit property's value from a window. + */ +bool XAtom::getValue(Window win, Atoms atom, Atoms type, + unsigned long &nelements, + unsigned long **value) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_ATOMS); + return getValue(win, _atoms[atom], _atoms[type], nelements, + reinterpret_cast(value), 32); +} + + +/* + * Gets a single 32-bit property's value from a window. + */ +bool XAtom::getValue(Window win, Atoms atom, Atoms type, + unsigned long &value) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_ATOMS); + unsigned long *temp; + unsigned long num = 1; + if (! getValue(win, _atoms[atom], _atoms[type], num, + reinterpret_cast(&temp), 32)) + return False; + value = temp[0]; + delete [] temp; + return True; +} + + +/* + * Gets an string property's value from a window. + */ +bool XAtom::getValue(Window win, Atoms atom, StringType type, + std::string &value) const { + unsigned long n = 1; + StringVect s; + if (getValue(win, atom, type, n, s)) { + value = s[0]; + return True; + } + return False; +} + + +bool XAtom::getValue(Window win, Atoms atom, StringType type, + unsigned long &nelements, StringVect &strings) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(type >= 0 && type < NUM_STRING_TYPE); + assert(win != None); assert(_atoms[atom] != None); + assert(nelements > 0); + + Atom t; + switch (type) { + case ansi: t = _atoms[string]; break; + case utf8: t = _atoms[utf8_string]; break; + default: assert(False); return False; // unhandled StringType + } + + unsigned char *value; + unsigned long elements = (unsigned) -1; + if (!getValue(win, _atoms[atom], t, elements, &value, 8) || elements < 1) + return False; + + std::string s(reinterpret_cast(value), elements); + delete [] value; + + std::string::const_iterator it = s.begin(), end = s.end(); + unsigned long num = 0; + while(num < nelements) { + 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) + ++num; + if (it == end) break; + ++it; + if (it == end) break; + } + + nelements = num; + + return True; +} + + +/* + * Removes a property entirely from a window. + */ +void XAtom::eraseValue(Window win, Atoms atom) const { + assert(atom >= 0 && atom < NUM_ATOMS); + XDeleteProperty(_display, win, _atoms[atom]); +} + + +void XAtom::sendClientMessage(Window target, Atoms type, Window about, + long data, long data1, long data2, + long data3, long data4) const { + assert(atom >= 0 && atom < NUM_ATOMS); + assert(target != None); + + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.format = 32; + e.xclient.message_type = _atoms[type]; + e.xclient.window = about; + e.xclient.data.l[0] = data; + e.xclient.data.l[1] = data1; + e.xclient.data.l[2] = data2; + e.xclient.data.l[3] = data3; + e.xclient.data.l[4] = data4; + + XSendEvent(_display, target, False, + SubstructureRedirectMask | SubstructureNotifyMask, + &e); +} diff --git a/src/xatom.hh b/src/xatom.hh new file mode 100644 index 00000000..d92b01f0 --- /dev/null +++ b/src/xatom.hh @@ -0,0 +1,230 @@ +// XAtom.h for Openbox +// Copyright (c) 2002 - 2002 Ben Janens (ben at orodu.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef __XAtom_h +#define __XAtom_h + +#include +#include + +#include + +#include +#include + +class Blackbox; +class ScreenInfo; + +class XAtom { +public: + enum Atoms { + // types + cardinal, + window, + pixmap, + atom, + string, + utf8_string, + +#ifdef HAVE_GETPID + blackbox_pid, +#endif // HAVE_GETPID + + // window hints + wm_colormap_windows, + wm_protocols, + wm_state, + wm_delete_window, + wm_take_focus, + wm_change_state, + wm_name, + wm_icon_name, + wm_class, + motif_wm_hints, + blackbox_attributes, + blackbox_change_attributes, + blackbox_hints, + + // blackbox-protocol atoms (wm -> client) + blackbox_structure_messages, + blackbox_notify_startup, + blackbox_notify_window_add, + blackbox_notify_window_del, + blackbox_notify_window_focus, + blackbox_notify_current_workspace, + blackbox_notify_workspace_count, + blackbox_notify_window_raise, + blackbox_notify_window_lower, + // blackbox-protocol atoms (client -> wm) + blackbox_change_workspace, + blackbox_change_window_focus, + blackbox_cycle_window_focus, + + openbox_show_root_menu, + openbox_show_workspace_menu, + + // NETWM atoms + // root window properties + net_supported, + net_client_list, + net_client_list_stacking, + net_number_of_desktops, + net_desktop_geometry, + net_desktop_viewport, + net_current_desktop, + net_desktop_names, + net_active_window, + net_workarea, + net_supporting_wm_check, +// net_virtual_roots, + // root window messages + net_close_window, + net_wm_moveresize, + // application window properties +// net_properties, + net_wm_name, + net_wm_visible_name, + net_wm_icon_name, + net_wm_visible_icon_name, + net_wm_desktop, + net_wm_window_type, + net_wm_state, + net_wm_strut, +// net_wm_icon_geometry, +// net_wm_icon, +// net_wm_pid, +// net_wm_handled_icons, + net_wm_allowed_actions, + // application protocols +// net_wm_ping, + + net_wm_window_type_desktop, + net_wm_window_type_dock, + net_wm_window_type_toolbar, + net_wm_window_type_menu, + net_wm_window_type_utility, + net_wm_window_type_splash, + net_wm_window_type_dialog, + net_wm_window_type_normal, + + net_wm_moveresize_size_topleft, + net_wm_moveresize_size_topright, + net_wm_moveresize_size_bottomleft, + net_wm_moveresize_size_bottomright, + net_wm_moveresize_move, + + net_wm_action_move, + net_wm_action_resize, + net_wm_action_shade, + net_wm_action_maximize_horz, + net_wm_action_maximize_vert, + net_wm_action_change_desktop, + net_wm_action_close, + + net_wm_state_modal, + net_wm_state_maximized_vert, + net_wm_state_maximized_horz, + net_wm_state_shaded, + net_wm_state_skip_taskbar, + net_wm_state_skip_pager, + net_wm_state_hidden, + net_wm_state_fullscreen, + + kde_net_system_tray_windows, + kde_net_wm_system_tray_window_for, + kde_net_wm_window_type_override, + + // constant for how many atoms exist in the enumerator + NUM_ATOMS + }; + + enum StringType { + ansi, + utf8, + NUM_STRING_TYPE + }; + +private: + typedef std::vector SupportWindows; + + Display *_display; + // windows used to specify support for NETWM + SupportWindows _support_windows; + Atom _atoms[NUM_ATOMS]; + + Atom create(const char *name) const; + + void setValue(Window win, Atom atom, Atom type, unsigned char *data, + int size, int nelements, bool append) const; + bool getValue(Window win, Atom atom, Atom type, + unsigned long &nelements, unsigned char **value, + int size) const; + + // no copying!! + XAtom(const XAtom &); + XAtom& operator=(const XAtom&); + +public: + typedef std::vector StringVect; + + XAtom(Display *d); + virtual ~XAtom(); + + // setup support on a screen, each screen should call this once in its + // constructor. + void setSupported(const ScreenInfo *screen); + + void setValue(Window win, Atoms atom, Atoms type, unsigned long value) const; + void setValue(Window win, Atoms atom, Atoms type, + unsigned long value[], int elements) const; + void setValue(Window win, Atoms atom, StringType type, + const std::string &value) const; + void setValue(Window win, Atoms atom, StringType type, + const StringVect &strings) const; + + // the 'value' is allocated inside the function and + // delete [] value needs to be called when you are done with it. + // the 'value' array returned is null terminated, and has 'nelements' + // elements in it plus the null. + // nelements must be set to the maximum number of elements to read from + // the property. + bool getValue(Window win, Atoms atom, Atoms type, + unsigned long &nelements, unsigned long **value) const; + bool getValue(Window win, Atoms atom, Atoms type, unsigned long &value) const; + bool getValue(Window win, Atoms atom, StringType type, + std::string &value) const; + bool getValue(Window win, Atoms atom, StringType type, + unsigned long &nelements, StringVect &strings) const; + + void eraseValue(Window win, Atoms atom) const; + + // sends a client message a window + void sendClientMessage(Window target, Atoms type, Window about, + long data = 0, long data1 = 0, long data2 = 0, + long data3 = 0, long data4 = 0) const; + + // temporary function!! remove when not used in blackbox.hh anymore!! + inline Atom getAtom(Atoms a) + { assert(a >= 0 && a < NUM_ATOMS); Atom ret = _atoms[a]; + assert(ret != 0); return ret; } +}; + +#endif // __XAtom_h -- cgit v1.2.3