From dfc5f034581f5a26cba5c4811500438f89f0634a Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 11 Apr 2002 03:20:38 +0000 Subject: Initial revision --- src/BaseDisplay.cc | 617 ++++++++++ src/BaseDisplay.h | 357 ++++++ src/Basemenu.cc | 1036 ++++++++++++++++ src/Basemenu.h | 170 +++ src/Clientmenu.cc | 64 + src/Clientmenu.h | 44 + src/Configmenu.cc | 323 +++++ src/Configmenu.h | 78 ++ src/Iconmenu.cc | 64 + src/Iconmenu.h | 44 + src/Image.cc | 2444 +++++++++++++++++++++++++++++++++++++ src/Image.h | 241 ++++ src/LinkedList.cc | 356 ++++++ src/LinkedList.h | 130 ++ src/Makefile.am | 108 ++ src/Makefile.in | 462 +++++++ src/Netizen.cc | 116 ++ src/Netizen.h | 60 + src/Rootmenu.cc | 113 ++ src/Rootmenu.h | 51 + src/Screen.cc | 2281 +++++++++++++++++++++++++++++++++++ src/Screen.h | 349 ++++++ src/Slit.cc | 773 ++++++++++++ src/Slit.h | 159 +++ src/Timer.cc | 76 ++ src/Timer.h | 78 ++ src/Toolbar.cc | 1260 ++++++++++++++++++++ src/Toolbar.h | 156 +++ src/Window.cc | 3244 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/Window.h | 330 +++++ src/Windowmenu.cc | 204 ++++ src/Windowmenu.h | 78 ++ src/Workspace.cc | 502 ++++++++ src/Workspace.h | 90 ++ src/Workspacemenu.cc | 69 ++ src/Workspacemenu.h | 45 + src/bsd-snprintf.c | 788 ++++++++++++ src/bsd-snprintf.h | 17 + src/i18n.cc | 134 +++ src/i18n.h | 66 + src/main.cc | 186 +++ src/openbox.cc | 1797 ++++++++++++++++++++++++++++ src/openbox.h | 212 ++++ 43 files changed, 19772 insertions(+) create mode 100644 src/BaseDisplay.cc create mode 100644 src/BaseDisplay.h create mode 100644 src/Basemenu.cc create mode 100644 src/Basemenu.h create mode 100644 src/Clientmenu.cc create mode 100644 src/Clientmenu.h create mode 100644 src/Configmenu.cc create mode 100644 src/Configmenu.h create mode 100644 src/Iconmenu.cc create mode 100644 src/Iconmenu.h create mode 100644 src/Image.cc create mode 100644 src/Image.h create mode 100644 src/LinkedList.cc create mode 100644 src/LinkedList.h create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/Netizen.cc create mode 100644 src/Netizen.h create mode 100644 src/Rootmenu.cc create mode 100644 src/Rootmenu.h create mode 100644 src/Screen.cc create mode 100644 src/Screen.h create mode 100644 src/Slit.cc create mode 100644 src/Slit.h create mode 100644 src/Timer.cc create mode 100644 src/Timer.h create mode 100644 src/Toolbar.cc create mode 100644 src/Toolbar.h create mode 100644 src/Window.cc create mode 100644 src/Window.h create mode 100644 src/Windowmenu.cc create mode 100644 src/Windowmenu.h create mode 100644 src/Workspace.cc create mode 100644 src/Workspace.h create mode 100644 src/Workspacemenu.cc create mode 100644 src/Workspacemenu.h create mode 100644 src/bsd-snprintf.c create mode 100644 src/bsd-snprintf.h create mode 100644 src/i18n.cc create mode 100644 src/i18n.h create mode 100644 src/main.cc create mode 100644 src/openbox.cc create mode 100644 src/openbox.h (limited to 'src') diff --git a/src/BaseDisplay.cc b/src/BaseDisplay.cc new file mode 100644 index 00000000..258e3eab --- /dev/null +++ b/src/BaseDisplay.cc @@ -0,0 +1,617 @@ +// BaseDisplay.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include +#include + +#ifdef SHAPE +# include +#endif // SHAPE + +#ifdef HAVE_FCNTL_H +# include +#endif // HAVE_FCNTL_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#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 + +#if defined(HAVE_PROCESS_H) && defined(__EMX__) +# include +#endif // HAVE_PROCESS_H __EMX__ + +#include "i18n.h" +#include "BaseDisplay.h" +#include "LinkedList.h" +#include "Timer.h" + +// X error handler to handle any and all X errors while the application is +// running +static Bool internal_error = False; +static Window last_bad_window = None; + +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->getMessage(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); +#endif // DEBUG + + if (e->error_code == BadWindow) last_bad_window = e->resourceid; + 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->getMessage(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->getMessage(BaseDisplaySet, BaseDisplayShuttingDown, + "shutting down\n")); + base_display->shutdown(); + } + + if (sig != SIGTERM && sig != SIGINT) { + fprintf(stderr, i18n->getMessage(BaseDisplaySet, BaseDisplayAborting, + "aborting... dumping core\n")); + abort(); + } + + exit(0); + + break; + } +} + + +// convenience functions +#ifndef __EMX__ +void bexec(const char *command, char* displaystring) { + if (! fork()) { + setsid(); + putenv(displaystring); + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + exit(0); + } +} +#endif // !__EMX__ + +char *bstrdup(const char *s) { + const int l = strlen(s) + 1; + char *n = new char[l]; + strncpy(n, s, l); + return n; +} + +BaseDisplay::BaseDisplay(char *app_name, char *dpy_name) { + application_name = app_name; + + _startup = True; + _shutdown = False; + server_grabs = 0; + last_bad_window = None; + + ::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->getMessage(BaseDisplaySet, BaseDisplayXConnectFail, + "BaseDisplay::BaseDisplay: connection to X server failed.\n")); + ::exit(2); + } else if (fcntl(ConnectionNumber(display), F_SETFD, 1) == -1) { + fprintf(stderr, + i18n->getMessage(BaseDisplaySet, BaseDisplayCloseOnExecFail, + "BaseDisplay::BaseDisplay: couldn't mark display connection " + "as close-on-exec\n")); + ::exit(2); + } + + number_of_screens = ScreenCount(display); + display_name = XDisplayName(dpy_name); + +#ifdef SHAPE + shape.extensions = XShapeQueryExtension(display, &shape.event_basep, + &shape.error_basep); +#else // !SHAPE + shape.extensions = False; +#endif // SHAPE + + xa_wm_colormap_windows = + XInternAtom(display, "WM_COLORMAP_WINDOWS", False); + xa_wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False); + xa_wm_state = XInternAtom(display, "WM_STATE", False); + xa_wm_change_state = XInternAtom(display, "WM_CHANGE_STATE", False); + xa_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); + xa_wm_take_focus = XInternAtom(display, "WM_TAKE_FOCUS", False); + motif_wm_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False); + + openbox_hints = XInternAtom(display, "_BLACKBOX_HINTS", False); + openbox_attributes = XInternAtom(display, "_BLACKBOX_ATTRIBUTES", False); + openbox_change_attributes = + XInternAtom(display, "_BLACKBOX_CHANGE_ATTRIBUTES", False); + + openbox_structure_messages = + XInternAtom(display, "_BLACKBOX_STRUCTURE_MESSAGES", False); + openbox_notify_startup = + XInternAtom(display, "_BLACKBOX_NOTIFY_STARTUP", False); + openbox_notify_window_add = + XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_ADD", False); + openbox_notify_window_del = + XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_DEL", False); + openbox_notify_current_workspace = + XInternAtom(display, "_BLACKBOX_NOTIFY_CURRENT_WORKSPACE", False); + openbox_notify_workspace_count = + XInternAtom(display, "_BLACKBOX_NOTIFY_WORKSPACE_COUNT", False); + openbox_notify_window_focus = + XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_FOCUS", False); + openbox_notify_window_raise = + XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_RAISE", False); + openbox_notify_window_lower = + XInternAtom(display, "_BLACKBOX_NOTIFY_WINDOW_LOWER", False); + + openbox_change_workspace = + XInternAtom(display, "_BLACKBOX_CHANGE_WORKSPACE", False); + openbox_change_window_focus = + XInternAtom(display, "_BLACKBOX_CHANGE_WINDOW_FOCUS", False); + openbox_cycle_window_focus = + XInternAtom(display, "_BLACKBOX_CYCLE_WINDOW_FOCUS", False); + +#ifdef NEWWMSPEC + + net_supported = XInternAtom(display, "_NET_SUPPORTED", False); + net_client_list = XInternAtom(display, "_NET_CLIENT_LIST", False); + net_client_list_stacking = XInternAtom(display, "_NET_CLIENT_LIST_STACKING", False); + net_number_of_desktops = XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False); + net_desktop_geometry = XInternAtom(display, "_NET_DESKTOP_GEOMETRY", False); + net_desktop_viewport = XInternAtom(display, "_NET_DESKTOP_VIEWPORT", False); + net_current_desktop = XInternAtom(display, "_NET_CURRENT_DESKTOP", False); + net_desktop_names = XInternAtom(display, "_NET_DESKTOP_NAMES", False); + net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False); + net_workarea = XInternAtom(display, "_NET_WORKAREA", False); + net_supporting_wm_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False); + net_virtual_roots = XInternAtom(display, "_NET_VIRTUAL_ROOTS", False); + + net_close_window = XInternAtom(display, "_NET_CLOSE_WINDOW", False); + net_wm_moveresize = XInternAtom(display, "_NET_WM_MOVERESIZE", False); + + net_properties = XInternAtom(display, "_NET_PROPERTIES", False); + net_wm_name = XInternAtom(display, "_NET_WM_NAME", False); + net_wm_desktop = XInternAtom(display, "_NET_WM_DESKTOP", False); + net_wm_window_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); + net_wm_state = XInternAtom(display, "_NET_WM_STATE", False); + net_wm_strut = XInternAtom(display, "_NET_WM_STRUT", False); + net_wm_icon_geometry = XInternAtom(display, "_NET_WM_ICON_GEOMETRY", False); + net_wm_icon = XInternAtom(display, "_NET_WM_ICON", False); + net_wm_pid = XInternAtom(display, "_NET_WM_PID", False); + net_wm_handled_icons = XInternAtom(display, "_NET_WM_HANDLED_ICONS", False); + + net_wm_ping = XInternAtom(display, "_NET_WM_PING", False); + +#endif // NEWWMSPEC + + cursor.session = XCreateFontCursor(display, XC_left_ptr); + cursor.move = XCreateFontCursor(display, XC_fleur); + cursor.ll_angle = XCreateFontCursor(display, XC_ll_angle); + cursor.lr_angle = XCreateFontCursor(display, XC_lr_angle); + cursor.ul_angle = XCreateFontCursor(display, XC_ul_angle); + cursor.ur_angle = XCreateFontCursor(display, XC_ur_angle); + + XSetErrorHandler((XErrorHandler) handleXErrors); + + timerList = new LinkedList; + + screenInfoList = new LinkedList; + for (int i = 0; i < number_of_screens; i++) { + ScreenInfo *screeninfo = new ScreenInfo(this, i); + screenInfoList->insert(screeninfo); + } + +#ifndef NOCLOBBER + 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_code = XKeysymToKeycode(display, XK_Num_Lock); + const KeyCode scroll_lock_code = XKeysymToKeycode(display, XK_Scroll_Lock); + + for (size_t cnt = 0; cnt < size; ++cnt) { + if (! modmap->modifiermap[cnt]) continue; + + if (num_lock_code == modmap->modifiermap[cnt]) + NumLockMask = mask_table[cnt / modmap->max_keypermod]; + if (scroll_lock_code == modmap->modifiermap[cnt]) + ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; + } + } + + MaskList[0] = 0; + MaskList[1] = LockMask; + MaskList[2] = NumLockMask; + MaskList[3] = ScrollLockMask; + MaskList[4] = LockMask | NumLockMask; + MaskList[5] = NumLockMask | ScrollLockMask; + MaskList[6] = LockMask | ScrollLockMask; + MaskList[7] = LockMask | NumLockMask | ScrollLockMask; + MaskListLength = sizeof(MaskList) / sizeof(MaskList[0]); + + if (modmap) XFreeModifiermap(const_cast(modmap)); +#endif // NOCLOBBER +} + + +BaseDisplay::~BaseDisplay(void) { + while (screenInfoList->count()) { + ScreenInfo *si = screenInfoList->first(); + + screenInfoList->remove(si); + delete si; + } + + delete screenInfoList; + + // we don't create the BTimers, we don't delete them + while (timerList->count()) + timerList->remove(0); + + delete timerList; + + XCloseDisplay(display); +} + + +void BaseDisplay::eventLoop(void) { + run(); + + int xfd = ConnectionNumber(display); + + while ((! _shutdown) && (! internal_error)) { + if (XPending(display)) { + XEvent e; + XNextEvent(display, &e); + + if (last_bad_window != None && e.xany.window == last_bad_window) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(BaseDisplaySet, + BaseDisplayBadWindowRemove, + "BaseDisplay::eventLoop(): removing bad window " + "from event queue\n")); +#endif // DEBUG + } else { + last_bad_window = None; + process_event(&e); + } + } else { + fd_set rfds; + timeval now, tm, *timeout = (timeval *) 0; + + FD_ZERO(&rfds); + FD_SET(xfd, &rfds); + + if (timerList->count()) { + gettimeofday(&now, 0); + + tm.tv_sec = tm.tv_usec = 0l; + + BTimer *timer = timerList->first(); + + tm.tv_sec = timer->getStartTime().tv_sec + + timer->getTimeout().tv_sec - now.tv_sec; + tm.tv_usec = timer->getStartTime().tv_usec + + timer->getTimeout().tv_usec - now.tv_usec; + + while (tm.tv_usec >= 1000000) { + tm.tv_sec++; + tm.tv_usec -= 1000000; + } + + while (tm.tv_usec < 0) { + if (tm.tv_sec > 0) { + tm.tv_sec--; + tm.tv_usec += 1000000; + } else { + tm.tv_usec = 0; + break; + } + } + + timeout = &tm; + } + + select(xfd + 1, &rfds, 0, 0, timeout); + + // check for timer timeout + gettimeofday(&now, 0); + + LinkedListIterator it(timerList); + for(BTimer *timer = it.current(); timer; it++, timer = it.current()) { + tm.tv_sec = timer->getStartTime().tv_sec + + timer->getTimeout().tv_sec; + tm.tv_usec = timer->getStartTime().tv_usec + + timer->getTimeout().tv_usec; + + if ((now.tv_sec < tm.tv_sec) || + (now.tv_sec == tm.tv_sec && now.tv_usec < tm.tv_usec)) + break; + + timer->fireTimeout(); + + // restart the current timer so that the start time is updated + if (! timer->doOnce()) timer->start(); + else timer->stop(); + } + } + } +} + + +const Bool BaseDisplay::validateWindow(Window window) { + XEvent event; + if (XCheckTypedWindowEvent(display, window, DestroyNotify, &event)) { + XPutBackEvent(display, &event); + + return False; + } + + return True; +} + + +void BaseDisplay::grab(void) { + if (! server_grabs++) + XGrabServer(display); +} + + +void BaseDisplay::ungrab(void) { + if (! --server_grabs) + XUngrabServer(display); + + if (server_grabs < 0) server_grabs = 0; +} + + +void BaseDisplay::addTimer(BTimer *timer) { + if (! timer) return; + + LinkedListIterator it(timerList); + int index = 0; + for (BTimer *tmp = it.current(); tmp; it++, index++, tmp = it.current()) + if ((tmp->getTimeout().tv_sec > timer->getTimeout().tv_sec) || + ((tmp->getTimeout().tv_sec == timer->getTimeout().tv_sec) && + (tmp->getTimeout().tv_usec >= timer->getTimeout().tv_usec))) + break; + + timerList->insert(timer, index); +} + + +void BaseDisplay::removeTimer(BTimer *timer) { + timerList->remove(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. + */ +void BaseDisplay::grabButton(unsigned int button, unsigned int modifiers, + Window grab_window, Bool owner_events, + unsigned int event_mask, int pointer_mode, + int keybaord_mode, Window confine_to, + Cursor cursor) const +{ +#ifndef NOCLOBBER + for (size_t cnt = 0; cnt < MaskListLength; ++cnt) + XGrabButton(display, button, modifiers | MaskList[cnt], grab_window, + owner_events, event_mask, pointer_mode, keybaord_mode, + confine_to, cursor); +#else // NOCLOBBER + XGrabButton(display, button, modifiers, grab_window, + owner_events, event_mask, pointer_mode, keybaord_mode, + confine_to, cursor); +#endif // NOCLOBBER +} + +/* + * 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 { +#ifndef NOCLOBBER + for (size_t cnt = 0; cnt < MaskListLength; ++cnt) + XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window); +#else // NOCLOBBER + XUngrabButton(display, button, modifiers, grab_window); +#endif // NOCLOBBER +} + + +ScreenInfo::ScreenInfo(BaseDisplay *d, int num) { + basedisplay = d; + screen_number = num; + + root_window = RootWindow(basedisplay->getXDisplay(), screen_number); + depth = DefaultDepth(basedisplay->getXDisplay(), screen_number); + + width = + WidthOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), screen_number)); + height = + HeightOfScreen(ScreenOfDisplay(basedisplay->getXDisplay(), screen_number)); + + // 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; + + vinfo_template.screen = screen_number; + vinfo_template.c_class = TrueColor; + + visual = (Visual *) 0; + + if ((vinfo_return = XGetVisualInfo(basedisplay->getXDisplay(), + VisualScreenMask | VisualClassMask, + &vinfo_template, &vinfo_nitems)) && + vinfo_nitems > 0) { + for (int i = 0; i < vinfo_nitems; i++) { + if (depth < (vinfo_return + i)->depth) { + depth = (vinfo_return + i)->depth; + visual = (vinfo_return + i)->visual; + } + } + + XFree(vinfo_return); + } + + if (visual) { + colormap = XCreateColormap(basedisplay->getXDisplay(), root_window, + visual, AllocNone); + } else { + visual = DefaultVisual(basedisplay->getXDisplay(), screen_number); + colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number); + } +} diff --git a/src/BaseDisplay.h b/src/BaseDisplay.h new file mode 100644 index 00000000..2aa82d76 --- /dev/null +++ b/src/BaseDisplay.h @@ -0,0 +1,357 @@ +// BaseDisplay.h for Openbox +// 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 __BaseDisplay_hh +#define __BaseDisplay_hh + +#include +#include + +// forward declaration +class BaseDisplay; +class ScreenInfo; + +#include "LinkedList.h" +#include "Timer.h" + +#define AttribShaded (1l << 0) +#define AttribMaxHoriz (1l << 1) +#define AttribMaxVert (1l << 2) +#define AttribOmnipresent (1l << 3) +#define AttribWorkspace (1l << 4) +#define AttribStack (1l << 5) +#define AttribDecoration (1l << 6) + +#define StackTop (0) +#define StackNormal (1) +#define StackBottom (2) + +#define DecorNone (0) +#define DecorNormal (1) +#define DecorTiny (2) +#define DecorTool (3) + +typedef struct _openbox_hints { + unsigned long flags, attrib, workspace, stack, decoration; +} OpenboxHints; + +typedef struct _openbox_attributes { + unsigned long flags, attrib, workspace, stack, decoration; + int premax_x, premax_y; + unsigned int premax_w, premax_h; +} OpenboxAttributes; + +#define PropOpenboxHintsElements (5) +#define PropOpenboxAttributesElements (9) + +#ifndef __EMX__ +void bexec(const char *, char *); +#endif // !__EMX__ + +char *bstrdup(const char *); + +class BaseDisplay { +private: + struct cursor { + Cursor session, move, ll_angle, lr_angle, ul_angle, ur_angle; + } cursor; + + struct shape { + Bool extensions; + int event_basep, error_basep; + } shape; + +#ifndef NOCLOBBER + unsigned int MaskList[8]; + size_t MaskListLength; +#endif // NOCLOBBER + + Atom xa_wm_colormap_windows, xa_wm_protocols, xa_wm_state, + xa_wm_delete_window, xa_wm_take_focus, xa_wm_change_state, + motif_wm_hints; + + // NETAttributes + Atom openbox_attributes, openbox_change_attributes, openbox_hints; + + // NETStructureMessages + Atom openbox_structure_messages, openbox_notify_startup, + openbox_notify_window_add, openbox_notify_window_del, + openbox_notify_window_focus, openbox_notify_current_workspace, + openbox_notify_workspace_count, openbox_notify_window_raise, + openbox_notify_window_lower; + + // message_types for client -> wm messages + Atom openbox_change_workspace, openbox_change_window_focus, + openbox_cycle_window_focus; + +#ifdef NEWWMSPEC + + // root window properties + Atom 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 + Atom net_close_window, net_wm_moveresize; + + // application window properties + Atom net_properties, net_wm_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; + + // application protocols + Atom net_wm_ping; + +#endif // NEWWMSPEC + + Bool _startup, _shutdown; + Display *display; + LinkedList *screenInfoList; + LinkedList *timerList; + + char *display_name, *application_name; + int number_of_screens, server_grabs, colors_per_channel; + + +protected: + // pure virtual function... you must override this + virtual void process_event(XEvent *) = 0; + + // the masks of the modifiers which are ignored in button events. + int NumLockMask, ScrollLockMask; + + +public: + BaseDisplay(char *, char * = 0); + virtual ~BaseDisplay(void); + + inline const Atom &getWMChangeStateAtom(void) const + { return xa_wm_change_state; } + inline const Atom &getWMStateAtom(void) const + { return xa_wm_state; } + inline const Atom &getWMDeleteAtom(void) const + { return xa_wm_delete_window; } + inline const Atom &getWMProtocolsAtom(void) const + { return xa_wm_protocols; } + inline const Atom &getWMTakeFocusAtom(void) const + { return xa_wm_take_focus; } + inline const Atom &getWMColormapAtom(void) const + { return xa_wm_colormap_windows; } + inline const Atom &getMotifWMHintsAtom(void) const + { return motif_wm_hints; } + + // this atom is for normal app->WM hints about decorations, stacking, + // starting workspace etc... + inline const Atom &getOpenboxHintsAtom(void) const + { return openbox_hints;} + + // these atoms are for normal app->WM interaction beyond the scope of the + // ICCCM... + inline const Atom &getOpenboxAttributesAtom(void) const + { return openbox_attributes; } + inline const Atom &getOpenboxChangeAttributesAtom(void) const + { return openbox_change_attributes; } + + // these atoms are for window->WM interaction, with more control and + // information on window "structure"... common examples are + // notifying apps when windows are raised/lowered... when the user changes + // workspaces... i.e. "pager talk" + inline const Atom &getOpenboxStructureMessagesAtom(void) const + { return openbox_structure_messages; } + + // *Notify* portions of the NETStructureMessages protocol + inline const Atom &getOpenboxNotifyStartupAtom(void) const + { return openbox_notify_startup; } + inline const Atom &getOpenboxNotifyWindowAddAtom(void) const + { return openbox_notify_window_add; } + inline const Atom &getOpenboxNotifyWindowDelAtom(void) const + { return openbox_notify_window_del; } + inline const Atom &getOpenboxNotifyWindowFocusAtom(void) const + { return openbox_notify_window_focus; } + inline const Atom &getOpenboxNotifyCurrentWorkspaceAtom(void) const + { return openbox_notify_current_workspace; } + inline const Atom &getOpenboxNotifyWorkspaceCountAtom(void) const + { return openbox_notify_workspace_count; } + inline const Atom &getOpenboxNotifyWindowRaiseAtom(void) const + { return openbox_notify_window_raise; } + inline const Atom &getOpenboxNotifyWindowLowerAtom(void) const + { return openbox_notify_window_lower; } + + // atoms to change that request changes to the desktop environment during + // runtime... these messages can be sent by any client... as the sending + // client window id is not included in the ClientMessage event... + inline const Atom &getOpenboxChangeWorkspaceAtom(void) const + { return openbox_change_workspace; } + inline const Atom &getOpenboxChangeWindowFocusAtom(void) const + { return openbox_change_window_focus; } + inline const Atom &getOpenboxCycleWindowFocusAtom(void) const + { return openbox_cycle_window_focus; } + +#ifdef NEWWMSPEC + + // root window properties + inline const Atom &getNETSupportedAtom(void) const + { return net_supported; } + inline const Atom &getNETClientListAtom(void) const + { return net_client_list; } + inline const Atom &getNETClientListStackingAtom(void) const + { return net_client_list_stacking; } + inline const Atom &getNETNumberOfDesktopsAtom(void) const + { return net_number_of_desktops; } + inline const Atom &getNETDesktopGeometryAtom(void) const + { return net_desktop_geometry; } + inline const Atom &getNETDesktopViewportAtom(void) const + { return net_desktop_viewport; } + inline const Atom &getNETCurrentDesktopAtom(void) const + { return net_current_desktop; } + inline const Atom &getNETDesktopNamesAtom(void) const + { return net_desktop_names; } + inline const Atom &getNETActiveWindowAtom(void) const + { return net_active_window; } + inline const Atom &getNETWorkareaAtom(void) const + { return net_workarea; } + inline const Atom &getNETSupportingWMCheckAtom(void) const + { return net_supporting_wm_check; } + inline const Atom &getNETVirtualRootsAtom(void) const + { return net_virtual_roots; } + + // root window messages + inline const Atom &getNETCloseWindowAtom(void) const + { return net_close_window; } + inline const Atom &getNETWMMoveResizeAtom(void) const + { return net_wm_moveresize; } + + // application window properties + inline const Atom &getNETPropertiesAtom(void) const + { return net_properties; } + inline const Atom &getNETWMNameAtom(void) const + { return net_wm_name; } + inline const Atom &getNETWMDesktopAtom(void) const + { return net_wm_desktop; } + inline const Atom &getNETWMWindowTypeAtom(void) const + { return net_wm_window_type; } + inline const Atom &getNETWMStateAtom(void) const + { return net_wm_state; } + inline const Atom &getNETWMStrutAtom(void) const + { return net_wm_strut; } + inline const Atom &getNETWMIconGeometryAtom(void) const + { return net_wm_icon_geometry; } + inline const Atom &getNETWMIconAtom(void) const + { return net_wm_icon; } + inline const Atom &getNETWMPidAtom(void) const + { return net_wm_pid; } + inline const Atom &getNETWMHandledIconsAtom(void) const + { return net_wm_handled_icons; } + + // application protocols + inline const Atom &getNETWMPingAtom(void) const + { return net_wm_ping; } + +#endif // NEWWMSPEC + + inline ScreenInfo *getScreenInfo(int s) + { return (ScreenInfo *) screenInfoList->find(s); } + + inline const Bool &hasShapeExtensions(void) const + { return shape.extensions; } + inline const Bool &doShutdown(void) const + { return _shutdown; } + inline const Bool &isStartup(void) const + { return _startup; } + + inline const Cursor &getSessionCursor(void) const + { return cursor.session; } + inline const Cursor &getMoveCursor(void) const + { return cursor.move; } + inline const Cursor &getLowerLeftAngleCursor(void) const + { return cursor.ll_angle; } + inline const Cursor &getLowerRightAngleCursor(void) const + { return cursor.lr_angle; } + inline const Cursor &getUpperLeftAngleCursor(void) const + { return cursor.ul_angle; } + inline const Cursor &getUpperRightAngleCursor(void) const + { return cursor.ur_angle; } + + inline Display *getXDisplay(void) { return display; } + + inline const char *getXDisplayName(void) const + { return (const char *) display_name; } + inline const char *getApplicationName(void) const + { return (const char *) application_name; } + + inline const int &getNumberOfScreens(void) const + { return number_of_screens; } + inline const int &getShapeEventBase(void) const + { return shape.event_basep; } + + inline void shutdown(void) { _shutdown = True; } + inline void run(void) { _startup = _shutdown = False; } + + const Bool validateWindow(Window); + + void grabButton(unsigned int, unsigned int, Window, Bool, unsigned int, int, + int, Window, Cursor) const; + void ungrabButton(unsigned int button, unsigned int modifiers, + Window grab_window) const; + + void grab(void); + void ungrab(void); + void eventLoop(void); + void addTimer(BTimer *); + void removeTimer(BTimer *); + + // another pure virtual... this is used to handle signals that BaseDisplay + // doesn't understand itself + virtual Bool handleSignal(int) = 0; +}; + + +class ScreenInfo { +private: + BaseDisplay *basedisplay; + Visual *visual; + Window root_window; + Colormap colormap; + + int depth, screen_number; + unsigned int width, height; + + +public: + ScreenInfo(BaseDisplay *, int); + + inline BaseDisplay *getBaseDisplay(void) { return basedisplay; } + + inline Visual *getVisual(void) { return visual; } + inline const Window &getRootWindow(void) const { return root_window; } + inline const Colormap &getColormap(void) const { return colormap; } + + inline const int &getDepth(void) const { return depth; } + inline const int &getScreenNumber(void) const { return screen_number; } + + inline const unsigned int &getWidth(void) const { return width; } + inline const unsigned int &getHeight(void) const { return height; } +}; + + +#endif // __BaseDisplay_hh diff --git a/src/Basemenu.cc b/src/Basemenu.cc new file mode 100644 index 00000000..b0e97606 --- /dev/null +++ b/src/Basemenu.cc @@ -0,0 +1,1036 @@ +// Basemenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#include +using namespace std; + +#include "i18n.h" +#include "openbox.h" +#include "Basemenu.h" +#include "Screen.h" + +static Basemenu *shown = (Basemenu *) 0; + +Basemenu::Basemenu(BScreen *scrn) { + screen = scrn; + openbox = screen->getOpenbox(); + image_ctrl = screen->getImageControl(); + display = openbox->getXDisplay(); + parent = (Basemenu *) 0; + alignment = AlignDontCare; + + title_vis = + movable = + hide_tree = True; + + shifted = + internal_menu = + moving = + torn = + visible = False; + + menu.x = + menu.y = + menu.x_shift = + menu.y_shift = + menu.x_move = + menu.y_move = 0; + + which_sub = + which_press = + which_sbl = -1; + + menu.frame_pixmap = + menu.title_pixmap = + menu.hilite_pixmap = + menu.sel_pixmap = None; + + menu.bevel_w = screen->getBevelWidth(); + + if (i18n->multibyte()) + menu.width = menu.title_h = menu.item_w = menu.frame_h = + screen->getMenuStyle()->t_fontset_extents->max_ink_extent.height + + (menu.bevel_w * 2); + else + menu.width = menu.title_h = menu.item_w = menu.frame_h = + screen->getMenuStyle()->t_font->ascent + + screen->getMenuStyle()->t_font->descent + (menu.bevel_w * 2); + + menu.label = 0; + + menu.sublevels = + menu.persub = + menu.minsub = 0; + + MenuStyle *style = screen->getMenuStyle(); + if (i18n->multibyte()) { + menu.item_h = style->f_fontset_extents->max_ink_extent.height + + (menu.bevel_w); + } else { + menu.item_h = style->f_font->ascent + style->f_font->descent + + (menu.bevel_w); + } + + menu.height = menu.title_h + screen->getBorderWidth() + menu.frame_h; + + unsigned long attrib_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | + CWColormap | CWOverrideRedirect | CWEventMask; + XSetWindowAttributes attrib; + attrib.background_pixmap = None; + attrib.background_pixel = attrib.border_pixel = + screen->getBorderColor()->getPixel(); + attrib.colormap = screen->getColormap(); + attrib.override_redirect = True; + attrib.event_mask = ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask; + + menu.window = + XCreateWindow(display, screen->getRootWindow(), menu.x, menu.y, menu.width, + menu.height, screen->getBorderWidth(), screen->getDepth(), + InputOutput, screen->getVisual(), attrib_mask, &attrib); + openbox->saveMenuSearch(menu.window, this); + + attrib_mask = CWBackPixmap | CWBackPixel | CWBorderPixel | CWEventMask; + attrib.background_pixel = screen->getBorderColor()->getPixel(); + attrib.event_mask |= EnterWindowMask | LeaveWindowMask; + + menu.title = + XCreateWindow(display, menu.window, 0, 0, menu.width, menu.height, 0, + screen->getDepth(), InputOutput, screen->getVisual(), + attrib_mask, &attrib); + openbox->saveMenuSearch(menu.title, this); + + attrib.event_mask |= PointerMotionMask; + menu.frame = XCreateWindow(display, menu.window, 0, + menu.title_h + screen->getBorderWidth(), + menu.width, menu.frame_h, 0, + screen->getDepth(), InputOutput, + screen->getVisual(), attrib_mask, &attrib); + openbox->saveMenuSearch(menu.frame, this); + + menuitems = new LinkedList; + + // even though this is the end of the constructor the menu is still not + // completely created. items must be inserted and it must be update()'d +} + + +Basemenu::~Basemenu(void) { + XUnmapWindow(display, menu.window); + + if (shown && shown->getWindowID() == getWindowID()) + shown = (Basemenu *) 0; + + int n = menuitems->count(); + for (int i = 0; i < n; ++i) + remove(0); + + delete menuitems; + + if (menu.label) + delete [] menu.label; + + if (menu.title_pixmap) + image_ctrl->removeImage(menu.title_pixmap); + + if (menu.frame_pixmap) + image_ctrl->removeImage(menu.frame_pixmap); + + if (menu.hilite_pixmap) + image_ctrl->removeImage(menu.hilite_pixmap); + + if (menu.sel_pixmap) + image_ctrl->removeImage(menu.sel_pixmap); + + openbox->removeMenuSearch(menu.title); + XDestroyWindow(display, menu.title); + + openbox->removeMenuSearch(menu.frame); + XDestroyWindow(display, menu.frame); + + openbox->removeMenuSearch(menu.window); + XDestroyWindow(display, menu.window); +} + + +int Basemenu::insert(const char *l, int function, const char *e, int pos) { + char *label = 0, *exec = 0; + + if (l) label = bstrdup(l); + if (e) exec = bstrdup(e); + + BasemenuItem *item = new BasemenuItem(label, function, exec); + menuitems->insert(item, pos); + + return menuitems->count(); +} + + +int Basemenu::insert(const char *l, Basemenu *submenu, int pos) { + char *label = 0; + + if (l) label = bstrdup(l); + + BasemenuItem *item = new BasemenuItem(label, submenu); + menuitems->insert(item, pos); + + submenu->parent = this; + + return menuitems->count(); +} + + +int Basemenu::insert(const char **ulabel, int pos, int function) { + BasemenuItem *item = new BasemenuItem(ulabel, function); + menuitems->insert(item, pos); + + return menuitems->count(); +} + + +int Basemenu::remove(int index) { + if (index < 0 || index > menuitems->count()) return -1; + + BasemenuItem *item = menuitems->remove(index); + + if (item) { + if ((! internal_menu) && (item->submenu())) { + Basemenu *tmp = (Basemenu *) item->submenu(); + + if (! tmp->internal_menu) { + delete tmp; + } else { + tmp->internal_hide(); + } + } + + if (item->label()) + delete [] item->label(); + + if (item->exec()) + delete [] item->exec(); + + delete item; + } + + if (which_sub == index) + which_sub = -1; + else if (which_sub > index) + which_sub--; + + return menuitems->count(); +} + + +void Basemenu::update(void) { + MenuStyle *style = screen->getMenuStyle(); + if (i18n->multibyte()) { + menu.item_h = style->f_fontset_extents->max_ink_extent.height + + menu.bevel_w; + menu.title_h = style->t_fontset_extents->max_ink_extent.height + + (menu.bevel_w * 2); + } else { + menu.item_h = style->f_font->ascent + style->f_font->descent + + menu.bevel_w; + menu.title_h = style->t_font->ascent + style->t_font->descent + + (menu.bevel_w * 2); + } + + if (title_vis) { + const char *s = (menu.label) ? menu.label : + i18n->getMessage(BasemenuSet, BasemenuOpenboxMenu, + "Openbox Menu"); + int l = strlen(s); + + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getMenuStyle()->t_fontset, s, l, &ink, &logical); + menu.item_w = logical.width; + } else { + menu.item_w = XTextWidth(screen->getMenuStyle()->t_font, s, l); + } + + menu.item_w += (menu.bevel_w * 2); + } else { + menu.item_w = 1; + } + + int ii = 0; + LinkedListIterator it(menuitems); + for (BasemenuItem *tmp = it.current(); tmp; it++, tmp = it.current()) { + const char *s = ((tmp->u && *tmp->u) ? *tmp->u : + ((tmp->l) ? tmp->l : (const char *) 0)); + int l = strlen(s); + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getMenuStyle()->f_fontset, s, l, &ink, &logical); + ii = logical.width; + } else + ii = XTextWidth(screen->getMenuStyle()->f_font, s, l); + + ii += (menu.bevel_w * 2) + (menu.item_h * 2); + + menu.item_w = ((menu.item_w < (unsigned int) ii) ? ii : menu.item_w); + } + + if (menuitems->count()) { + menu.sublevels = 1; + + while (((menu.item_h * (menuitems->count() + 1) / menu.sublevels) + + menu.title_h + screen->getBorderWidth()) > + screen->getHeight()) + menu.sublevels++; + + if (menu.sublevels < menu.minsub) menu.sublevels = menu.minsub; + + menu.persub = menuitems->count() / menu.sublevels; + if (menuitems->count() % menu.sublevels) menu.persub++; + } else { + menu.sublevels = 0; + menu.persub = 0; + } + + menu.width = (menu.sublevels * (menu.item_w)); + if (! menu.width) menu.width = menu.item_w; + + menu.frame_h = (menu.item_h * menu.persub); + menu.height = ((title_vis) ? menu.title_h + screen->getBorderWidth() : 0) + + menu.frame_h; + if (! menu.frame_h) menu.frame_h = 1; + if (menu.height < 1) menu.height = 1; + + Pixmap tmp; + BTexture *texture; + if (title_vis) { + tmp = menu.title_pixmap; + texture = &(screen->getMenuStyle()->title); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + menu.title_pixmap = None; + XSetWindowBackground(display, menu.title, + texture->getColor()->getPixel()); + } else { + menu.title_pixmap = + image_ctrl->renderImage(menu.width, menu.title_h, texture); + XSetWindowBackgroundPixmap(display, menu.title, menu.title_pixmap); + } + if (tmp) image_ctrl->removeImage(tmp); + XClearWindow(display, menu.title); + } + + tmp = menu.frame_pixmap; + texture = &(screen->getMenuStyle()->frame); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + menu.frame_pixmap = None; + XSetWindowBackground(display, menu.frame, + texture->getColor()->getPixel()); + } else { + menu.frame_pixmap = + image_ctrl->renderImage(menu.width, menu.frame_h, texture); + XSetWindowBackgroundPixmap(display, menu.frame, menu.frame_pixmap); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = menu.hilite_pixmap; + texture = &(screen->getMenuStyle()->hilite); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + menu.hilite_pixmap = None; + } else { + menu.hilite_pixmap = + image_ctrl->renderImage(menu.item_w, menu.item_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = menu.sel_pixmap; + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + menu.sel_pixmap = None; + } else { + int hw = menu.item_h / 2; + menu.sel_pixmap = + image_ctrl->renderImage(hw, hw, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + XResizeWindow(display, menu.window, menu.width, menu.height); + + if (title_vis) + XResizeWindow(display, menu.title, menu.width, menu.title_h); + + XMoveResizeWindow(display, menu.frame, 0, + ((title_vis) ? menu.title_h + + screen->getBorderWidth() : 0), menu.width, + menu.frame_h); + + XClearWindow(display, menu.window); + XClearWindow(display, menu.title); + XClearWindow(display, menu.frame); + + if (title_vis && visible) redrawTitle(); + + for (int i = 0; visible && i < menuitems->count(); i++) { + if (i == which_sub) { + drawItem(i, True, 0); + drawSubmenu(i); + } else { + drawItem(i, False, 0); + } + } + + if (parent && visible) + parent->drawSubmenu(parent->which_sub); + + XMapSubwindows(display, menu.window); +} + + +void Basemenu::show(void) { + XMapSubwindows(display, menu.window); + XMapWindow(display, menu.window); + visible = True; + + if (! parent) { + if (shown && (! shown->torn)) + shown->hide(); + + shown = this; + } +} + + +void Basemenu::hide(void) { + if ((! torn) && hide_tree && parent && parent->isVisible()) { + Basemenu *p = parent; + + while (p->isVisible() && (! p->torn) && p->parent) p = p->parent; + p->internal_hide(); + } else { + internal_hide(); + } +} + + +void Basemenu::internal_hide(void) { + if (which_sub != -1) { + BasemenuItem *tmp = menuitems->find(which_sub); + tmp->submenu()->internal_hide(); + } + + if (parent && (! torn)) { + parent->drawItem(parent->which_sub, False, True); + + parent->which_sub = -1; + } else if (shown && shown->menu.window == menu.window) { + shown = (Basemenu *) 0; + } + + torn = visible = False; + which_sub = which_press = which_sub = -1; + + XUnmapWindow(display, menu.window); +} + + +void Basemenu::move(int x, int y) { + menu.x = x; + menu.y = y; + XMoveWindow(display, menu.window, x, y); + if (which_sub != -1) + drawSubmenu(which_sub); +} + + +void Basemenu::redrawTitle(void) { + char *text = (char *) ((menu.label) ? menu.label : + i18n->getMessage(BasemenuSet, BasemenuOpenboxMenu, + "Openbox Menu")); + int dx = menu.bevel_w, len = strlen(text); + unsigned int l; + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getMenuStyle()->t_fontset, text, len, &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getMenuStyle()->t_font, text, len); + } + + l += (menu.bevel_w * 2); + + switch (screen->getMenuStyle()->t_justify) { + case BScreen::RightJustify: + dx += menu.width - l; + break; + + case BScreen::CenterJustify: + dx += (menu.width - l) / 2; + break; + } + + MenuStyle *style = screen->getMenuStyle(); + if (i18n->multibyte()) + XmbDrawString(display, menu.title, style->t_fontset, style->t_text_gc, dx, + (menu.bevel_w - style->t_fontset_extents->max_ink_extent.y), + text, len); + else + XDrawString(display, menu.title, style->t_text_gc, dx, + (style->t_font->ascent + menu.bevel_w), text, len); +} + + +void Basemenu::drawSubmenu(int index) { + if (which_sub != -1 && which_sub != index) { + BasemenuItem *itmp = menuitems->find(which_sub); + + if (! itmp->submenu()->isTorn()) + itmp->submenu()->internal_hide(); + } + + if (index >= 0 && index < menuitems->count()) { + BasemenuItem *item = menuitems->find(index); + if (item->submenu() && visible && (! item->submenu()->isTorn()) && + item->isEnabled()) { + if (item->submenu()->parent != this) item->submenu()->parent = this; + int sbl = index / menu.persub, i = index - (sbl * menu.persub), + x = menu.x + + ((menu.item_w * (sbl + 1)) + screen->getBorderWidth()), y; + + if (alignment == AlignTop) + y = (((shifted) ? menu.y_shift : menu.y) + + ((title_vis) ? menu.title_h + screen->getBorderWidth() : 0) - + ((item->submenu()->title_vis) ? + item->submenu()->menu.title_h + screen->getBorderWidth() : 0)); + else + y = (((shifted) ? menu.y_shift : menu.y) + + (menu.item_h * i) + + ((title_vis) ? menu.title_h + screen->getBorderWidth() : 0) - + ((item->submenu()->title_vis) ? + item->submenu()->menu.title_h + screen->getBorderWidth() : 0)); + + if (alignment == AlignBottom && + (y + item->submenu()->menu.height) > ((shifted) ? menu.y_shift : + menu.y) + menu.height) + y = (((shifted) ? menu.y_shift : menu.y) + + menu.height - item->submenu()->menu.height); + + if ((x + item->submenu()->getWidth()) > screen->getWidth()) { + x = ((shifted) ? menu.x_shift : menu.x) - + item->submenu()->getWidth() - screen->getBorderWidth(); + } + + if (x < 0) x = 0; + + if ((y + item->submenu()->getHeight()) > screen->getHeight()) + y = screen->getHeight() - item->submenu()->getHeight() - + (screen->getBorderWidth() * 2); + if (y < 0) y = 0; + + item->submenu()->move(x, y); + if (! moving) drawItem(index, True); + + if (! item->submenu()->isVisible()) + item->submenu()->show(); + item->submenu()->moving = moving; + which_sub = index; + } else { + which_sub = -1; + } + } +} + + +Bool Basemenu::hasSubmenu(int index) { + if ((index >= 0) && (index < menuitems->count())) + if (menuitems->find(index)->submenu()) + return True; + + return False; +} + + +void Basemenu::drawItem(int index, Bool highlight, Bool clear, + int x, int y, unsigned int w, unsigned int h) +{ + if (index < 0 || index > menuitems->count()) return; + + BasemenuItem *item = menuitems->find(index); + if (! item) return; + + Bool dotext = True, dohilite = True, dosel = True; + const char *text = (item->ulabel()) ? *item->ulabel() : item->label(); + int sbl = index / menu.persub, i = index - (sbl * menu.persub); + int item_x = (sbl * menu.item_w), item_y = (i * menu.item_h); + int hilite_x = item_x, hilite_y = item_y, hoff_x = 0, hoff_y = 0; + int text_x = 0, text_y = 0, len = strlen(text), sel_x = 0, sel_y = 0; + unsigned int hilite_w = menu.item_w, hilite_h = menu.item_h, text_w = 0, + text_h = 0; + unsigned int half_w = menu.item_h / 2, quarter_w = menu.item_h / 4; + + if (text) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getMenuStyle()->f_fontset, + text, len, &ink, &logical); + text_w = logical.width; + text_y = item_y + (menu.bevel_w / 2) - + screen->getMenuStyle()->f_fontset_extents->max_ink_extent.y; + } else { + text_w = XTextWidth(screen->getMenuStyle()->f_font, text, len); + text_y = item_y + + screen->getMenuStyle()->f_font->ascent + + (menu.bevel_w / 2); + } + + switch(screen->getMenuStyle()->f_justify) { + case BScreen::LeftJustify: + text_x = item_x + menu.bevel_w + menu.item_h + 1; + break; + + case BScreen::RightJustify: + text_x = item_x + menu.item_w - (menu.item_h + menu.bevel_w + text_w); + break; + + case BScreen::CenterJustify: + text_x = item_x + ((menu.item_w + 1 - text_w) / 2); + break; + } + + text_h = menu.item_h - menu.bevel_w; + } + + GC gc = + ((highlight || item->isSelected()) ? screen->getMenuStyle()->h_text_gc : + screen->getMenuStyle()->f_text_gc), + tgc = + ((highlight) ? screen->getMenuStyle()->h_text_gc : + ((item->isEnabled()) ? screen->getMenuStyle()->f_text_gc : + screen->getMenuStyle()->d_text_gc)); + + sel_x = item_x; + if (screen->getMenuStyle()->bullet_pos == Right) + sel_x += (menu.item_w - menu.item_h - menu.bevel_w); + sel_x += quarter_w; + sel_y = item_y + quarter_w; + + if (clear) { + XClearArea(display, menu.frame, item_x, item_y, menu.item_w, menu.item_h, + False); + } else if (! (x == y && y == -1 && w == h && h == 0)) { + // calculate the which part of the hilite to redraw + if (! (max(item_x, x) <= (signed) min(item_x + menu.item_w, x + w) && + max(item_y, y) <= (signed) min(item_y + menu.item_h, y + h))) { + dohilite = False; + } else { + hilite_x = max(item_x, x); + hilite_y = max(item_y, y); + hilite_w = min(item_x + menu.item_w, x + w) - hilite_x; + hilite_h = min(item_y + menu.item_h, y + h) - hilite_y; + hoff_x = hilite_x % menu.item_w; + hoff_y = hilite_y % menu.item_h; + } + + // check if we need to redraw the text + int text_ry = item_y + (menu.bevel_w / 2); + if (! (max(text_x, x) <= (signed) min(text_x + text_w, x + w) && + max(text_ry, y) <= (signed) min(text_ry + text_h, y + h))) + dotext = False; + + // check if we need to redraw the select pixmap/menu bullet + if (! (max(sel_x, x) <= (signed) min(sel_x + half_w, x + w) && + max(sel_y, y) <= (signed) min(sel_y + half_w, y + h))) + dosel = False; + } + + if (dohilite && highlight && (menu.hilite_pixmap != ParentRelative)) { + if (menu.hilite_pixmap) + XCopyArea(display, menu.hilite_pixmap, menu.frame, + screen->getMenuStyle()->hilite_gc, hoff_x, hoff_y, + hilite_w, hilite_h, hilite_x, hilite_y); + else + XFillRectangle(display, menu.frame, + screen->getMenuStyle()->hilite_gc, + hilite_x, hilite_y, hilite_w, hilite_h); + } else if (dosel && item->isSelected() && + (menu.sel_pixmap != ParentRelative)) { + if (menu.sel_pixmap) + XCopyArea(display, menu.sel_pixmap, menu.frame, + screen->getMenuStyle()->hilite_gc, 0, 0, + half_w, half_w, sel_x, sel_y); + else + XFillRectangle(display, menu.frame, + screen->getMenuStyle()->hilite_gc, + sel_x, sel_y, half_w, half_w); + } + + if (dotext && text) { + if (i18n->multibyte()) + XmbDrawString(display, menu.frame, screen->getMenuStyle()->f_fontset, + tgc, text_x, text_y, text, len); + else + XDrawString(display, menu.frame, tgc, text_x, text_y, text, len); + } + + if (dosel && item->submenu()) { + switch (screen->getMenuStyle()->bullet) { + case Square: + XDrawRectangle(display, menu.frame, gc, sel_x, sel_y, half_w, half_w); + break; + + case Triangle: + XPoint tri[3]; + + if (screen->getMenuStyle()->bullet_pos == Right) { + tri[0].x = sel_x + quarter_w - 2; + tri[0].y = sel_y + quarter_w - 2; + tri[1].x = 4; + tri[1].y = 2; + tri[2].x = -4; + tri[2].y = 2; + } else { + tri[0].x = sel_x + quarter_w - 2; + tri[0].y = item_y + half_w; + tri[1].x = 4; + tri[1].y = 2; + tri[2].x = 0; + tri[2].y = -4; + } + + XFillPolygon(display, menu.frame, gc, tri, 3, Convex, + CoordModePrevious); + break; + + case Diamond: + XPoint dia[4]; + + dia[0].x = sel_x + quarter_w - 3; + dia[0].y = item_y + half_w; + dia[1].x = 3; + dia[1].y = -3; + dia[2].x = 3; + dia[2].y = 3; + dia[3].x = -3; + dia[3].y = 3; + + XFillPolygon(display, menu.frame, gc, dia, 4, Convex, + CoordModePrevious); + break; + } + } +} + + +void Basemenu::setLabel(const char *l) { + if (menu.label) + delete [] menu.label; + + if (l) menu.label = bstrdup(l); + else menu.label = 0; +} + + +void Basemenu::setItemSelected(int index, Bool sel) { + if (index < 0 || index >= menuitems->count()) return; + + BasemenuItem *item = find(index); + if (! item) return; + + item->setSelected(sel); + if (visible) drawItem(index, (index == which_sub), True); +} + + +Bool Basemenu::isItemSelected(int index) { + if (index < 0 || index >= menuitems->count()) return False; + + BasemenuItem *item = find(index); + if (! item) return False; + + return item->isSelected(); +} + + +void Basemenu::setItemEnabled(int index, Bool enable) { + if (index < 0 || index >= menuitems->count()) return; + + BasemenuItem *item = find(index); + if (! item) return; + + item->setEnabled(enable); + if (visible) drawItem(index, (index == which_sub), True); +} + + +Bool Basemenu::isItemEnabled(int index) { + if (index < 0 || index >= menuitems->count()) return False; + + BasemenuItem *item = find(index); + if (! item) return False; + + return item->isEnabled(); +} + + +void Basemenu::buttonPressEvent(XButtonEvent *be) { + if (be->window == menu.frame) { + int sbl = (be->x / menu.item_w), i = (be->y / menu.item_h); + int w = (sbl * menu.persub) + i; + + if (w < menuitems->count() && w >= 0) { + which_press = i; + which_sbl = sbl; + + BasemenuItem *item = menuitems->find(w); + + if (item->submenu()) + drawSubmenu(w); + else + drawItem(w, (item->isEnabled()), True); + } + } else { + menu.x_move = be->x_root - menu.x; + menu.y_move = be->y_root - menu.y; + } +} + + +void Basemenu::buttonReleaseEvent(XButtonEvent *re) { + if (re->window == menu.title) { + if (moving) { + moving = False; + + if (which_sub != -1) + drawSubmenu(which_sub); + } + + if (re->x >= 0 && re->x <= (signed) menu.width && + re->y >= 0 && re->y <= (signed) menu.title_h) + if (re->button == 3) + hide(); + } else if (re->window == menu.frame && + re->x >= 0 && re->x < (signed) menu.width && + re->y >= 0 && re->y < (signed) menu.frame_h) { + if (re->button == 3) { + hide(); + } else { + int sbl = (re->x / menu.item_w), i = (re->y / menu.item_h), + ix = sbl * menu.item_w, iy = i * menu.item_h, + w = (sbl * menu.persub) + i, + p = (which_sbl * menu.persub) + which_press; + + if (w < menuitems->count() && w >= 0) { + drawItem(p, (p == which_sub), True); + + if (p == w && isItemEnabled(w)) { + if (re->x > ix && re->x < (signed) (ix + menu.item_w) && + re->y > iy && re->y < (signed) (iy + menu.item_h)) { + itemSelected(re->button, w); + } + } + } else + drawItem(p, False, True); + } + } +} + + +void Basemenu::motionNotifyEvent(XMotionEvent *me) { + if (me->window == menu.title && (me->state & Button1Mask)) { + if (movable) { + if (! moving) { + if (parent && (! torn)) { + parent->drawItem(parent->which_sub, False, True); + parent->which_sub = -1; + } + + moving = torn = True; + + if (which_sub != -1) + drawSubmenu(which_sub); + } else { + menu.x = me->x_root - menu.x_move, + menu.y = me->y_root - menu.y_move; + + XMoveWindow(display, menu.window, menu.x, menu.y); + + if (which_sub != -1) + drawSubmenu(which_sub); + } + } + } else if ((! (me->state & Button1Mask)) && me->window == menu.frame && + me->x >= 0 && me->x < (signed) menu.width && + me->y >= 0 && me->y < (signed) menu.frame_h) { + int sbl = (me->x / menu.item_w), i = (me->y / menu.item_h), + w = (sbl * menu.persub) + i; + + if ((i != which_press || sbl != which_sbl) && + (w < menuitems->count() && w >= 0)) { + if (which_press != -1 && which_sbl != -1) { + int p = (which_sbl * menu.persub) + which_press; + BasemenuItem *item = menuitems->find(p); + + drawItem(p, False, True); + if (item->submenu()) + if (item->submenu()->isVisible() && + (! item->submenu()->isTorn())) { + item->submenu()->internal_hide(); + which_sub = -1; + } + } + + which_press = i; + which_sbl = sbl; + + BasemenuItem *itmp = menuitems->find(w); + + if (itmp->submenu()) + drawSubmenu(w); + else + drawItem(w, (itmp->isEnabled()), True); + } + } +} + + +void Basemenu::exposeEvent(XExposeEvent *ee) { + if (ee->window == menu.title) { + redrawTitle(); + } else if (ee->window == menu.frame) { + // this is a compilicated algorithm... lets do it step by step... + // first... we see in which sub level the expose starts... and how many + // items down in that sublevel + + int sbl = (ee->x / menu.item_w), id = (ee->y / menu.item_h), + // next... figure out how many sublevels over the redraw spans + sbl_d = ((ee->x + ee->width) / menu.item_w), + // then we see how many items down to redraw + id_d = ((ee->y + ee->height) / menu.item_h); + + if (id_d > menu.persub) id_d = menu.persub; + + // draw the sublevels and the number of items the exposure spans + LinkedListIterator it(menuitems); + int i, ii; + for (i = sbl; i <= sbl_d; i++) { + // set the iterator to the first item in the sublevel needing redrawing + it.set(id + (i * menu.persub)); + for (ii = id; ii <= id_d && it.current(); it++, ii++) { + int index = ii + (i * menu.persub); + // redraw the item + drawItem(index, (which_sub == index), False, + ee->x, ee->y, ee->width, ee->height); + } + } + } +} + + +void Basemenu::enterNotifyEvent(XCrossingEvent *ce) { + if (ce->window == menu.frame) { + menu.x_shift = menu.x, menu.y_shift = menu.y; + if (menu.x + menu.width > screen->getWidth()) { + menu.x_shift = screen->getWidth() - menu.width - + screen->getBorderWidth(); + shifted = True; + } else if (menu.x < 0) { + menu.x_shift = -screen->getBorderWidth(); + shifted = True; + } + + if (menu.y + menu.height > screen->getHeight()) { + menu.y_shift = screen->getHeight() - menu.height - + screen->getBorderWidth(); + shifted = True; + } else if (menu.y + (signed) menu.title_h < 0) { + menu.y_shift = -screen->getBorderWidth(); + shifted = True; + } + + if (shifted) + XMoveWindow(display, menu.window, menu.x_shift, menu.y_shift); + + if (which_sub != -1) { + BasemenuItem *tmp = menuitems->find(which_sub); + if (tmp->submenu()->isVisible()) { + int sbl = (ce->x / menu.item_w), i = (ce->y / menu.item_h), + w = (sbl * menu.persub) + i; + + if (w != which_sub && (! tmp->submenu()->isTorn())) { + tmp->submenu()->internal_hide(); + + drawItem(which_sub, False, True); + which_sub = -1; + } + } + } + } +} + + +void Basemenu::leaveNotifyEvent(XCrossingEvent *ce) { + if (ce->window == menu.frame) { + if (which_press != -1 && which_sbl != -1 && menuitems->count() > 0) { + int p = (which_sbl * menu.persub) + which_press; + + drawItem(p, (p == which_sub), True); + + which_sbl = which_press = -1; + } + + if (shifted) { + XMoveWindow(display, menu.window, menu.x, menu.y); + shifted = False; + + if (which_sub != -1) drawSubmenu(which_sub); + } + } +} + + +void Basemenu::reconfigure(void) { + XSetWindowBackground(display, menu.window, + screen->getBorderColor()->getPixel()); + XSetWindowBorder(display, menu.window, + screen->getBorderColor()->getPixel()); + XSetWindowBorderWidth(display, menu.window, screen->getBorderWidth()); + + menu.bevel_w = screen->getBevelWidth(); + update(); +} diff --git a/src/Basemenu.h b/src/Basemenu.h new file mode 100644 index 00000000..ba28404c --- /dev/null +++ b/src/Basemenu.h @@ -0,0 +1,170 @@ +// Basemenu.h for Openbox +// 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 __Basemenu_hh +#define __Basemenu_hh + +#include + +class Openbox; +class BImageControl; +class BScreen; +class Basemenu; +class BasemenuItem; +#include "LinkedList.h" + + +class Basemenu { +private: + LinkedList *menuitems; + Openbox *openbox; + Basemenu *parent; + BImageControl *image_ctrl; + BScreen *screen; + + Bool moving, visible, movable, torn, internal_menu, title_vis, shifted, + hide_tree; + Display *display; + int which_sub, which_press, which_sbl, alignment; + + struct _menu { + Pixmap frame_pixmap, title_pixmap, hilite_pixmap, sel_pixmap; + Window window, frame, title; + + char *label; + int x, y, x_move, y_move, x_shift, y_shift, sublevels, persub, minsub, + grab_x, grab_y; + unsigned int width, height, title_h, frame_h, item_w, item_h, bevel_w, + bevel_h; + } menu; + + +protected: + inline BasemenuItem *find(int index) { return menuitems->find(index); } + inline void setTitleVisibility(Bool b) { title_vis = b; } + inline void setMovable(Bool b) { movable = b; } + inline void setHideTree(Bool h) { hide_tree = h; } + inline void setMinimumSublevels(int m) { menu.minsub = m; } + + virtual void itemSelected(int, int) = 0; + virtual void drawItem(int, Bool = False, Bool = False, + int = -1, int = -1, unsigned int = 0, + unsigned int = 0); + virtual void redrawTitle(); + virtual void internal_hide(void); + + +public: + Basemenu(BScreen *); + virtual ~Basemenu(void); + + inline const Bool &isTorn(void) const { return torn; } + inline const Bool &isVisible(void) const { return visible; } + + inline BScreen *getScreen(void) { return screen; } + + inline const Window &getWindowID(void) const { return menu.window; } + + inline const char *getLabel(void) const { return menu.label; } + + int insert(const char *, int = 0, const char * = (const char *) 0, int = -1); + int insert(const char **, int = -1, int = 0); + int insert(const char *, Basemenu *, int = -1); + int remove(int); + + inline const int &getX(void) const { return menu.x; } + inline const int &getY(void) const { return menu.y; } + inline int getCount(void) { return menuitems->count(); } + inline const int &getCurrentSubmenu(void) const { return which_sub; } + + inline const unsigned int &getWidth(void) const { return menu.width; } + inline const unsigned int &getHeight(void) const { return menu.height; } + inline const unsigned int &getTitleHeight(void) const + { return menu.title_h; } + + inline void setInternalMenu(void) { internal_menu = True; } + inline void setAlignment(int a) { alignment = a; } + inline void setTorn(void) { torn = True; } + inline void removeParent(void) + { if (internal_menu) parent = (Basemenu *) 0; } + + Bool hasSubmenu(int); + Bool isItemSelected(int); + Bool isItemEnabled(int); + + void buttonPressEvent(XButtonEvent *); + void buttonReleaseEvent(XButtonEvent *); + void motionNotifyEvent(XMotionEvent *); + void enterNotifyEvent(XCrossingEvent *); + void leaveNotifyEvent(XCrossingEvent *); + void exposeEvent(XExposeEvent *); + void reconfigure(void); + void setLabel(const char *n); + void move(int, int); + void update(void); + void setItemSelected(int, Bool); + void setItemEnabled(int, Bool); + + virtual void drawSubmenu(int); + virtual void show(void); + virtual void hide(void); + + enum { AlignDontCare = 1, AlignTop, AlignBottom }; + enum { Right = 1, Left }; + enum { Empty = 0, Square, Triangle, Diamond }; +}; + + +class BasemenuItem { +private: + Basemenu *s; + const char **u, *l, *e; + int f, enabled, selected; + + friend class Basemenu; + +protected: + +public: + BasemenuItem(const char *lp, int fp, const char *ep = (const char *) 0): + s(0), u(0), l(lp), e(ep), f(fp), enabled(1), selected(0) {} + + BasemenuItem(const char *lp, Basemenu *mp): s(mp), u(0), l(lp), e(0), f(0), + enabled(1), selected(0) {} + + BasemenuItem(const char **up, int fp): s(0), u(up), l(0), e(0), f(fp), + enabled(1), selected(0) {} + + inline const char *exec(void) const { return e; } + inline const char *label(void) const { return l; } + inline const char **ulabel(void) const { return u; } + inline const int &function(void) const { return f; } + inline Basemenu *submenu(void) { return s; } + + inline const int &isEnabled(void) const { return enabled; } + inline void setEnabled(int e) { enabled = e; } + inline const int &isSelected(void) const { return selected; } + inline void setSelected(int s) { selected = s; } +}; + + +#endif // __Basemenu_hh diff --git a/src/Clientmenu.cc b/src/Clientmenu.cc new file mode 100644 index 00000000..2191f2a5 --- /dev/null +++ b/src/Clientmenu.cc @@ -0,0 +1,64 @@ +// Clientmenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "openbox.h" +#include "Clientmenu.h" +#include "Screen.h" +#include "Window.h" +#include "Workspace.h" +#include "Workspacemenu.h" + + +Clientmenu::Clientmenu(Workspace *ws) : Basemenu(ws->getScreen()) { + wkspc = ws; + screen = wkspc->getScreen(); + + setInternalMenu(); +} + + +void Clientmenu::itemSelected(int button, int index) { + if (button > 2) return; + + OpenboxWindow *win = wkspc->getWindow(index); + if (win) { + if (button == 1) { + if (! wkspc->isCurrent()) wkspc->setCurrent(); + } else if (button == 2) { + if (! wkspc->isCurrent()) win->deiconify(True, False); + } + wkspc->raiseWindow(win); + win->setInputFocus(); + } + + if (! (screen->getWorkspacemenu()->isTorn() || isTorn())) hide(); +} diff --git a/src/Clientmenu.h b/src/Clientmenu.h new file mode 100644 index 00000000..3b9792e1 --- /dev/null +++ b/src/Clientmenu.h @@ -0,0 +1,44 @@ +// Clientmenu.h for Openbox +// 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 __Clientmenu_hh +#define __Clientmenu_hh + +#include "Basemenu.h" +class Workspace; +class BScreen; + +class Clientmenu : public Basemenu { +private: + BScreen *screen; + Workspace *wkspc; + +protected: + virtual void itemSelected(int, int); + +public: + Clientmenu(Workspace *); +}; + + +#endif // __Clientmenu_hh + diff --git a/src/Configmenu.cc b/src/Configmenu.cc new file mode 100644 index 00000000..97faf779 --- /dev/null +++ b/src/Configmenu.cc @@ -0,0 +1,323 @@ +// Configmenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "Configmenu.h" +#include "Toolbar.h" +#include "Window.h" +#include "Screen.h" + +Configmenu::Configmenu(BScreen *scr) : Basemenu(scr) { + screen = scr; + openbox = screen->getOpenbox(); + setLabel(i18n->getMessage(ConfigmenuSet, ConfigmenuConfigOptions, + "Config options")); + setInternalMenu(); + + focusmenu = new Focusmenu(this); + placementmenu = new Placementmenu(this); + + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuFocusModel, + "Focus Model"), focusmenu); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuWindowPlacement, + "Window Placement"), placementmenu); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuImageDithering, + "Image Dithering"), 1); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuOpaqueMove, + "Opaque Window Moving"), 2); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuFullMax, + "Full Maximization"), 3); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuFocusNew, + "Focus New Windows"), 4); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuFocusLast, + "Focus Last Window on Workspace"), 5); + update(); + + setItemSelected(2, screen->getImageControl()->doDither()); + setItemSelected(3, screen->doOpaqueMove()); + setItemSelected(4, screen->doFullMax()); + setItemSelected(5, screen->doFocusNew()); + setItemSelected(6, screen->doFocusLast()); +} + +Configmenu::~Configmenu(void) { + delete focusmenu; + delete placementmenu; +} + +void Configmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + + if (!item->function()) + return; + + switch(item->function()) { + case 1: { // dither + screen->getImageControl()-> + setDither((! screen->getImageControl()->doDither())); + + setItemSelected(index, screen->getImageControl()->doDither()); + + break; + } + + case 2: { // opaque move + screen->saveOpaqueMove((! screen->doOpaqueMove())); + + setItemSelected(index, screen->doOpaqueMove()); + + break; + } + + case 3: { // full maximization + screen->saveFullMax((! screen->doFullMax())); + + setItemSelected(index, screen->doFullMax()); + + break; + } + case 4: { // focus new windows + screen->saveFocusNew((! screen->doFocusNew())); + + setItemSelected(index, screen->doFocusNew()); + break; + } + + case 5: { // focus last window on workspace + screen->saveFocusLast((! screen->doFocusLast())); + setItemSelected(index, screen->doFocusLast()); + break; + } + } // switch +} + +void Configmenu::reconfigure(void) { + focusmenu->reconfigure(); + placementmenu->reconfigure(); + + Basemenu::reconfigure(); +} + +Configmenu::Focusmenu::Focusmenu(Configmenu *cm) : Basemenu(cm->screen) { + configmenu = cm; + + setLabel(i18n->getMessage(ConfigmenuSet, ConfigmenuFocusModel, + "Focus Model")); + setInternalMenu(); + + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuClickToFocus, + "Click To Focus"), 1); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuSloppyFocus, + "Sloppy Focus"), 2); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuAutoRaise, + "Auto Raise"), 3); + update(); + + setItemSelected(0, (! configmenu->screen->isSloppyFocus())); + setItemSelected(1, configmenu->screen->isSloppyFocus()); + setItemEnabled(2, configmenu->screen->isSloppyFocus()); + setItemSelected(2, configmenu->screen->doAutoRaise()); +} + +void Configmenu::Focusmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + + if (!item->function()) + return; + + switch (item->function()) { + case 1: // click to focus + configmenu->screen->saveSloppyFocus(False); + configmenu->screen->saveAutoRaise(False); + + if (! configmenu->screen->getOpenbox()->getFocusedWindow()) + XSetInputFocus(configmenu->screen->getOpenbox()->getXDisplay(), + configmenu->screen->getToolbar()->getWindowID(), + RevertToParent, CurrentTime); + else + XSetInputFocus(configmenu->screen->getOpenbox()->getXDisplay(), + configmenu->screen->getOpenbox()-> + getFocusedWindow()->getClientWindow(), + RevertToParent, CurrentTime); + + configmenu->screen->reconfigure(); + + break; + + case 2: // sloppy focus + configmenu->screen->saveSloppyFocus(True); + + configmenu->screen->reconfigure(); + + break; + + case 3: // auto raise with sloppy focus + Bool change = ((configmenu->screen->doAutoRaise()) ? False : True); + configmenu->screen->saveAutoRaise(change); + + break; + } + + setItemSelected(0, (! configmenu->screen->isSloppyFocus())); + setItemSelected(1, configmenu->screen->isSloppyFocus()); + setItemEnabled(2, configmenu->screen->isSloppyFocus()); + setItemSelected(2, configmenu->screen->doAutoRaise()); +} + +Configmenu::Placementmenu::Placementmenu(Configmenu *cm) : + Basemenu(cm->screen) { + configmenu = cm; + + setLabel(i18n->getMessage(ConfigmenuSet, ConfigmenuWindowPlacement, + "Window Placement")); + setInternalMenu(); + + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuSmartRows, + "Smart Placement (Rows)"), + BScreen::RowSmartPlacement); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuSmartCols, + "Smart Placement (Columns)"), + BScreen::ColSmartPlacement); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuCascade, + "Cascade Placement"), BScreen::CascadePlacement); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuLeftRight, + "Left to Right"), BScreen::LeftRight); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuRightLeft, + "Right to Left"), BScreen::RightLeft); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuTopBottom, + "Top to Bottom"), BScreen::TopBottom); + insert(i18n->getMessage(ConfigmenuSet, ConfigmenuBottomTop, + "Bottom to Top"), BScreen::BottomTop); + update(); + + switch (configmenu->screen->getPlacementPolicy()) { + case BScreen::RowSmartPlacement: + setItemSelected(0, True); + break; + + case BScreen::ColSmartPlacement: + setItemSelected(1, True); + break; + + case BScreen::CascadePlacement: + setItemSelected(2, True); + break; + } + + Bool rl = (configmenu->screen->getRowPlacementDirection() == + BScreen::LeftRight), + tb = (configmenu->screen->getColPlacementDirection() == + BScreen::TopBottom); + + setItemSelected(3, rl); + setItemSelected(4, ! rl); + + setItemSelected(5, tb); + setItemSelected(6, ! tb); +} + +void Configmenu::Placementmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + + if (!item->function()) + return; + + switch (item->function()) { + case BScreen::RowSmartPlacement: + configmenu->screen->savePlacementPolicy(item->function()); + + setItemSelected(0, True); + setItemSelected(1, False); + setItemSelected(2, False); + + break; + + case BScreen::ColSmartPlacement: + configmenu->screen->savePlacementPolicy(item->function()); + + setItemSelected(0, False); + setItemSelected(1, True); + setItemSelected(2, False); + + break; + + case BScreen::CascadePlacement: + configmenu->screen->savePlacementPolicy(item->function()); + + setItemSelected(0, False); + setItemSelected(1, False); + setItemSelected(2, True); + + break; + + case BScreen::LeftRight: + configmenu->screen->saveRowPlacementDirection(BScreen::LeftRight); + + setItemSelected(3, True); + setItemSelected(4, False); + + break; + + case BScreen::RightLeft: + configmenu->screen->saveRowPlacementDirection(BScreen::RightLeft); + + setItemSelected(3, False); + setItemSelected(4, True); + + break; + + case BScreen::TopBottom: + configmenu->screen->saveColPlacementDirection(BScreen::TopBottom); + + setItemSelected(5, True); + setItemSelected(6, False); + + break; + + case BScreen::BottomTop: + configmenu->screen->saveColPlacementDirection(BScreen::BottomTop); + + setItemSelected(5, False); + setItemSelected(6, True); + + break; + } +} diff --git a/src/Configmenu.h b/src/Configmenu.h new file mode 100644 index 00000000..c9d8f805 --- /dev/null +++ b/src/Configmenu.h @@ -0,0 +1,78 @@ +// Configmenu.h for Openbox +// 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 __Configmenu_hh +#define __Configmenu_hh + +#include "Basemenu.h" + +// forward declaration +class Openbox; +class BScreen; +class Configmenu; + +class Configmenu : public Basemenu { +private: + class Focusmenu : public Basemenu { + private: + Configmenu *configmenu; + + protected: + virtual void itemSelected(int, int); + + public: + Focusmenu(Configmenu *); + }; + + class Placementmenu : public Basemenu { + private: + Configmenu *configmenu; + + protected: + virtual void itemSelected(int, int); + + public: + Placementmenu(Configmenu *); + }; + + Openbox *openbox; + BScreen *screen; + Focusmenu *focusmenu; + Placementmenu *placementmenu; + + friend class Focusmenu; + friend class Placementmenu; + +protected: + virtual void itemSelected(int, int); + +public: + Configmenu(BScreen *); + virtual ~Configmenu(void); + + inline Basemenu *getFocusmenu(void) { return focusmenu; } + inline Basemenu *getPlacementmenu(void) { return placementmenu; } + + void reconfigure(void); +}; + +#endif // __Configmenu_hh diff --git a/src/Iconmenu.cc b/src/Iconmenu.cc new file mode 100644 index 00000000..32ae67a4 --- /dev/null +++ b/src/Iconmenu.cc @@ -0,0 +1,64 @@ +// Icon.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "Iconmenu.h" +#include "Screen.h" +#include "Window.h" + + +Iconmenu::Iconmenu(BScreen *scrn) : Basemenu(scrn) { + setInternalMenu(); + + screen = scrn; + + setLabel(i18n->getMessage(IconSet, IconIcons, "Icons")); + update(); +} + + +void Iconmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + if (index >= 0 && index < screen->getIconCount()) { + OpenboxWindow *win = screen->getIcon(index); + + if (win) { + win->deiconify(); + win->setInputFocus(); + } + } + + if (! (screen->getWorkspacemenu()->isTorn() || isTorn())) + hide(); +} diff --git a/src/Iconmenu.h b/src/Iconmenu.h new file mode 100644 index 00000000..ca1b103d --- /dev/null +++ b/src/Iconmenu.h @@ -0,0 +1,44 @@ +// Icon.h for Openbox +// 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 __Icon_hh +#define __Icon_hh + +#include "Basemenu.h" + +// forward declaration +class Iconmenu; +class BScreen; + +class Iconmenu : public Basemenu { +private: + BScreen *screen; + +protected: + virtual void itemSelected(int, int); + +public: + Iconmenu(BScreen *); +}; + + +#endif // __Icon_hh diff --git a/src/Image.cc b/src/Image.cc new file mode 100644 index 00000000..d42d1d12 --- /dev/null +++ b/src/Image.cc @@ -0,0 +1,2444 @@ +// Image.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "BaseDisplay.h" +#include "Image.h" + +#ifdef HAVE_SYS_TYPES_H +# include +#endif // HAVE_SYS_TYPES_H + +#ifndef u_int32_t +# ifdef uint_32_t +typedef uint32_t u_int32_t; +# else +# ifdef __uint32_t +typedef __uint32_t u_int32_t; +# else +typedef unsigned int u_int32_t; +# endif +# endif +#endif + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef HAVE_CTYPE_H +# include +#endif // HAVE_CTYPE_H + +#include +using namespace std; + +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; + } +} + + +BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) { + control = c; + + width = ((signed) w > 0) ? w : 1; + height = ((signed) 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) { + if (red) delete [] red; + if (green) delete [] green; + if (blue) delete [] blue; +} + + +Pixmap BImage::render(BTexture *texture) { + if (texture->getTexture() & BImage_ParentRelative) + return ParentRelative; + else if (texture->getTexture() & BImage_Solid) + return render_solid(texture); + else if (texture->getTexture() & BImage_Gradient) + return render_gradient(texture); + + return None; +} + + +Pixmap BImage::render_solid(BTexture *texture) { + Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(), + control->getDrawable(), width, + height, control->getDepth()); + if (pixmap == None) { + fprintf(stderr, i18n->getMessage(ImageSet, ImageErrorCreatingSolidPixmap, + "BImage::render_solid: error creating pixmap\n")); + return None; + } + + XGCValues gcv; + GC gc, hgc, lgc; + + gcv.foreground = texture->getColor()->getPixel(); + gcv.fill_style = FillSolid; + gc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, + GCForeground | GCFillStyle, &gcv); + + gcv.foreground = texture->getHiColor()->getPixel(); + hgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, + GCForeground, &gcv); + + gcv.foreground = texture->getLoColor()->getPixel(); + lgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, + GCForeground, &gcv); + + XFillRectangle(control->getBaseDisplay()->getXDisplay(), pixmap, gc, 0, 0, + width, height); + +#ifdef INTERLACE + if (texture->getTexture() & BImage_Interlaced) { + gcv.foreground = texture->getColorTo()->getPixel(); + GC igc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap, + GCForeground, &gcv); + + register unsigned int i = 0; + for (; i < height; i += 2) + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, igc, + 0, i, width, i); + + XFreeGC(control->getBaseDisplay()->getXDisplay(), igc); + } +#endif // INTERLACE + + + if (texture->getTexture() & BImage_Bevel1) { + if (texture->getTexture() & BImage_Raised) { + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 0, height - 1, width - 1, height - 1); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + width - 1, height - 1, width - 1, 0); + + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 0, 0, width - 1, 0); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 0, height - 1, 0, 0); + } else if (texture->getTexture() & BImage_Sunken) { + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 0, height - 1, width - 1, height - 1); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + width - 1, height - 1, width - 1, 0); + + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 0, 0, width - 1, 0); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 0, height - 1, 0, 0); + } + } else if (texture->getTexture() & BImage_Bevel2) { + if (texture->getTexture() & BImage_Raised) { + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 1, height - 3, width - 3, height - 3); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + width - 3, height - 3, width - 3, 1); + + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 1, 1, width - 3, 1); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 1, height - 3, 1, 1); + } else if (texture->getTexture() & BImage_Sunken) { + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + 1, height - 3, width - 3, height - 3); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc, + width - 3, height - 3, width - 3, 1); + + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 1, 1, width - 3, 1); + XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc, + 1, height - 3, 1, 1); + } + } + + XFreeGC(control->getBaseDisplay()->getXDisplay(), gc); + XFreeGC(control->getBaseDisplay()->getXDisplay(), hgc); + XFreeGC(control->getBaseDisplay()->getXDisplay(), lgc); + + return pixmap; +} + + +Pixmap BImage::render_gradient(BTexture *texture) { + int inverted = 0; + +#ifdef INTERLACE + interlaced = texture->getTexture() & BImage_Interlaced; +#endif // INTERLACE + + if (texture->getTexture() & BImage_Sunken) { + from = texture->getColorTo(); + to = texture->getColor(); + + if (! (texture->getTexture() & BImage_Invert)) inverted = 1; + } else { + from = texture->getColor(); + to = texture->getColorTo(); + + if (texture->getTexture() & BImage_Invert) inverted = 1; + } + + control->getGradientBuffers(width, height, &xtable, &ytable); + + if (texture->getTexture() & BImage_Diagonal) dgradient(); + else if (texture->getTexture() & BImage_Elliptic) egradient(); + else if (texture->getTexture() & BImage_Horizontal) hgradient(); + else if (texture->getTexture() & BImage_Pyramid) pgradient(); + else if (texture->getTexture() & BImage_Rectangle) rgradient(); + else if (texture->getTexture() & BImage_Vertical) vgradient(); + else if (texture->getTexture() & BImage_CrossDiagonal) cdgradient(); + else if (texture->getTexture() & BImage_PipeCross) pcgradient(); + + if (texture->getTexture() & BImage_Bevel1) bevel1(); + else if (texture->getTexture() & BImage_Bevel2) bevel2(); + + if (inverted) invert(); + + Pixmap pixmap = renderPixmap(); + + return pixmap; + +} + + +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->getMessage(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)]; + register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset; + + unsigned char *pixel_data = d, *ppixel_data = d; + unsigned long pixel; + + o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0); + + if (control->doDither() && width > 1 && height > 1) { + unsigned char dither4[4][4] = { {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2} }; + +#ifdef ORDEREDPSEUDO + 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 } }; +#endif // ORDEREDPSEUDO + + switch (control->getVisual()->c_class) { + case TrueColor: + // 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 + 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); + + switch (o) { + 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; + } + } + + pixel_data = (ppixel_data += image->bytes_per_line); + } + + break; + + case StaticColor: + case PseudoColor: { +#ifndef ORDEREDPSEUDO + 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(); + + 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; +#endif // ORDEREDPSEUDO + + for (y = 0, offset = 0; y < height; y++) { +#ifdef ORDEREDPSEUDO + 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 += image->bytes_per_line); + } +#else // !ORDEREDPSEUDO + 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 += image->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; +#endif // ORDEREDPSUEDO + + break; } + + default: + fprintf(stderr, i18n->getMessage(ImageSet, ImageUnsupVisual, + "BImage::renderXImage: unsupported visual\n")); + delete [] d; + XDestroyImage(image); + return (XImage *) 0; + } + } else { + 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); + + switch (o) { + 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; + } + } + + 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: + fprintf(stderr, i18n->getMessage(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->getMessage(ImageSet, ImageErrorCreatingPixmap, + "BImage::renderPixmap: error creating pixmap\n")); + return None; + } + + XImage *image = renderXImage(); + + if (! image) { + XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap); + return None; + } else 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::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->getRed(), + xg = (float) from->getGreen(), + xb = (float) from->getBlue(); + 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->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + // 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE + +} + + +void BImage::hgradient(void) { + float drx, dgx, dbx, + xr = (float) from->getRed(), + xg = (float) from->getGreen(), + xb = (float) from->getBlue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int x, y; + + drx = (float) (to->getRed() - from->getRed()); + dgx = (float) (to->getGreen() - from->getGreen()); + dbx = (float) (to->getBlue() - from->getBlue()); + + drx /= width; + dgx /= width; + dbx /= width; + +#ifdef INTERLACE + 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 { +#endif // INTERLACE + + // 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); + } + +#ifdef INTERLACE + } +#endif // INTERLACE + +} + + +void BImage::vgradient(void) { + float dry, dgy, dby, + yr = (float) from->getRed(), + yg = (float) from->getGreen(), + yb = (float) from->getBlue(); + unsigned char *pr = red, *pg = green, *pb = blue; + + register unsigned int y; + + dry = (float) (to->getRed() - from->getRed()); + dgy = (float) (to->getGreen() - from->getGreen()); + dby = (float) (to->getBlue() - from->getBlue()); + + dry /= height; + dgy /= height; + dby /= height; + +#ifdef INTERLACE + 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 { +#endif // INTERLACE + + // 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; + } + +#ifdef INTERLACE + } +#endif // INTERLACE + +} + + +void BImage::pgradient(void) { + // pyramid gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Openbox 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->getRed(), tg = to->getGreen(), tb = to->getBlue(), + *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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)))); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE +} + + +void BImage::rgradient(void) { + // rectangle gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Openbox 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->getRed(), tg = to->getGreen(), tb = to->getBlue(), + *xt = xtable, *yt = ytable; + + register unsigned int x, y; + + dry = drx = (float) (to->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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)))); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE +} + + +void BImage::egradient(void) { + // elliptic gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Openbox 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->getRed(), + tg = (unsigned long) to->getGreen(), + tb = (unsigned long) to->getBlue(); + + register unsigned int x, y; + + dry = drx = (float) (to->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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)))); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE +} + + +void BImage::pcgradient(void) { + // pipe cross gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Openbox 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->getRed(), + tg = to->getGreen(), + tb = to->getBlue(); + + register unsigned int x, y; + + dry = drx = (float) (to->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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)))); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE +} + + +void BImage::cdgradient(void) { + // cross diagonal gradient - based on original dgradient, written by + // Mosfet (mosfet@kde.org) + // adapted from kde sources for Openbox by Brad Hughes + + float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0, + xr = (float) from->getRed(), + xg = (float) from->getGreen(), + xb = (float) from->getBlue(); + 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->getRed() - from->getRed()); + dgy = dgx = (float) (to->getGreen() - from->getGreen()); + dby = dbx = (float) (to->getBlue() - from->getBlue()); + + // 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 + +#ifdef INTERLACE + if (! interlaced) { +#endif // INTERLACE + + // 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); + } + } + +#ifdef INTERLACE + } 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; + } + } + } + } +#endif // INTERLACE +} + + +BImageControl::BImageControl(BaseDisplay *dpy, ScreenInfo *scrn, Bool _dither, + int _cpc, unsigned long cache_timeout, + unsigned long cmax) +{ + 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(); + + int count; + XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(), + &count); + colormap = screeninfo->getColormap(); + + 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->getMessage(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->getMessage(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; + } + + basedisplay->grab(); + + for (i = 0; i < ncolors; i++) + if (! XAllocColor(basedisplay->getXDisplay(), colormap, &colors[i])) { + fprintf(stderr, i18n->getMessage(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; + + basedisplay->ungrab(); + + 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->getMessage(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->getMessage(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; + + basedisplay->grab(); + 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->getMessage(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; + } + + basedisplay->ungrab(); + + 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->getMessage(ImageSet, ImageUnsupVisual, + "BImageControl::BImageControl: unsupported visual %d\n"), + getVisual()->c_class); + exit(1); + } + + cache = new LinkedList; +} + + +BImageControl::~BImageControl(void) { + if (sqrt_table) { + delete [] sqrt_table; + } + + if (grad_xbuffer) { + delete [] grad_xbuffer; + } + + if (grad_ybuffer) { + delete [] grad_ybuffer; + } + + if (colors) { + unsigned long *pixels = new unsigned long [ncolors]; + + int i; + for (i = 0; i < ncolors; i++) + *(pixels + i) = (*(colors + i)).pixel; + + XFreeColors(basedisplay->getXDisplay(), colormap, pixels, ncolors, 0); + + delete [] colors; + } + + if (cache->count()) { + int i, n = cache->count(); + fprintf(stderr, i18n->getMessage(ImageSet, ImagePixmapRelease, + "BImageContol::~BImageControl: pixmap cache - " + "releasing %d pixmaps\n"), n); + + for (i = 0; i < n; i++) { + Cache *tmp = cache->first(); + XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap); + cache->remove(tmp); + delete tmp; + } + +#ifdef TIMEDCACHE + if (timer) { + timer->stop(); + delete timer; + } +#endif // TIMEDCACHE + } + + delete cache; +} + + +Pixmap BImageControl::searchCache(unsigned int width, unsigned int height, + unsigned long texture, + BColor *c1, BColor *c2) { + if (cache->count()) { + LinkedListIterator it(cache); + + for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) { + if ((tmp->width == width) && (tmp->height == height) && + (tmp->texture == texture) && (tmp->pixel1 == c1->getPixel())) + if (texture & BImage_Gradient) { + if (tmp->pixel2 == c2->getPixel()) { + tmp->count++; + return tmp->pixmap; + } + } else { + tmp->count++; + return tmp->pixmap; + } + } + } + + return None; +} + + +Pixmap BImageControl::renderImage(unsigned int width, unsigned int height, + BTexture *texture) { + if (texture->getTexture() & BImage_ParentRelative) return ParentRelative; + + Pixmap pixmap = searchCache(width, height, texture->getTexture(), + texture->getColor(), texture->getColorTo()); + if (pixmap) return pixmap; + + BImage image(this, width, height); + pixmap = image.render(texture); + + if (pixmap) { + Cache *tmp = new Cache; + + tmp->pixmap = pixmap; + tmp->width = width; + tmp->height = height; + tmp->count = 1; + tmp->texture = texture->getTexture(); + tmp->pixel1 = texture->getColor()->getPixel(); + + if (texture->getTexture() & BImage_Gradient) + tmp->pixel2 = texture->getColorTo()->getPixel(); + else + tmp->pixel2 = 0l; + + cache->insert(tmp); + + if ((unsigned) cache->count() > cache_max) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(ImageSet, ImagePixmapCacheLarge, + "BImageControl::renderImage: cache is large, " + "forcing cleanout\n")); +#endif // DEBUG + + timeout(); + } + + return pixmap; + } + + return None; +} + + +void BImageControl::removeImage(Pixmap pixmap) { + if (pixmap) { + LinkedListIterator it(cache); + for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->pixmap == pixmap) { + if (tmp->count) { + tmp->count--; + +#ifdef TIMEDCACHE + if (! timer) timeout(); +#else // !TIMEDCACHE + if (! tmp->count) timeout(); +#endif // TIMEDCACHE + } + + return; + } + } + } +} + + +unsigned long BImageControl::getColor(const char *colorname, + unsigned char *r, unsigned char *g, + unsigned char *b) +{ + XColor color; + color.pixel = 0; + + if (! XParseColor(basedisplay->getXDisplay(), colormap, colorname, &color)) + fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", + colorname); + else if (! XAllocColor(basedisplay->getXDisplay(), colormap, &color)) + fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n", + colorname); + + if (color.red == 65535) *r = 0xff; + else *r = (unsigned char) (color.red / 0xff); + if (color.green == 65535) *g = 0xff; + else *g = (unsigned char) (color.green / 0xff); + if (color.blue == 65535) *b = 0xff; + else *b = (unsigned char) (color.blue / 0xff); + + return color.pixel; +} + + +unsigned long BImageControl::getColor(const char *colorname) { + XColor color; + color.pixel = 0; + + if (! XParseColor(basedisplay->getXDisplay(), colormap, colorname, &color)) + fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n", + colorname); + else if (! XAllocColor(basedisplay->getXDisplay(), colormap, &color)) + fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n", + colorname); + + return color.pixel; +} + + +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) { + basedisplay->grab(); + + Bool install = True; + int i = 0, ncmap = 0; + Colormap *cmaps = + XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap); + + if (cmaps) { + for (i = 0; i < ncmap; i++) + if (*(cmaps + i) == colormap) + install = False; + + if (install) + XInstallColormap(basedisplay->getXDisplay(), colormap); + + XFree(cmaps); + } + + basedisplay->ungrab(); +} + + +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]; + int i = 0; + + for (; i < (256 * 256 * 2); i++) + *(sqrt_table + i) = bsqrt(i); + } + + return (*(sqrt_table + x)); +} + + +void BImageControl::parseTexture(BTexture *texture, char *t) { + if ((! texture) || (! t)) return; + + int t_len = strlen(t) + 1, i; + char *ts = new char[t_len]; + if (! ts) return; + + // convert to lower case + for (i = 0; i < t_len; i++) + *(ts + i) = tolower(*(t + i)); + + if (strstr(ts, "parentrelative")) { + texture->setTexture(BImage_ParentRelative); + } else { + texture->setTexture(0); + + if (strstr(ts, "solid")) + texture->addTexture(BImage_Solid); + else if (strstr(ts, "gradient")) { + texture->addTexture(BImage_Gradient); + if (strstr(ts, "crossdiagonal")) + texture->addTexture(BImage_CrossDiagonal); + else if (strstr(ts, "rectangle")) + texture->addTexture(BImage_Rectangle); + else if (strstr(ts, "pyramid")) + texture->addTexture(BImage_Pyramid); + else if (strstr(ts, "pipecross")) + texture->addTexture(BImage_PipeCross); + else if (strstr(ts, "elliptic")) + texture->addTexture(BImage_Elliptic); + else if (strstr(ts, "diagonal")) + texture->addTexture(BImage_Diagonal); + else if (strstr(ts, "horizontal")) + texture->addTexture(BImage_Horizontal); + else if (strstr(ts, "vertical")) + texture->addTexture(BImage_Vertical); + else + texture->addTexture(BImage_Diagonal); + } else + texture->addTexture(BImage_Solid); + + if (strstr(ts, "raised")) + texture->addTexture(BImage_Raised); + else if (strstr(ts, "sunken")) + texture->addTexture(BImage_Sunken); + else if (strstr(ts, "flat")) + texture->addTexture(BImage_Flat); + else + texture->addTexture(BImage_Raised); + + if (! (texture->getTexture() & BImage_Flat)) + if (strstr(ts, "bevel2")) + texture->addTexture(BImage_Bevel2); + else + texture->addTexture(BImage_Bevel1); + +#ifdef INTERLACE + if (strstr(ts, "interlaced")) + texture->addTexture(BImage_Interlaced); +#endif // INTERLACE + } + + delete [] ts; +} + + +void BImageControl::parseColor(BColor *color, char *c) { + if (! color) return; + + if (color->isAllocated()) { + unsigned long pixel = color->getPixel(); + + XFreeColors(basedisplay->getXDisplay(), colormap, &pixel, 1, 0); + + color->setPixel(0l); + color->setRGB(0, 0, 0); + color->setAllocated(False); + } + + if (c) { + unsigned char r, g, b; + + color->setPixel(getColor(c, &r, &g, &b)); + color->setRGB(r, g, b); + color->setAllocated(True); + } +} + + +void BImageControl::timeout(void) { + LinkedListIterator it(cache); + for (Cache *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->count <= 0) { + XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap); + cache->remove(tmp); + delete tmp; + } + } +} diff --git a/src/Image.h b/src/Image.h new file mode 100644 index 00000000..249f2672 --- /dev/null +++ b/src/Image.h @@ -0,0 +1,241 @@ +// Image.h for Openbox +// 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 __Image_hh +#define __Image_hh + +#include +#include + +#include "LinkedList.h" +#include "Timer.h" + +class ScreenInfo; +class BImage; +class BImageControl; + + +// bevel options +#define BImage_Flat (1l<<1) +#define BImage_Sunken (1l<<2) +#define BImage_Raised (1l<<3) + +// textures +#define BImage_Solid (1l<<4) +#define BImage_Gradient (1l<<5) + +// gradients +#define BImage_Horizontal (1l<<6) +#define BImage_Vertical (1l<<7) +#define BImage_Diagonal (1l<<8) +#define BImage_CrossDiagonal (1l<<9) +#define BImage_Rectangle (1l<<10) +#define BImage_Pyramid (1l<<11) +#define BImage_PipeCross (1l<<12) +#define BImage_Elliptic (1l<<13) + +// bevel types +#define BImage_Bevel1 (1l<<14) +#define BImage_Bevel2 (1l<<15) + +// inverted image +#define BImage_Invert (1l<<16) + +// parent relative image +#define BImage_ParentRelative (1l<<17) + +#ifdef INTERLACE +// fake interlaced image +# define BImage_Interlaced (1l<<18) +#endif // INTERLACE + +class BColor { +private: + int allocated; + unsigned char red, green, blue; + unsigned long pixel; + +public: + BColor(char r = 0, char g = 0, char b = 0) + { red = r; green = g; blue = b; pixel = 0; allocated = 0; } + + inline const int &isAllocated(void) const { return allocated; } + + inline const unsigned char &getRed(void) const { return red; } + inline const unsigned char &getGreen(void) const { return green; } + inline const unsigned char &getBlue(void) const { return blue; } + + inline const unsigned long &getPixel(void) const { return pixel; } + + inline void setAllocated(int a) { allocated = a; } + inline void setRGB(char r, char g, char b) { red = r; green = g; blue = b; } + inline void setPixel(unsigned long p) { pixel = p; } +}; + + +class BTexture { +private: + BColor color, colorTo, hiColor, loColor; + unsigned long texture; + +public: + BTexture(void) { texture = 0; } + + inline BColor *getColor(void) { return &color; } + inline BColor *getColorTo(void) { return &colorTo; } + inline BColor *getHiColor(void) { return &hiColor; } + inline BColor *getLoColor(void) { return &loColor; } + + inline const unsigned long &getTexture(void) const { return texture; } + + inline void setTexture(unsigned long t) { texture = t; } + inline void addTexture(unsigned long t) { texture |= t; } +}; + + +class BImage { +private: + BImageControl *control; + +#ifdef INTERLACE + Bool interlaced; +#endif // INTERLACE + + 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; + + +protected: + Pixmap renderPixmap(void); + + XImage *renderXImage(void); + + void invert(void); + void bevel1(void); + void bevel2(void); + 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 *, unsigned int, unsigned int); + ~BImage(void); + + Pixmap render(BTexture *); + Pixmap render_solid(BTexture *); + Pixmap render_gradient(BTexture *); +}; + + +class BImageControl : public TimeoutHandler { +private: + Bool dither; + BaseDisplay *basedisplay; + 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 struct Cache { + Pixmap pixmap; + + unsigned int count, width, height; + unsigned long pixel1, pixel2, texture; + } Cache; + + LinkedList *cache; + + +protected: + Pixmap searchCache(unsigned int, unsigned int, unsigned long, BColor *, + BColor *); + + +public: + BImageControl(BaseDisplay *, ScreenInfo *, Bool = False, int = 4, + unsigned long = 300000l, unsigned long = 200l); + virtual ~BImageControl(void); + + inline BaseDisplay *getBaseDisplay(void) { return basedisplay; } + + inline const Bool &doDither(void) { return dither; } + + inline ScreenInfo *getScreenInfo(void) { return screeninfo; } + + inline const Window &getDrawable(void) const { return window; } + + inline Visual *getVisual(void) { return screeninfo->getVisual(); } + + inline const int &getBitsPerPixel(void) const { return bits_per_pixel; } + inline const int &getDepth(void) const { return screen_depth; } + inline const int &getColorsPerChannel(void) const + { return colors_per_channel; } + + unsigned long getColor(const char *); + unsigned long getColor(const char *, unsigned char *, unsigned char *, + unsigned char *); + unsigned long getSqrt(unsigned int); + + Pixmap renderImage(unsigned int, unsigned int, BTexture *); + + void installRootColormap(void); + void removeImage(Pixmap); + void getColorTables(unsigned char **, unsigned char **, unsigned char **, + int *, int *, int *, int *, int *, int *); + void getXColorTable(XColor **, int *); + void getGradientBuffers(unsigned int, unsigned int, + unsigned int **, unsigned int **); + void setDither(Bool d) { dither = d; } + void setColorsPerChannel(int); + void parseTexture(BTexture *, char *); + void parseColor(BColor *, char * = 0); + + virtual void timeout(void); +}; + + +#endif // __Image_hh + diff --git a/src/LinkedList.cc b/src/LinkedList.cc new file mode 100644 index 00000000..8e066965 --- /dev/null +++ b/src/LinkedList.cc @@ -0,0 +1,356 @@ +// LinkedList.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include "LinkedList.h" + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + + +__llist_iterator::__llist_iterator(__llist *l) { + // initialize the iterator... + list = l; + + if (list) { + if (! list->iterators) + list->iterators = new __llist; + + list->iterators->insert(this); + } + + reset(); +} + + +__llist_iterator::~__llist_iterator(void) { + if (list && list->iterators) + list->iterators->remove(this); +} + + +void *__llist_iterator::current(void) { + // return the current node data... if any + return ((node) ? node->getData() : 0); +} + + +void __llist_iterator::reset(void) { + // update the iterator's current node to the first node in the linked list + if (list) + node = list->_first; +} + + +const int __llist_iterator::set(const int index) { + // set the current node to index + if (list) { + if (index < list->elements && index >= 0 && list->_first) { + node = list->_first; + + for (register int i = 0; i < index; i++) + node = node->getNext(); + + return 1; + } + } + + node = (__llist_node *) 0; + return 0; +} + + +void __llist_iterator::operator++(void) { + // iterate to the next node in the list... + node = ((node) ? node->getNext() : 0); +} + + +void __llist_iterator::operator++(int) { + // iterate to the next node in the list... + node = ((node) ? node->getNext() : 0); +} + + +__llist::__llist(void *d) { + // initialize the linked list... + _first = (__llist_node *) 0; + _last = (__llist_node *) 0; + iterators = (__llist *) 0; + elements = 0; + + if (d) insert(d); +} + + +__llist::~__llist(void) { + // remove all the items in the list... + for (register int i = 0; i < elements; i++) + remove(0); + + if (iterators) { + __llist_node *n = iterators->_first; + + while (n) { + __llist_iterator *p = (__llist_iterator *) n->getData(); + p->list = (__llist *) 0; + p->node = (__llist_node *) 0; + + n = n->getNext(); + } + + delete iterators; + } +} + + +const int __llist::insert(void *d, int index) { + // insert item into linked list at specified index... + + __llist_node *nnode = new __llist_node; + if (! nnode) return -1; + + if ((! _first) || (! _last)) { + // list is empty... insert the item as the first item, regardless of the + // index given + _first = nnode; + _first->setData(d); + _first->setNext((__llist_node *) 0); + _last = _first; + } else { + if (index == 0) { + // if index is 0... prepend the data on the list + + nnode->setData(d); + nnode->setNext(_first); + + _first = nnode; + } else if ((index == -1) || (index == elements)) { + // if index is -1... append the data on the list + + nnode->setData(d); + nnode->setNext((__llist_node *) 0); + _last->setNext(nnode); + + _last = nnode; + } else if (index < elements) { + // otherwise... insert the item at the position specified by index + __llist_node *inode = _first; + + for (register int i = 1; i < index; i++) { + if (inode) { + inode = inode->getNext(); + } else { + delete nnode; + return -1; + } + } + + nnode->setData(d); + + if ((! inode) || inode == _last) { + nnode->setNext((__llist_node *) 0); + _last->setNext(nnode); + + _last = nnode; + } else { + nnode->setNext(inode->getNext()); + inode->setNext(nnode); + } + } + } + + return ++elements; +} + + +const int __llist::remove(void *d) { + // remove list item whose data pointer address matches the pointer address + // given + + if ((! _first) || (! _last)) + return -1; + + if (_first->getData() == d) { + // remove the first item in the list... + __llist_node *node = _first; + _first = _first->getNext(); + + if (iterators && iterators->_first) { + __llist_node *n = iterators->_first; + while (n) { + ((__llist_iterator *) n->getData())->reset(); + n = n->getNext(); + } + } + + --elements; + delete node; + return 0; + } else { + // iterate through the list and remove the first occurance of the item + + // NOTE: we don't validate _first in this assignment, because it is checked + // for validity above... + __llist_node *rnode = _first->getNext(), *prev = _first; + + for (register int i = 1; i < elements; i++) { + if (rnode) { + if (rnode->getData() == d) { + // we found the item... update the previous node and delete the + // now useless rnode... + prev->setNext(rnode->getNext()); + + if (rnode == _last) + _last = prev; + + if (iterators && iterators->_first) { + __llist_node *n = iterators->_first; + while (n) { + ((__llist_iterator *) n->getData())->reset(); + n = n->getNext(); + } + } + + --elements; + delete rnode; + return i; + } else { + prev = rnode; + rnode = rnode->getNext(); + } + } + } + + return -1; + } +} + + +void *__llist::remove(const int index) { + if (index >= elements || index < 0 || (! _first) || (! _last)) + return (void *) 0; + + // remove list item at specified index within the list + if (index == 0) { + // remove the first item in the list... + __llist_node *node = _first; + void *data_return = _first->getData(); + + _first = _first->getNext(); + + if (iterators && iterators->_first) { + __llist_node *n = iterators->_first; + while (n) { + ((__llist_iterator *) n->getData())->reset(); + n = n->getNext(); + } + } + + --elements; + delete node; + + return data_return; + } else { + __llist_node *rnode = _first->getNext(), *prev = _first; + void *data_return = (void *) 0; + + for (register int i = 1; i < index; i++) { + if (rnode) { + prev = rnode; + rnode = rnode->getNext(); + } else { + return (void *) 0; + } + } + + if (! rnode) return (void *) 0; + + prev->setNext(rnode->getNext()); + data_return = rnode->getData(); + + if (rnode == _last) + _last = prev; + + if (iterators && iterators->_first) { + __llist_node *n = iterators->_first; + while (n) { + ((__llist_iterator *) n->getData())->reset(); + n = n->getNext(); + } + } + + --elements; + data_return = rnode->getData(); + delete rnode; + return data_return; + } + + return (void *) 0; +} + + +void *__llist::find(const int index) { + if (index >= elements || index < 0 || (! _first) || (! _last)) + return (void *) 0; + + if (index == 0) // return the first item + return first(); + if (index == (elements - 1)) // return the last item + return last(); + + __llist_node *fnode = _first->getNext(); + + for (register int i = 1; i < index; i++) { + if (fnode) + fnode = fnode->getNext(); + else + return (void *) 0; + } + + return fnode->getData(); +} + + +void *__llist::first(void) { + if (_first) + return _first->getData(); + + return (void *) 0; +} + + +void *__llist::last(void) { + if (_last) + return _last->getData(); + + return (void *) 0; +} diff --git a/src/LinkedList.h b/src/LinkedList.h new file mode 100644 index 00000000..ba546163 --- /dev/null +++ b/src/LinkedList.h @@ -0,0 +1,130 @@ +// LinkedList.h for Openbox +// 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 __LinkedList_hh +#define __LinkedList_hh + + +class __llist_node { +private: + __llist_node *next; + void *data; + +protected: + +public: + __llist_node(void) { next = (__llist_node *) 0; data = (void *) 0; } + + inline __llist_node *getNext(void) { return next; } + + inline void *getData(void) { return data; } + inline void setData(void *d) { data = d; } + inline void setNext(__llist_node *n) { next = n; } +}; + + +// forward declaration +class __llist; + + +class __llist_iterator { +private: + __llist *list; + __llist_node *node; + + friend class __llist; + + +protected: + __llist_iterator(__llist *); + ~__llist_iterator(void); + + const int set(const int); + + void *current(void); + void reset(void); + + void operator++(void); + void operator++(int); +}; + + +class __llist { +private: + int elements; + __llist_node *_first, *_last; + __llist *iterators; + + friend class __llist_iterator; + + +protected: + __llist(void * = 0); + ~__llist(void); + + inline const int &count(void) const { return elements; } + inline const int empty(void) const { return (elements == 0); } + + const int insert(void *, int = -1); + const int remove(void *); + + void *find(const int); + void *remove(const int); + void *first(void); + void *last(void); +}; + + +template +class LinkedListIterator : public __llist_iterator { +public: + LinkedListIterator(__llist *d = 0) : __llist_iterator(d) { return; } + + inline Z *current(void) { return (Z *) __llist_iterator::current(); } + + inline const int set(const int i) { return __llist_iterator::set(i); } + + inline void reset(void) { __llist_iterator::reset(); } + + inline void operator++(void) { __llist_iterator::operator++(); } + inline void operator++(int) { __llist_iterator::operator++(0); } +}; + + +template +class LinkedList : public __llist { +public: + LinkedList(Z *d = 0) : __llist(d) { return; } + + inline Z *find(const int i) { return (Z *) __llist::find(i); } + inline Z *remove(const int i) { return (Z *) __llist::remove(i); } + inline Z *first(void) { return (Z *) __llist::first(); } + inline Z *last(void) { return (Z *) __llist::last(); } + + inline const int count(void) const { return __llist::count(); } + inline const int empty(void) const { return __llist::empty(); } + + inline const int insert(Z *d, int i = -1) { return __llist::insert((void *) d, i); } + inline const int remove(Z *d) { return __llist::remove((void *) d); } +}; + + +#endif // __LinkedList_hh diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..f5b0b09e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,108 @@ +# src/Makefile.am for Openbox +# 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. + +DEFAULT_MENU=$(pkgdatadir)/menu +DEFAULT_STYLE=$(pkgdatadir)/styles/steelblue + +CPPFLAGS= @CPPFLAGS@ @SHAPE@ @SLIT@ @INTERLACE@ @ORDEREDPSEUDO@ \ +@DEBUG@ @NEWWMSPEC@ @NLS@ @TIMEDCACHE@ @CLOBBER@ \ +-DLOCALEPATH=\"$(pkgdatadir)/nls\" \ +-DDEFAULTMENU=\"$(DEFAULT_MENU)\" \ +-DDEFAULTSTYLE=\"$(DEFAULT_STYLE)\" + +bin_PROGRAMS= openbox + +openbox_SOURCES= BaseDisplay.cc Basemenu.cc Clientmenu.cc Configmenu.cc Iconmenu.cc Image.cc LinkedList.cc Netizen.cc Rootmenu.cc Screen.cc Slit.cc Timer.cc Toolbar.cc Window.cc Windowmenu.cc Workspace.cc Workspacemenu.cc openbox.cc bsd-snprintf.c i18n.cc main.cc + +MAINTAINERCLEANFILES= Makefile.in + +distclean-local: + rm -f *\~ *.orig *.rej + +# local dependencies + +BaseDisplay.o: BaseDisplay.cc i18n.h BaseDisplay.h LinkedList.h \ + Timer.h +Basemenu.o: Basemenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h +Clientmenu.o: Clientmenu.cc openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Clientmenu.h Workspace.h Screen.h Configmenu.h Netizen.h \ + Rootmenu.h Workspacemenu.h +Configmenu.o: Configmenu.cc i18n.h Configmenu.h Basemenu.h \ + LinkedList.h Screen.h BaseDisplay.h Timer.h Iconmenu.h Netizen.h \ + Rootmenu.h Workspace.h Workspacemenu.h openbox.h Image.h \ + Window.h Windowmenu.h Slit.h Toolbar.h +Icon.o: Iconmenu.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Image.o: Image.cc i18n.h BaseDisplay.h LinkedList.h Timer.h \ + Image.h +LinkedList.o: LinkedList.cc LinkedList.h +Netizen.o: Netizen.cc Netizen.h BaseDisplay.h LinkedList.h Timer.h \ + Screen.h Configmenu.h Basemenu.h openbox.h Image.h Window.h \ + Iconmenu.h Windowmenu.h Slit.h Rootmenu.h Workspace.h \ + Workspacemenu.h +Rootmenu.o: Rootmenu.cc openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Rootmenu.h Screen.h Configmenu.h Netizen.h Workspace.h \ + Workspacemenu.h +Screen.o: Screen.cc i18n.h bsd-snprintf.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Screen.h Configmenu.h \ + Netizen.h Rootmenu.h Workspacemenu.h Toolbar.h +Slit.o: Slit.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Timer.o: Timer.cc BaseDisplay.h LinkedList.h Timer.h +Toolbar.o: Toolbar.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Clientmenu.h Workspace.h Rootmenu.h Screen.h Configmenu.h \ + Netizen.h Workspacemenu.h Toolbar.h +Window.o: Window.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Windowmenu.o: Windowmenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h +Workspace.o: Workspace.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Screen.h \ + Configmenu.h Netizen.h Rootmenu.h Workspacemenu.h Toolbar.h +Workspacemenu.o: Workspacemenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h Toolbar.h +openbox.o: openbox.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Rootmenu.h \ + Screen.h Configmenu.h Netizen.h Workspacemenu.h Toolbar.h +bsd-snprintf.o: bsd-snprintf.c bsd-snprintf.h +i18n.o: i18n.cc i18n.h +main.o: main.cc ../version.h i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 00000000..7b8d140b --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,462 @@ +# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# src/Makefile.am for Openbox +# 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. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +CLOBBER = @CLOBBER@ +CXX = @CXX@ +DEBUG = @DEBUG@ +INTERLACE = @INTERLACE@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +NEWWMSPEC = @NEWWMSPEC@ +NLS = @NLS@ +ORDEREDPSEUDO = @ORDEREDPSEUDO@ +PACKAGE = @PACKAGE@ +SHAPE = @SHAPE@ +SLIT = @SLIT@ +TIMEDCACHE = @TIMEDCACHE@ +VERSION = @VERSION@ +gencat_cmd = @gencat_cmd@ +regex_cmd = @regex_cmd@ + +DEFAULT_MENU = $(pkgdatadir)/menu +DEFAULT_STYLE = $(pkgdatadir)/styles/steelblue + +CPPFLAGS = @CPPFLAGS@ @SHAPE@ @SLIT@ @INTERLACE@ @ORDEREDPSEUDO@ @DEBUG@ @NEWWMSPEC@ @NLS@ @TIMEDCACHE@ @CLOBBER@ -DLOCALEPATH=\"$(pkgdatadir)/nls\" -DDEFAULTMENU=\"$(DEFAULT_MENU)\" -DDEFAULTSTYLE=\"$(DEFAULT_STYLE)\" + + +bin_PROGRAMS = openbox + +openbox_SOURCES = BaseDisplay.cc Basemenu.cc Clientmenu.cc Configmenu.cc Iconmenu.cc Image.cc LinkedList.cc Netizen.cc Rootmenu.cc Screen.cc Slit.cc Timer.cc Toolbar.cc Window.cc Windowmenu.cc Workspace.cc Workspacemenu.cc openbox.cc bsd-snprintf.c i18n.cc main.cc + +MAINTAINERCLEANFILES = Makefile.in +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +openbox_OBJECTS = BaseDisplay.o Basemenu.o Clientmenu.o Configmenu.o \ +Iconmenu.o Image.o LinkedList.o Netizen.o Rootmenu.o Screen.o Slit.o \ +Timer.o Toolbar.o Window.o Windowmenu.o Workspace.o Workspacemenu.o \ +openbox.o bsd-snprintf.o i18n.o main.o +openbox_LDADD = $(LDADD) +openbox_DEPENDENCIES = +openbox_LDFLAGS = +CXXFLAGS = @CXXFLAGS@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +DEP_FILES = .deps/BaseDisplay.P .deps/Basemenu.P .deps/Clientmenu.P \ +.deps/Configmenu.P .deps/Iconmenu.P .deps/Image.P .deps/LinkedList.P \ +.deps/Netizen.P .deps/Rootmenu.P .deps/Screen.P .deps/Slit.P \ +.deps/Timer.P .deps/Toolbar.P .deps/Window.P .deps/Windowmenu.P \ +.deps/Workspace.P .deps/Workspacemenu.P .deps/bsd-snprintf.P \ +.deps/i18n.P .deps/main.P .deps/openbox.P +SOURCES = $(openbox_SOURCES) +OBJECTS = $(openbox_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .cc .o .s +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +openbox: $(openbox_OBJECTS) $(openbox_DEPENDENCIES) + @rm -f openbox + $(CXXLINK) $(openbox_LDFLAGS) $(openbox_OBJECTS) $(openbox_LDADD) $(LIBS) +.cc.o: + $(CXXCOMPILE) -c $< + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp + +%.o: %.cc + @echo '$(CXXCOMPILE) -c $<'; \ + $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.cc + @echo '$(LTCXXCOMPILE) -c $<'; \ + $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-depend distclean-generic clean-am \ + distclean-local + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +distclean-local: + rm -f *\~ *.orig *.rej + +# local dependencies + +BaseDisplay.o: BaseDisplay.cc i18n.h BaseDisplay.h LinkedList.h \ + Timer.h +Basemenu.o: Basemenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h +Clientmenu.o: Clientmenu.cc openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Clientmenu.h Workspace.h Screen.h Configmenu.h Netizen.h \ + Rootmenu.h Workspacemenu.h +Configmenu.o: Configmenu.cc i18n.h Configmenu.h Basemenu.h \ + LinkedList.h Screen.h BaseDisplay.h Timer.h Iconmenu.h Netizen.h \ + Rootmenu.h Workspace.h Workspacemenu.h openbox.h Image.h \ + Window.h Windowmenu.h Slit.h Toolbar.h +Icon.o: Iconmenu.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Image.o: Image.cc i18n.h BaseDisplay.h LinkedList.h Timer.h \ + Image.h +LinkedList.o: LinkedList.cc LinkedList.h +Netizen.o: Netizen.cc Netizen.h BaseDisplay.h LinkedList.h Timer.h \ + Screen.h Configmenu.h Basemenu.h openbox.h Image.h Window.h \ + Iconmenu.h Windowmenu.h Slit.h Rootmenu.h Workspace.h \ + Workspacemenu.h +Rootmenu.o: Rootmenu.cc openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Rootmenu.h Screen.h Configmenu.h Netizen.h Workspace.h \ + Workspacemenu.h +Screen.o: Screen.cc i18n.h bsd-snprintf.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Screen.h Configmenu.h \ + Netizen.h Rootmenu.h Workspacemenu.h Toolbar.h +Slit.o: Slit.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Timer.o: Timer.cc BaseDisplay.h LinkedList.h Timer.h +Toolbar.o: Toolbar.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Clientmenu.h Workspace.h Rootmenu.h Screen.h Configmenu.h \ + Netizen.h Workspacemenu.h Toolbar.h +Window.o: Window.cc i18n.h openbox.h BaseDisplay.h LinkedList.h \ + Timer.h Image.h Window.h Iconmenu.h Basemenu.h Windowmenu.h Slit.h \ + Screen.h Configmenu.h Netizen.h Rootmenu.h Workspace.h \ + Workspacemenu.h Toolbar.h +Windowmenu.o: Windowmenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h +Workspace.o: Workspace.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Screen.h \ + Configmenu.h Netizen.h Rootmenu.h Workspacemenu.h Toolbar.h +Workspacemenu.o: Workspacemenu.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Screen.h Configmenu.h Netizen.h Rootmenu.h \ + Workspace.h Workspacemenu.h Toolbar.h +openbox.o: openbox.cc i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h Clientmenu.h Workspace.h Rootmenu.h \ + Screen.h Configmenu.h Netizen.h Workspacemenu.h Toolbar.h +bsd-snprintf.o: bsd-snprintf.c bsd-snprintf.h +i18n.o: i18n.cc i18n.h +main.o: main.cc ../version.h i18n.h openbox.h BaseDisplay.h \ + LinkedList.h Timer.h Image.h Window.h Iconmenu.h Basemenu.h \ + Windowmenu.h Slit.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/Netizen.cc b/src/Netizen.cc new file mode 100644 index 00000000..22d47958 --- /dev/null +++ b/src/Netizen.cc @@ -0,0 +1,116 @@ +// Netizen.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif // HAVE_CONFIG_H + +#include "Netizen.h" +#include "Screen.h" + +Netizen::Netizen(BScreen *scr, Window win) { + screen = scr; + basedisplay = screen->getBaseDisplay(); + window = win; + + event.type = ClientMessage; + event.xclient.message_type = basedisplay->getOpenboxStructureMessagesAtom(); + event.xclient.display = basedisplay->getXDisplay(); + event.xclient.window = window; + event.xclient.format = 32; + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyStartupAtom(); + event.xclient.data.l[1] = event.xclient.data.l[2] = + event.xclient.data.l[3] = event.xclient.data.l[4] = 0l; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendWorkspaceCount(void) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWorkspaceCountAtom(); + event.xclient.data.l[1] = screen->getCount(); + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendCurrentWorkspace(void) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyCurrentWorkspaceAtom(); + event.xclient.data.l[1] = screen->getCurrentWorkspaceID(); + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendWindowFocus(Window w) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWindowFocusAtom(); + event.xclient.data.l[1] = w; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendWindowAdd(Window w, unsigned long p) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWindowAddAtom(); + event.xclient.data.l[1] = w; + event.xclient.data.l[2] = p; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); + + event.xclient.data.l[2] = 0l; +} + + +void Netizen::sendWindowDel(Window w) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWindowDelAtom(); + event.xclient.data.l[1] = w; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendWindowRaise(Window w) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWindowRaiseAtom(); + event.xclient.data.l[1] = w; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendWindowLower(Window w) { + event.xclient.data.l[0] = basedisplay->getOpenboxNotifyWindowLowerAtom(); + event.xclient.data.l[1] = w; + + XSendEvent(basedisplay->getXDisplay(), window, False, NoEventMask, &event); +} + + +void Netizen::sendConfigNotify(XEvent *e) { + XSendEvent(basedisplay->getXDisplay(), window, False, + StructureNotifyMask, e); +} diff --git a/src/Netizen.h b/src/Netizen.h new file mode 100644 index 00000000..85480f7b --- /dev/null +++ b/src/Netizen.h @@ -0,0 +1,60 @@ +// Netizen.h for Openbox +// 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 + +#include + +// forward declaration +class BaseDisplay; +class BScreen; +class Netizen; + +class Netizen { +private: + BaseDisplay *basedisplay; + BScreen *screen; + Window window; + XEvent event; + +protected: + +public: + Netizen(BScreen *, Window); + + inline const 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/Rootmenu.cc b/src/Rootmenu.cc new file mode 100644 index 00000000..ddb29855 --- /dev/null +++ b/src/Rootmenu.cc @@ -0,0 +1,113 @@ +// Rootmenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "openbox.h" +#include "Rootmenu.h" +#include "Screen.h" + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_SYS_PARAM_H +# include +#endif // HAVE_SYS_PARAM_H + +#ifndef MAXPATHLEN +#define MAXPATHLEN 255 +#endif // MAXPATHLEN + + +Rootmenu::Rootmenu(BScreen *scrn) : Basemenu(scrn) { + screen = scrn; + openbox = screen->getOpenbox(); +} + + +void Rootmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + + if (!item->function()) + return; + + switch (item->function()) { + case BScreen::Execute: + if (item->exec()) { +#ifndef __EMX__ + char displaystring[MAXPATHLEN]; + sprintf(displaystring, "DISPLAY=%s", + DisplayString(screen->getBaseDisplay()->getXDisplay())); + sprintf(displaystring + strlen(displaystring) - 1, "%d", + screen->getScreenNumber()); + + bexec(item->exec(), displaystring); +#else // __EMX__ + spawnlp(P_NOWAIT, "cmd.exe", "cmd.exe", "/c", item->exec(), NULL); +#endif // !__EMX__ + } + break; + + case BScreen::Restart: + openbox->restart(); + break; + + case BScreen::RestartOther: + if (item->exec()) + openbox->restart(item->exec()); + break; + + case BScreen::Exit: + openbox->shutdown(); + break; + + case BScreen::SetStyle: + if (item->exec()) + openbox->saveStyleFilename(item->exec()); + + case BScreen::Reconfigure: + openbox->reconfigure(); + return; + } + + if (! (screen->getRootmenu()->isTorn() || isTorn()) && + item->function() != BScreen::Reconfigure && + item->function() != BScreen::SetStyle) + hide(); +} diff --git a/src/Rootmenu.h b/src/Rootmenu.h new file mode 100644 index 00000000..076819f1 --- /dev/null +++ b/src/Rootmenu.h @@ -0,0 +1,51 @@ +// Rootmenu.h for Openbox +// 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 __Rootmenu_hh +#define __Rootmenu_hh + +// forward declarations +class Rootmenu; + +class Openbox; +class BScreen; + +#include "Basemenu.h" + + +class Rootmenu : public Basemenu { +private: + Openbox *openbox; + BScreen *screen; + + +protected: + virtual void itemSelected(int, int); + + +public: + Rootmenu(BScreen *); +}; + + +#endif // __Rootmenu_hh + diff --git a/src/Screen.cc b/src/Screen.cc new file mode 100644 index 00000000..13c69bfa --- /dev/null +++ b/src/Screen.cc @@ -0,0 +1,2281 @@ +// Screen.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include + +#include "i18n.h" +#include "openbox.h" +#include "Clientmenu.h" +#include "Iconmenu.h" +#include "Image.h" +#include "Screen.h" + +#ifdef SLIT +#include "Slit.h" +#endif // SLIT + +#include "Rootmenu.h" +#include "Toolbar.h" +#include "Window.h" +#include "Workspace.h" +#include "Workspacemenu.h" + +#ifdef STDC_HEADERS +# include +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_CTYPE_H +# include +#endif // HAVE_CTYPE_H + +#ifdef HAVE_DIRENT_H +# include +#endif // HAVE_DIRENT_H + +#ifdef HAVE_LOCALE_H +# include +#endif // HAVE_LOCALE_H + +#ifdef HAVE_UNISTD_H +# include +# include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_SYS_STAT_H +# include +#endif // HAVE_SYS_STAT_H + +#ifdef HAVE_STDARG_H +# include +#endif // HAVE_STDARG_H + +#ifndef HAVE_SNPRINTF +# include "bsd-snprintf.h" +#endif // !HAVE_SNPRINTF + +#ifndef MAXPATHLEN +#define MAXPATHLEN 255 +#endif // MAXPATHLEN + +#ifndef FONT_ELEMENT_SIZE +#define FONT_ELEMENT_SIZE 50 +#endif // FONT_ELEMENT_SIZE + +#include + +static Bool running = True; + +static int anotherWMRunning(Display *display, XErrorEvent *) { + fprintf(stderr, i18n->getMessage(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); +} + +struct dcmp { + bool operator()(const char *one, const char *two) const { + return (strcmp(one, two) < 0) ? True : False; + } +}; + +#ifndef HAVE_STRCASESTR +static const char * strcasestr(const char *str, const char *ptn) { + const char *s2, *p2; + for( ; *str; str++) { + for(s2=str,p2=ptn; ; s2++,p2++) { + if (!*p2) return str; + if (toupper(*s2) != toupper(*p2)) break; + } + } + return NULL; +} +#endif // HAVE_STRCASESTR + +static const char *getFontElement(const char *pattern, char *buf, int bufsiz, ...) { + const char *p, *v; + char *p2; + va_list va; + + va_start(va, bufsiz); + buf[bufsiz-1] = 0; + buf[bufsiz-2] = '*'; + while((v = va_arg(va, char *)) != NULL) { + p = strcasestr(pattern, v); + if (p) { + strncpy(buf, p+1, bufsiz-2); + p2 = strchr(buf, '-'); + if (p2) *p2=0; + va_end(va); + return p; + } + } + va_end(va); + strncpy(buf, "*", bufsiz); + return NULL; +} + +static const char *getFontSize(const char *pattern, int *size) { + const char *p; + const char *p2=NULL; + int n=0; + + for (p=pattern; 1; p++) { + if (!*p) { + if (p2!=NULL && n>1 && n<72) { + *size = n; return p2+1; + } else { + *size = 16; return NULL; + } + } else if (*p=='-') { + if (n>1 && n<72 && p2!=NULL) { + *size = n; + return p2+1; + } + p2=p; n=0; + } else if (*p>='0' && *p<='9' && p2!=NULL) { + n *= 10; + n += *p-'0'; + } else { + p2=NULL; n=0; + } + } +} + + +BScreen::BScreen(Openbox *bb, int scrn) : ScreenInfo(bb, scrn) { + openbox = bb; + + event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask | + SubstructureRedirectMask | KeyPressMask | KeyReleaseMask | + 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->getMessage(ScreenSet, ScreenManagingScreen, + "BScreen::BScreen: managing screen %d " + "using visual 0x%lx, depth %d\n"), + getScreenNumber(), XVisualIDFromVisual(getVisual()), + getDepth()); + + rootmenu = 0; + resource.stylerc = 0; + + resource.mstyle.t_fontset = resource.mstyle.f_fontset = + resource.tstyle.fontset = resource.wstyle.fontset = (XFontSet) 0; + resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font = + resource.wstyle.font = (XFontStruct *) 0; + resource.root_command = NULL; + +#ifdef HAVE_STRFTIME + resource.strftime_format = 0; +#endif // HAVE_STRFTIME + +#ifdef HAVE_GETPID + pid_t bpid = getpid(); + + XChangeProperty(getBaseDisplay()->getXDisplay(), getRootWindow(), + openbox->getOpenboxPidAtom(), XA_CARDINAL, + sizeof(pid_t) * 8, PropModeReplace, + (unsigned char *) &bpid, 1); +#endif // HAVE_GETPID + + XDefineCursor(getBaseDisplay()->getXDisplay(), getRootWindow(), + openbox->getSessionCursor()); + + workspaceNames = new LinkedList; + workspacesList = new LinkedList; + rootmenuList = new LinkedList; + netizenList = new LinkedList; + iconList = new LinkedList; + + image_control = + new BImageControl(openbox, this, True, openbox->getColorsPerChannel(), + openbox->getCacheLife(), openbox->getCacheMax()); + image_control->installRootColormap(); + root_colormap_installed = True; + + openbox->load_rc(this); + + image_control->setDither(resource.image_dither); + + LoadStyle(); + + XGCValues gcv; + unsigned long gc_value_mask = GCForeground; + if (! i18n->multibyte()) gc_value_mask |= GCFont; + + gcv.foreground = WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber()) + ^ BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber()); + gcv.function = GXxor; + gcv.subwindow_mode = IncludeInferiors; + opGC = XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + GCForeground | GCFunction | GCSubwindowMode, &gcv); + + gcv.foreground = resource.wstyle.l_text_focus.getPixel(); + if (resource.wstyle.font) + gcv.font = resource.wstyle.font->fid; + resource.wstyle.l_text_focus_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.wstyle.l_text_unfocus.getPixel(); + if (resource.wstyle.font) + gcv.font = resource.wstyle.font->fid; + resource.wstyle.l_text_unfocus_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.wstyle.b_pic_focus.getPixel(); + resource.wstyle.b_pic_focus_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + GCForeground, &gcv); + + gcv.foreground = resource.wstyle.b_pic_unfocus.getPixel(); + resource.wstyle.b_pic_unfocus_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + GCForeground, &gcv); + + gcv.foreground = resource.mstyle.t_text.getPixel(); + if (resource.mstyle.t_font) + gcv.font = resource.mstyle.t_font->fid; + resource.mstyle.t_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.f_text.getPixel(); + if (resource.mstyle.f_font) + gcv.font = resource.mstyle.f_font->fid; + resource.mstyle.f_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.h_text.getPixel(); + resource.mstyle.h_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.d_text.getPixel(); + resource.mstyle.d_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.hilite.getColor()->getPixel(); + resource.mstyle.hilite_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.l_text.getPixel(); + if (resource.tstyle.font) + gcv.font = resource.tstyle.font->fid; + resource.tstyle.l_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.w_text.getPixel(); + resource.tstyle.w_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.c_text.getPixel(); + resource.tstyle.c_text_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.b_pic.getPixel(); + resource.tstyle.b_pic_gc = + XCreateGC(getBaseDisplay()->getXDisplay(), getRootWindow(), + gc_value_mask, &gcv); + + const char *s = i18n->getMessage(ScreenSet, ScreenPositionLength, + "0: 0000 x 0: 0000"); + int l = strlen(s); + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical); + geom_w = logical.width; + + geom_h = resource.wstyle.fontset_extents->max_ink_extent.height; + } else { + geom_h = resource.wstyle.font->ascent + + resource.wstyle.font->descent; + + geom_w = XTextWidth(resource.wstyle.font, s, l); + } + + geom_w += (resource.bevel_width * 2); + geom_h += (resource.bevel_width * 2); + + XSetWindowAttributes attrib; + unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder; + attrib.border_pixel = getBorderColor()->getPixel(); + attrib.colormap = getColormap(); + attrib.save_under = True; + + geom_window = + XCreateWindow(getBaseDisplay()->getXDisplay(), getRootWindow(), + 0, 0, geom_w, geom_h, resource.border_width, getDepth(), + InputOutput, getVisual(), mask, &attrib); + geom_visible = False; + + if (resource.wstyle.l_focus.getTexture() & BImage_ParentRelative) { + if (resource.wstyle.t_focus.getTexture() == + (BImage_Flat | BImage_Solid)) { + geom_pixmap = None; + XSetWindowBackground(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.t_focus.getColor()->getPixel()); + } else { + geom_pixmap = image_control->renderImage(geom_w, geom_h, + &resource.wstyle.t_focus); + XSetWindowBackgroundPixmap(getBaseDisplay()->getXDisplay(), + geom_window, geom_pixmap); + } + } else { + if (resource.wstyle.l_focus.getTexture() == + (BImage_Flat | BImage_Solid)) { + geom_pixmap = None; + XSetWindowBackground(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.l_focus.getColor()->getPixel()); + } else { + geom_pixmap = image_control->renderImage(geom_w, geom_h, + &resource.wstyle.l_focus); + XSetWindowBackgroundPixmap(getBaseDisplay()->getXDisplay(), + geom_window, geom_pixmap); + } + } + + workspacemenu = new Workspacemenu(this); + iconmenu = new Iconmenu(this); + configmenu = new Configmenu(this); + + Workspace *wkspc = (Workspace *) 0; + if (resource.workspaces != 0) { + for (int i = 0; i < resource.workspaces; ++i) { + wkspc = new Workspace(this, workspacesList->count()); + workspacesList->insert(wkspc); + workspacemenu->insert(wkspc->getName(), wkspc->getMenu()); + } + } else { + wkspc = new Workspace(this, workspacesList->count()); + workspacesList->insert(wkspc); + workspacemenu->insert(wkspc->getName(), wkspc->getMenu()); + } + + workspacemenu->insert(i18n->getMessage(IconSet, IconIcons, "Icons"), + iconmenu); + workspacemenu->update(); + + current_workspace = workspacesList->first(); + workspacemenu->setItemSelected(2, True); + + toolbar = new Toolbar(this); + +#ifdef SLIT + slit = new Slit(this); +#endif // SLIT + + InitMenu(); + + raiseWindows(0, 0); + rootmenu->update(); + + changeWorkspaceID(0); + + int i; + unsigned int nchild; + Window r, p, *children; + XQueryTree(getBaseDisplay()->getXDisplay(), getRootWindow(), &r, &p, + &children, &nchild); + + // preen the window list of all icon windows... for better dockapp support + for (i = 0; i < (int) nchild; i++) { + if (children[i] == None) continue; + + XWMHints *wmhints = XGetWMHints(getBaseDisplay()->getXDisplay(), + children[i]); + + if (wmhints) { + if ((wmhints->flags & IconWindowHint) && + (wmhints->icon_window != children[i])) + for (int j = 0; j < (int) nchild; j++) + if (children[j] == wmhints->icon_window) { + children[j] = None; + + break; + } + + XFree(wmhints); + } + } + + // manage shown windows + for (i = 0; i < (int) nchild; ++i) { + if (children[i] == None || (! openbox->validateWindow(children[i]))) + continue; + + XWindowAttributes attrib; + if (XGetWindowAttributes(getBaseDisplay()->getXDisplay(), children[i], + &attrib)) { + if (attrib.override_redirect) continue; + + if (attrib.map_state != IsUnmapped) { + new OpenboxWindow(openbox, children[i], this); + + OpenboxWindow *win = openbox->searchWindow(children[i]); + if (win) { + XMapRequestEvent mre; + mre.window = children[i]; + win->restoreAttributes(); + win->mapRequestEvent(&mre); + } + } + } + } + + if (! resource.sloppy_focus) + XSetInputFocus(getBaseDisplay()->getXDisplay(), toolbar->getWindowID(), + RevertToParent, CurrentTime); + + XFree(children); + XFlush(getBaseDisplay()->getXDisplay()); +} + + +BScreen::~BScreen(void) { + if (! managed) return; + + if (geom_pixmap != None) + image_control->removeImage(geom_pixmap); + + if (geom_window != None) + XDestroyWindow(getBaseDisplay()->getXDisplay(), geom_window); + + removeWorkspaceNames(); + + while (workspacesList->count()) + delete workspacesList->remove(0); + + while (rootmenuList->count()) + rootmenuList->remove(0); + + while (iconList->count()) + delete iconList->remove(0); + + while (netizenList->count()) + delete netizenList->remove(0); + +#ifdef HAVE_STRFTIME + if (resource.strftime_format) + delete [] resource.strftime_format; +#endif // HAVE_STRFTIME + + delete rootmenu; + delete workspacemenu; + delete iconmenu; + delete configmenu; + +#ifdef SLIT + delete slit; +#endif // SLIT + + delete toolbar; + delete image_control; + + delete workspacesList; + delete workspaceNames; + delete rootmenuList; + delete iconList; + delete netizenList; + + if (resource.wstyle.fontset) + XFreeFontSet(getBaseDisplay()->getXDisplay(), resource.wstyle.fontset); + if (resource.mstyle.t_fontset) + XFreeFontSet(getBaseDisplay()->getXDisplay(), resource.mstyle.t_fontset); + if (resource.mstyle.f_fontset) + XFreeFontSet(getBaseDisplay()->getXDisplay(), resource.mstyle.f_fontset); + if (resource.tstyle.fontset) + XFreeFontSet(getBaseDisplay()->getXDisplay(), resource.tstyle.fontset); + + if (resource.wstyle.font) + XFreeFont(getBaseDisplay()->getXDisplay(), resource.wstyle.font); + if (resource.mstyle.t_font) + XFreeFont(getBaseDisplay()->getXDisplay(), resource.mstyle.t_font); + if (resource.mstyle.f_font) + XFreeFont(getBaseDisplay()->getXDisplay(), resource.mstyle.f_font); + if (resource.tstyle.font) + XFreeFont(getBaseDisplay()->getXDisplay(), resource.tstyle.font); + if (resource.root_command != NULL) + delete [] resource.root_command; + + XFreeGC(getBaseDisplay()->getXDisplay(), opGC); + + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.wstyle.l_text_focus_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.wstyle.l_text_unfocus_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.wstyle.b_pic_focus_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.wstyle.b_pic_unfocus_gc); + + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.mstyle.t_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.mstyle.f_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.mstyle.h_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.mstyle.d_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.mstyle.hilite_gc); + + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.tstyle.l_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.tstyle.w_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.tstyle.c_text_gc); + XFreeGC(getBaseDisplay()->getXDisplay(), + resource.tstyle.b_pic_gc); +} + +void BScreen::readDatabaseTexture(char *rname, char *rclass, + BTexture *texture, + unsigned long default_pixel) +{ + XrmValue value; + char *value_type; + + if (XrmGetResource(resource.stylerc, rname, rclass, &value_type, + &value)) + image_control->parseTexture(texture, value.addr); + else + texture->setTexture(BImage_Solid | BImage_Flat); + + if (texture->getTexture() & BImage_Solid) { + int clen = strlen(rclass) + 32, nlen = strlen(rname) + 32; + + char *colorclass = new char[clen], *colorname = new char[nlen]; + + sprintf(colorclass, "%s.Color", rclass); + sprintf(colorname, "%s.color", rname); + + readDatabaseColor(colorname, colorclass, texture->getColor(), + default_pixel); + +#ifdef INTERLACE + sprintf(colorclass, "%s.ColorTo", rclass); + sprintf(colorname, "%s.colorTo", rname); + + readDatabaseColor(colorname, colorclass, texture->getColorTo(), + default_pixel); +#endif // INTERLACE + + delete [] colorclass; + delete [] colorname; + + if ((! texture->getColor()->isAllocated()) || + (texture->getTexture() & BImage_Flat)) + return; + + XColor xcol; + + xcol.red = (unsigned int) (texture->getColor()->getRed() + + (texture->getColor()->getRed() >> 1)); + if (xcol.red >= 0xff) xcol.red = 0xffff; + else xcol.red *= 0xff; + xcol.green = (unsigned int) (texture->getColor()->getGreen() + + (texture->getColor()->getGreen() >> 1)); + if (xcol.green >= 0xff) xcol.green = 0xffff; + else xcol.green *= 0xff; + xcol.blue = (unsigned int) (texture->getColor()->getBlue() + + (texture->getColor()->getBlue() >> 1)); + if (xcol.blue >= 0xff) xcol.blue = 0xffff; + else xcol.blue *= 0xff; + + if (! XAllocColor(getBaseDisplay()->getXDisplay(), + getColormap(), &xcol)) + xcol.pixel = 0; + + texture->getHiColor()->setPixel(xcol.pixel); + + xcol.red = + (unsigned int) ((texture->getColor()->getRed() >> 2) + + (texture->getColor()->getRed() >> 1)) * 0xff; + xcol.green = + (unsigned int) ((texture->getColor()->getGreen() >> 2) + + (texture->getColor()->getGreen() >> 1)) * 0xff; + xcol.blue = + (unsigned int) ((texture->getColor()->getBlue() >> 2) + + (texture->getColor()->getBlue() >> 1)) * 0xff; + + if (! XAllocColor(getBaseDisplay()->getXDisplay(), + getColormap(), &xcol)) + xcol.pixel = 0; + + texture->getLoColor()->setPixel(xcol.pixel); + } else if (texture->getTexture() & BImage_Gradient) { + int clen = strlen(rclass) + 10, nlen = strlen(rname) + 10; + + char *colorclass = new char[clen], *colorname = new char[nlen], + *colortoclass = new char[clen], *colortoname = new char[nlen]; + + sprintf(colorclass, "%s.Color", rclass); + sprintf(colorname, "%s.color", rname); + + sprintf(colortoclass, "%s.ColorTo", rclass); + sprintf(colortoname, "%s.colorTo", rname); + + readDatabaseColor(colorname, colorclass, texture->getColor(), + default_pixel); + readDatabaseColor(colortoname, colortoclass, texture->getColorTo(), + default_pixel); + + delete [] colorclass; + delete [] colorname; + delete [] colortoclass; + delete [] colortoname; + } +} + + +void BScreen::readDatabaseColor(char *rname, char *rclass, BColor *color, + unsigned long default_pixel) +{ + XrmValue value; + char *value_type; + + if (XrmGetResource(resource.stylerc, rname, rclass, &value_type, + &value)) { + image_control->parseColor(color, value.addr); + } else { + // parsing with no color string just deallocates the color, if it has + // been previously allocated + image_control->parseColor(color); + color->setPixel(default_pixel); + } +} + + +void BScreen::readDatabaseFontSet(char *rname, char *rclass, + XFontSet *fontset) { + if (! fontset) return; + + static char *defaultFont = "fixed"; + + Bool load_default = False; + XrmValue value; + char *value_type; + + if (*fontset) + XFreeFontSet(getBaseDisplay()->getXDisplay(), *fontset); + + if (XrmGetResource(resource.stylerc, rname, rclass, &value_type, &value)) { + char *fontname = value.addr; + if (! (*fontset = createFontSet(fontname))) + load_default = True; + } else { + load_default = True; + } + + if (load_default) { + *fontset = createFontSet(defaultFont); + + if (! *fontset) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenDefaultFontLoadFail, + "BScreen::LoadStyle(): couldn't load default font.\n")); + exit(2); + } + } +} + + +void BScreen::readDatabaseFont(char *rname, char *rclass, XFontStruct **font) { + if (! font) return; + + static char *defaultFont = "fixed"; + + Bool load_default = False; + XrmValue value; + char *value_type; + + if (*font) + XFreeFont(getBaseDisplay()->getXDisplay(), *font); + + if (XrmGetResource(resource.stylerc, rname, rclass, &value_type, &value)) { + if ((*font = XLoadQueryFont(getBaseDisplay()->getXDisplay(), + value.addr)) == NULL) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenFontLoadFail, + "BScreen::LoadStyle(): couldn't load font '%s'\n"), + value.addr); + + load_default = True; + } + } else { + load_default = True; + } + + if (load_default) { + if ((*font = XLoadQueryFont(getBaseDisplay()->getXDisplay(), + defaultFont)) == NULL) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenDefaultFontLoadFail, + "BScreen::LoadStyle(): couldn't load default font.\n")); + exit(2); + } + } +} + + +XFontSet BScreen::createFontSet(char *fontname) { + XFontSet fs; + char **missing, *def = "-"; + int nmissing, pixel_size = 0, buf_size = 0; + char weight[FONT_ELEMENT_SIZE], slant[FONT_ELEMENT_SIZE]; + + fs = XCreateFontSet(getBaseDisplay()->getXDisplay(), + fontname, &missing, &nmissing, &def); + if (fs && (! nmissing)) return fs; + +#ifdef HAVE_SETLOCALE + if (! fs) { + if (nmissing) XFreeStringList(missing); + + setlocale(LC_CTYPE, "C"); + fs = XCreateFontSet(getBaseDisplay()->getXDisplay(), fontname, + &missing, &nmissing, &def); + setlocale(LC_CTYPE, ""); + } +#endif // HAVE_SETLOCALE + + if (fs) { + XFontStruct **fontstructs; + char **fontnames; + XFontsOfFontSet(fs, &fontstructs, &fontnames); + fontname = fontnames[0]; + } + + getFontElement(fontname, weight, FONT_ELEMENT_SIZE, + "-medium-", "-bold-", "-demibold-", "-regular-", NULL); + getFontElement(fontname, slant, FONT_ELEMENT_SIZE, + "-r-", "-i-", "-o-", "-ri-", "-ro-", NULL); + getFontSize(fontname, &pixel_size); + + if (! strcmp(weight, "*")) strncpy(weight, "medium", FONT_ELEMENT_SIZE); + if (! strcmp(slant, "*")) strncpy(slant, "r", FONT_ELEMENT_SIZE); + if (pixel_size < 3) pixel_size = 3; + else if (pixel_size > 97) pixel_size = 97; + + buf_size = strlen(fontname) + (FONT_ELEMENT_SIZE * 2) + 64; + char *pattern2 = new char[buf_size]; + snprintf(pattern2, buf_size - 1, + "%s," + "-*-*-%s-%s-*-*-%d-*-*-*-*-*-*-*," + "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*,*", + fontname, weight, slant, pixel_size, pixel_size); + fontname = pattern2; + + if (nmissing) XFreeStringList(missing); + if (fs) XFreeFontSet(getBaseDisplay()->getXDisplay(), fs); + + fs = XCreateFontSet(getBaseDisplay()->getXDisplay(), fontname, + &missing, &nmissing, &def); + delete [] pattern2; + + return fs; +} + + +void BScreen::reconfigure(void) { + LoadStyle(); + + XGCValues gcv; + unsigned long gc_value_mask = GCForeground; + if (! i18n->multibyte()) gc_value_mask |= GCFont; + + gcv.foreground = WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber()); + gcv.function = GXinvert; + gcv.subwindow_mode = IncludeInferiors; + XChangeGC(getBaseDisplay()->getXDisplay(), opGC, + GCForeground | GCFunction | GCSubwindowMode, &gcv); + + gcv.foreground = resource.wstyle.l_text_focus.getPixel(); + if (resource.wstyle.font) + gcv.font = resource.wstyle.font->fid; + XChangeGC(getBaseDisplay()->getXDisplay(), resource.wstyle.l_text_focus_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.wstyle.l_text_unfocus.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.wstyle.l_text_unfocus_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.wstyle.b_pic_focus.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.wstyle.b_pic_focus_gc, + GCForeground, &gcv); + + gcv.foreground = resource.wstyle.b_pic_unfocus.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.wstyle.b_pic_unfocus_gc, + GCForeground, &gcv); + + gcv.foreground = resource.mstyle.t_text.getPixel(); + if (resource.mstyle.t_font) + gcv.font = resource.mstyle.t_font->fid; + XChangeGC(getBaseDisplay()->getXDisplay(), resource.mstyle.t_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.f_text.getPixel(); + if (resource.mstyle.f_font) + gcv.font = resource.mstyle.f_font->fid; + XChangeGC(getBaseDisplay()->getXDisplay(), resource.mstyle.f_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.h_text.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.mstyle.h_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.d_text.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.mstyle.d_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.mstyle.hilite.getColor()->getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.mstyle.hilite_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.l_text.getPixel(); + if (resource.tstyle.font) + gcv.font = resource.tstyle.font->fid; + XChangeGC(getBaseDisplay()->getXDisplay(), resource.tstyle.l_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.w_text.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.tstyle.w_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.c_text.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.tstyle.c_text_gc, + gc_value_mask, &gcv); + + gcv.foreground = resource.tstyle.b_pic.getPixel(); + XChangeGC(getBaseDisplay()->getXDisplay(), resource.tstyle.b_pic_gc, + gc_value_mask, &gcv); + + const char *s = i18n->getMessage(ScreenSet, ScreenPositionLength, + "0: 0000 x 0: 0000"); + int l = strlen(s); + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical); + geom_w = logical.width; + + geom_h = resource.wstyle.fontset_extents->max_ink_extent.height; + } else { + geom_w = XTextWidth(resource.wstyle.font, s, l); + + geom_h = resource.wstyle.font->ascent + + resource.wstyle.font->descent; + } + + geom_w += (resource.bevel_width * 2); + geom_h += (resource.bevel_width * 2); + + Pixmap tmp = geom_pixmap; + if (resource.wstyle.l_focus.getTexture() & BImage_ParentRelative) { + if (resource.wstyle.t_focus.getTexture() == + (BImage_Flat | BImage_Solid)) { + geom_pixmap = None; + XSetWindowBackground(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.t_focus.getColor()->getPixel()); + } else { + geom_pixmap = image_control->renderImage(geom_w, geom_h, + &resource.wstyle.t_focus); + XSetWindowBackgroundPixmap(getBaseDisplay()->getXDisplay(), + geom_window, geom_pixmap); + } + } else { + if (resource.wstyle.l_focus.getTexture() == + (BImage_Flat | BImage_Solid)) { + geom_pixmap = None; + XSetWindowBackground(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.l_focus.getColor()->getPixel()); + } else { + geom_pixmap = image_control->renderImage(geom_w, geom_h, + &resource.wstyle.l_focus); + XSetWindowBackgroundPixmap(getBaseDisplay()->getXDisplay(), + geom_window, geom_pixmap); + } + } + if (tmp) image_control->removeImage(tmp); + + XSetWindowBorderWidth(getBaseDisplay()->getXDisplay(), geom_window, + resource.border_width); + XSetWindowBorder(getBaseDisplay()->getXDisplay(), geom_window, + resource.border_color.getPixel()); + + workspacemenu->reconfigure(); + iconmenu->reconfigure(); + + { + int remember_sub = rootmenu->getCurrentSubmenu(); + InitMenu(); + raiseWindows(0, 0); + rootmenu->reconfigure(); + rootmenu->drawSubmenu(remember_sub); + } + + configmenu->reconfigure(); + + toolbar->reconfigure(); + +#ifdef SLIT + slit->reconfigure(); +#endif // SLIT + + LinkedListIterator wit(workspacesList); + for (Workspace *w = wit.current(); w; wit++, w = wit.current()) + w->reconfigure(); + + LinkedListIterator iit(iconList); + for (OpenboxWindow *bw = iit.current(); bw; iit++, bw = iit.current()) + if (bw->validateClient()) + bw->reconfigure(); + + image_control->timeout(); +} + + +void BScreen::rereadMenu(void) { + InitMenu(); + raiseWindows(0, 0); + + rootmenu->reconfigure(); +} + + +void BScreen::removeWorkspaceNames(void) { + while (workspaceNames->count()) + delete [] workspaceNames->remove(0); +} + + +void BScreen::LoadStyle(void) { + resource.stylerc = XrmGetFileDatabase(openbox->getStyleFilename()); + if (resource.stylerc == NULL) + resource.stylerc = XrmGetFileDatabase(DEFAULTSTYLE); + assert(resource.stylerc != NULL); + + XrmValue value; + char *value_type; + + // load fonts/fontsets + + if (i18n->multibyte()) { + readDatabaseFontSet("window.font", "Window.Font", + &resource.wstyle.fontset); + readDatabaseFontSet("toolbar.font", "Toolbar.Font", + &resource.tstyle.fontset); + readDatabaseFontSet("menu.title.font", "Menu.Title.Font", + &resource.mstyle.t_fontset); + readDatabaseFontSet("menu.frame.font", "Menu.Frame.Font", + &resource.mstyle.f_fontset); + + resource.mstyle.t_fontset_extents = + XExtentsOfFontSet(resource.mstyle.t_fontset); + resource.mstyle.f_fontset_extents = + XExtentsOfFontSet(resource.mstyle.f_fontset); + resource.tstyle.fontset_extents = + XExtentsOfFontSet(resource.tstyle.fontset); + resource.wstyle.fontset_extents = + XExtentsOfFontSet(resource.wstyle.fontset); + } else { + readDatabaseFont("window.font", "Window.Font", + &resource.wstyle.font); + readDatabaseFont("menu.title.font", "Menu.Title.Font", + &resource.mstyle.t_font); + readDatabaseFont("menu.frame.font", "Menu.Frame.Font", + &resource.mstyle.f_font); + readDatabaseFont("toolbar.font", "Toolbar.Font", + &resource.tstyle.font); + } + + // load window config + readDatabaseTexture("window.title.focus", "Window.Title.Focus", + &resource.wstyle.t_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.title.unfocus", "Window.Title.Unfocus", + &resource.wstyle.t_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.label.focus", "Window.Label.Focus", + &resource.wstyle.l_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.label.unfocus", "Window.Label.Unfocus", + &resource.wstyle.l_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.handle.focus", "Window.Handle.Focus", + &resource.wstyle.h_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.handle.unfocus", "Window.Handle.Unfocus", + &resource.wstyle.h_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.grip.focus", "Window.Grip.Focus", + &resource.wstyle.g_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.grip.unfocus", "Window.Grip.Unfocus", + &resource.wstyle.g_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.button.focus", "Window.Button.Focus", + &resource.wstyle.b_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.button.unfocus", "Window.Button.Unfocus", + &resource.wstyle.b_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("window.button.pressed", "Window.Button.Pressed", + &resource.wstyle.b_pressed, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.frame.focusColor", + "Window.Frame.FocusColor", + &resource.wstyle.f_focus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.frame.unfocusColor", + "Window.Frame.UnfocusColor", + &resource.wstyle.f_unfocus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.label.focus.textColor", + "Window.Label.Focus.TextColor", + &resource.wstyle.l_text_focus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.label.unfocus.textColor", + "Window.Label.Unfocus.TextColor", + &resource.wstyle.l_text_unfocus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.button.focus.picColor", + "Window.Button.Focus.PicColor", + &resource.wstyle.b_pic_focus, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("window.button.unfocus.picColor", + "Window.Button.Unfocus.PicColor", + &resource.wstyle.b_pic_unfocus, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + + if (XrmGetResource(resource.stylerc, "window.justify", "Window.Justify", + &value_type, &value)) { + if (strstr(value.addr, "right") || strstr(value.addr, "Right")) + resource.wstyle.justify = BScreen::RightJustify; + else if (strstr(value.addr, "center") || strstr(value.addr, "Center")) + resource.wstyle.justify = BScreen::CenterJustify; + else + resource.wstyle.justify = BScreen::LeftJustify; + } else { + resource.wstyle.justify = BScreen::LeftJustify; + } + // load toolbar config + readDatabaseTexture("toolbar", "Toolbar", + &resource.tstyle.toolbar, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("toolbar.label", "Toolbar.Label", + &resource.tstyle.label, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("toolbar.windowLabel", "Toolbar.WindowLabel", + &resource.tstyle.window, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("toolbar.button", "Toolbar.Button", + &resource.tstyle.button, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("toolbar.button.pressed", "Toolbar.Button.Pressed", + &resource.tstyle.pressed, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("toolbar.clock", "Toolbar.Clock", + &resource.tstyle.clock, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("toolbar.label.textColor", "Toolbar.Label.TextColor", + &resource.tstyle.l_text, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("toolbar.windowLabel.textColor", + "Toolbar.WindowLabel.TextColor", + &resource.tstyle.w_text, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("toolbar.clock.textColor", "Toolbar.Clock.TextColor", + &resource.tstyle.c_text, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("toolbar.button.picColor", "Toolbar.Button.PicColor", + &resource.tstyle.b_pic, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + + if (XrmGetResource(resource.stylerc, "toolbar.justify", + "Toolbar.Justify", &value_type, &value)) { + if (strstr(value.addr, "right") || strstr(value.addr, "Right")) + resource.tstyle.justify = BScreen::RightJustify; + else if (strstr(value.addr, "center") || strstr(value.addr, "Center")) + resource.tstyle.justify = BScreen::CenterJustify; + else + resource.tstyle.justify = BScreen::LeftJustify; + } else { + resource.tstyle.justify = BScreen::LeftJustify; + } + // load menu config + readDatabaseTexture("menu.title", "Menu.Title", + &resource.mstyle.title, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("menu.frame", "Menu.Frame", + &resource.mstyle.frame, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseTexture("menu.hilite", "Menu.Hilite", + &resource.mstyle.hilite, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("menu.title.textColor", "Menu.Title.TextColor", + &resource.mstyle.t_text, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("menu.frame.textColor", "Menu.Frame.TextColor", + &resource.mstyle.f_text, + WhitePixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("menu.frame.disableColor", "Menu.Frame.DisableColor", + &resource.mstyle.d_text, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + readDatabaseColor("menu.hilite.textColor", "Menu.Hilite.TextColor", + &resource.mstyle.h_text, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + + if (XrmGetResource(resource.stylerc, "menu.title.justify", + "Menu.Title.Justify", + &value_type, &value)) { + if (strstr(value.addr, "right") || strstr(value.addr, "Right")) + resource.mstyle.t_justify = BScreen::RightJustify; + else if (strstr(value.addr, "center") || strstr(value.addr, "Center")) + resource.mstyle.t_justify = BScreen::CenterJustify; + else + resource.mstyle.t_justify = BScreen::LeftJustify; + } else { + resource.mstyle.t_justify = BScreen::LeftJustify; + } + if (XrmGetResource(resource.stylerc, "menu.frame.justify", + "Menu.Frame.Justify", + &value_type, &value)) { + if (strstr(value.addr, "right") || strstr(value.addr, "Right")) + resource.mstyle.f_justify = BScreen::RightJustify; + else if (strstr(value.addr, "center") || strstr(value.addr, "Center")) + resource.mstyle.f_justify = BScreen::CenterJustify; + else + resource.mstyle.f_justify = BScreen::LeftJustify; + } else { + resource.mstyle.f_justify = BScreen::LeftJustify; + } + if (XrmGetResource(resource.stylerc, "menu.bullet", "Menu.Bullet", + &value_type, &value)) { + if (! strncasecmp(value.addr, "empty", value.size)) + resource.mstyle.bullet = Basemenu::Empty; + else if (! strncasecmp(value.addr, "square", value.size)) + resource.mstyle.bullet = Basemenu::Square; + else if (! strncasecmp(value.addr, "diamond", value.size)) + resource.mstyle.bullet = Basemenu::Diamond; + else + resource.mstyle.bullet = Basemenu::Triangle; + } else { + resource.mstyle.bullet = Basemenu::Triangle; + } + if (XrmGetResource(resource.stylerc, "menu.bullet.position", + "Menu.Bullet.Position", &value_type, &value)) { + if (! strncasecmp(value.addr, "right", value.size)) + resource.mstyle.bullet_pos = Basemenu::Right; + else + resource.mstyle.bullet_pos = Basemenu::Left; + } else { + resource.mstyle.bullet_pos = Basemenu::Left; + } + readDatabaseColor("borderColor", "BorderColor", &resource.border_color, + BlackPixel(getBaseDisplay()->getXDisplay(), + getScreenNumber())); + + // load bevel, border and handle widths + if (XrmGetResource(resource.stylerc, "handleWidth", "HandleWidth", + &value_type, &value)) { + if (sscanf(value.addr, "%u", &resource.handle_width) != 1 || + resource.handle_width > getWidth() / 2 || resource.handle_width == 0) + resource.handle_width = 6; + } else { + resource.handle_width = 6; + } + if (XrmGetResource(resource.stylerc, "borderWidth", "BorderWidth", + &value_type, &value)) { + if (sscanf(value.addr, "%u", &resource.border_width) != 1) + resource.border_width = 1; + } else { + resource.border_width = 1; + } + + if (XrmGetResource(resource.stylerc, "bevelWidth", "BevelWidth", + &value_type, &value)) { + if (sscanf(value.addr, "%u", &resource.bevel_width) != 1 || + resource.bevel_width > getWidth() / 2 || resource.bevel_width == 0) + resource.bevel_width = 3; + } else { + resource.bevel_width = 3; + } + if (XrmGetResource(resource.stylerc, "frameWidth", "FrameWidth", + &value_type, &value)) { + if (sscanf(value.addr, "%u", &resource.frame_width) != 1 || + resource.frame_width > getWidth() / 2) + resource.frame_width = resource.bevel_width; + } else { + resource.frame_width = resource.bevel_width; + } + const char *cmd = resource.root_command; + if (cmd != NULL || XrmGetResource(resource.stylerc, + "rootCommand", + "RootCommand", &value_type, &value)) { + if (cmd == NULL) + cmd = value.addr; // not specified by the screen, so use the one from the + // style file +#ifndef __EMX__ + char displaystring[MAXPATHLEN]; + sprintf(displaystring, "DISPLAY=%s", + DisplayString(getBaseDisplay()->getXDisplay())); + sprintf(displaystring + strlen(displaystring) - 1, "%d", + getScreenNumber()); + + bexec(cmd, displaystring); +#else // __EMX__ + spawnlp(P_NOWAIT, "cmd.exe", "cmd.exe", "/c", cmd, NULL); +#endif // !__EMX__ + } + + XrmDestroyDatabase(resource.stylerc); +} + + +void BScreen::addIcon(OpenboxWindow *w) { + if (! w) return; + + w->setWorkspace(-1); + w->setWindowNumber(iconList->count()); + + iconList->insert(w); + + iconmenu->insert((const char **) w->getIconTitle()); + iconmenu->update(); +} + + +void BScreen::removeIcon(OpenboxWindow *w) { + if (! w) return; + + iconList->remove(w->getWindowNumber()); + + iconmenu->remove(w->getWindowNumber()); + iconmenu->update(); + + LinkedListIterator it(iconList); + OpenboxWindow *bw = it.current(); + for (int i = 0; bw; it++, bw = it.current()) + bw->setWindowNumber(i++); +} + + +OpenboxWindow *BScreen::getIcon(int index) { + if (index >= 0 && index < iconList->count()) + return iconList->find(index); + + return (OpenboxWindow *) 0; +} + + +int BScreen::addWorkspace(void) { + Workspace *wkspc = new Workspace(this, workspacesList->count()); + workspacesList->insert(wkspc); + + workspacemenu->insert(wkspc->getName(), wkspc->getMenu(), + wkspc->getWorkspaceID() + 2); + workspacemenu->update(); + + toolbar->reconfigure(); + + updateNetizenWorkspaceCount(); + + return workspacesList->count(); +} + + +int BScreen::removeLastWorkspace(void) { + if (workspacesList->count() == 1) + return 0; + + Workspace *wkspc = workspacesList->last(); + + if (current_workspace->getWorkspaceID() == wkspc->getWorkspaceID()) + changeWorkspaceID(current_workspace->getWorkspaceID() - 1); + + wkspc->removeAll(); + + workspacemenu->remove(wkspc->getWorkspaceID() + 2); + workspacemenu->update(); + + workspacesList->remove(wkspc); + delete wkspc; + + toolbar->reconfigure(); + + updateNetizenWorkspaceCount(); + + return workspacesList->count(); +} + + +void BScreen::changeWorkspaceID(int id) { + if (! current_workspace) return; + + if (id != current_workspace->getWorkspaceID()) { + current_workspace->hideAll(); + + workspacemenu->setItemSelected(current_workspace->getWorkspaceID() + 2, + False); + + if (openbox->getFocusedWindow() && + openbox->getFocusedWindow()->getScreen() == this && + (! openbox->getFocusedWindow()->isStuck())) { + current_workspace->setLastFocusedWindow(openbox->getFocusedWindow()); + openbox->setFocusedWindow((OpenboxWindow *) 0); + } + + current_workspace = getWorkspace(id); + + workspacemenu->setItemSelected(current_workspace->getWorkspaceID() + 2, + True); + toolbar->redrawWorkspaceLabel(True); + + current_workspace->showAll(); + + if (resource.focus_last && current_workspace->getLastFocusedWindow()) { + XSync(openbox->getXDisplay(), False); + current_workspace->getLastFocusedWindow()->setInputFocus(); + } + } + + updateNetizenCurrentWorkspace(); +} + + +void BScreen::addNetizen(Netizen *n) { + netizenList->insert(n); + + n->sendWorkspaceCount(); + n->sendCurrentWorkspace(); + + LinkedListIterator it(workspacesList); + for (Workspace *w = it.current(); w; it++, w = it.current()) { + for (int i = 0; i < w->getCount(); i++) + n->sendWindowAdd(w->getWindow(i)->getClientWindow(), + w->getWorkspaceID()); + } + + Window f = ((openbox->getFocusedWindow()) ? + openbox->getFocusedWindow()->getClientWindow() : None); + n->sendWindowFocus(f); +} + + +void BScreen::removeNetizen(Window w) { + LinkedListIterator it(netizenList); + int i = 0; + + for (Netizen *n = it.current(); n; it++, i++, n = it.current()) + if (n->getWindowID() == w) { + Netizen *tmp = netizenList->remove(i); + delete tmp; + + break; + } +} + + +void BScreen::updateNetizenCurrentWorkspace(void) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendCurrentWorkspace(); +} + + +void BScreen::updateNetizenWorkspaceCount(void) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWorkspaceCount(); +} + + +void BScreen::updateNetizenWindowFocus(void) { + Window f = ((openbox->getFocusedWindow()) ? + openbox->getFocusedWindow()->getClientWindow() : None); + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWindowFocus(f); +} + + +void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWindowAdd(w, p); +} + + +void BScreen::updateNetizenWindowDel(Window w) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWindowDel(w); +} + + +void BScreen::updateNetizenWindowRaise(Window w) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWindowRaise(w); +} + + +void BScreen::updateNetizenWindowLower(Window w) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendWindowLower(w); +} + + +void BScreen::updateNetizenConfigNotify(XEvent *e) { + LinkedListIterator it(netizenList); + for (Netizen *n = it.current(); n; it++, n = it.current()) + n->sendConfigNotify(e); +} + + +void BScreen::raiseWindows(Window *workspace_stack, int num) { + Window *session_stack = new + Window[(num + workspacesList->count() + rootmenuList->count() + 13)]; + int i = 0, k = num; + + XRaiseWindow(getBaseDisplay()->getXDisplay(), iconmenu->getWindowID()); + *(session_stack + i++) = iconmenu->getWindowID(); + + LinkedListIterator wit(workspacesList); + for (Workspace *tmp = wit.current(); tmp; wit++, tmp = wit.current()) + *(session_stack + i++) = tmp->getMenu()->getWindowID(); + + *(session_stack + i++) = workspacemenu->getWindowID(); + + *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID(); + *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = configmenu->getWindowID(); + +#ifdef SLIT + *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID(); + *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = slit->getMenu()->getWindowID(); +#endif // SLIT + + *(session_stack + i++) = + toolbar->getMenu()->getPlacementmenu()->getWindowID(); + *(session_stack + i++) = toolbar->getMenu()->getWindowID(); + + LinkedListIterator rit(rootmenuList); + for (Rootmenu *tmp = rit.current(); tmp; rit++, tmp = rit.current()) + *(session_stack + i++) = tmp->getWindowID(); + *(session_stack + i++) = rootmenu->getWindowID(); + + if (toolbar->isOnTop()) + *(session_stack + i++) = toolbar->getWindowID(); + +#ifdef SLIT + if (slit->isOnTop()) + *(session_stack + i++) = slit->getWindowID(); +#endif // SLIT + + while (k--) + *(session_stack + i++) = *(workspace_stack + k); + + XRestackWindows(getBaseDisplay()->getXDisplay(), session_stack, i); + + delete [] session_stack; +} + + +#ifdef HAVE_STRFTIME +void BScreen::saveStrftimeFormat(char *format) { + if (resource.strftime_format) + delete [] resource.strftime_format; + + resource.strftime_format = bstrdup(format); +} +#endif // HAVE_STRFTIME + + +void BScreen::addWorkspaceName(char *name) { + workspaceNames->insert(bstrdup(name)); +} + + +char* BScreen::getNameOfWorkspace(int id) { + char *name = (char *) 0; + + if (id >= 0 && id < workspaceNames->count()) { + char *wkspc_name = workspaceNames->find(id); + + if (wkspc_name) + name = wkspc_name; + } + return name; +} + + +void BScreen::reassociateWindow(OpenboxWindow *w, int wkspc_id, Bool ignore_sticky) { + if (! w) return; + + if (wkspc_id == -1) + wkspc_id = current_workspace->getWorkspaceID(); + + if (w->getWorkspaceNumber() == wkspc_id) + return; + + if (w->isIconic()) { + removeIcon(w); + getWorkspace(wkspc_id)->addWindow(w); + } else if (ignore_sticky || ! w->isStuck()) { + getWorkspace(w->getWorkspaceNumber())->removeWindow(w); + getWorkspace(wkspc_id)->addWindow(w); + } +} + + +void BScreen::nextFocus(void) { + Bool have_focused = False; + int focused_window_number = -1; + OpenboxWindow *next; + + if (openbox->getFocusedWindow()) { + if (openbox->getFocusedWindow()->getScreen()->getScreenNumber() == + getScreenNumber()) { + have_focused = True; + focused_window_number = openbox->getFocusedWindow()->getWindowNumber(); + } + } + + if ((getCurrentWorkspace()->getCount() > 1) && have_focused) { + int next_window_number = focused_window_number; + do { + if ((++next_window_number) >= getCurrentWorkspace()->getCount()) + next_window_number = 0; + + next = getCurrentWorkspace()->getWindow(next_window_number); + } while ((! next->setInputFocus()) && (next_window_number != + focused_window_number)); + + if (next_window_number != focused_window_number) + getCurrentWorkspace()->raiseWindow(next); + } else if (getCurrentWorkspace()->getCount() >= 1) { + next = current_workspace->getWindow(0); + + current_workspace->raiseWindow(next); + next->setInputFocus(); + } +} + + +void BScreen::prevFocus(void) { + Bool have_focused = False; + int focused_window_number = -1; + OpenboxWindow *prev; + + if (openbox->getFocusedWindow()) { + if (openbox->getFocusedWindow()->getScreen()->getScreenNumber() == + getScreenNumber()) { + have_focused = True; + focused_window_number = openbox->getFocusedWindow()->getWindowNumber(); + } + } + + if ((getCurrentWorkspace()->getCount() > 1) && have_focused) { + int prev_window_number = focused_window_number; + do { + if ((--prev_window_number) < 0) + prev_window_number = getCurrentWorkspace()->getCount() - 1; + + prev = getCurrentWorkspace()->getWindow(prev_window_number); + } while ((! prev->setInputFocus()) && (prev_window_number != + focused_window_number)); + + if (prev_window_number != focused_window_number) + getCurrentWorkspace()->raiseWindow(prev); + } else if (getCurrentWorkspace()->getCount() >= 1) { + prev = current_workspace->getWindow(0); + + current_workspace->raiseWindow(prev); + prev->setInputFocus(); + } +} + + +void BScreen::raiseFocus(void) { + Bool have_focused = False; + int focused_window_number = -1; + + if (openbox->getFocusedWindow()) { + if (openbox->getFocusedWindow()->getScreen()->getScreenNumber() == + getScreenNumber()) { + have_focused = True; + focused_window_number = openbox->getFocusedWindow()->getWindowNumber(); + } + } + + if ((getCurrentWorkspace()->getCount() > 1) && have_focused) + getWorkspace(openbox->getFocusedWindow()->getWorkspaceNumber())-> + raiseWindow(openbox->getFocusedWindow()); +} + + +void BScreen::InitMenu(void) { + if (rootmenu) { + while (rootmenuList->count()) + rootmenuList->remove(0); + + while (rootmenu->getCount()) + rootmenu->remove(0); + } else { + rootmenu = new Rootmenu(this); + } + Bool defaultMenu = True; + + if (openbox->getMenuFilename()) { + FILE *menu_file = fopen(openbox->getMenuFilename(), "r"); + + if (!menu_file) { + perror(openbox->getMenuFilename()); + } else { + if (feof(menu_file)) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenEmptyMenuFile, + "%s: Empty menu file"), + openbox->getMenuFilename()); + } 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] != '#') { + int i, key = 0, index = -1, len = strlen(line); + + key = 0; + 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) { + 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); + break; + } + } + } + } + fclose(menu_file); + } + } + + if (defaultMenu) { + rootmenu->setInternalMenu(); + rootmenu->insert(i18n->getMessage(ScreenSet, Screenxterm, "xterm"), + BScreen::Execute, + i18n->getMessage(ScreenSet, Screenxterm, "xterm")); + rootmenu->insert(i18n->getMessage(ScreenSet, ScreenRestart, "Restart"), + BScreen::Restart); + rootmenu->insert(i18n->getMessage(ScreenSet, ScreenExit, "Exit"), + BScreen::Exit); + } else { + openbox->saveMenuFilename(openbox->getMenuFilename()); + } +} + + +Bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) { + char line[1024], label[1024], command[1024]; + + while (! feof(file)) { + memset(line, 0, 1024); + memset(label, 0, 1024); + memset(command, 0, 1024); + + if (fgets(line, 1024, file)) { + if (line[0] != '#') { + register int i, key = 0, parse = 0, index = -1, + line_length = strlen(line), + label_length = 0, command_length = 0; + + // determine the keyword + key = 0; + for (i = 0; i < line_length; i++) { + if (line[i] == '[') parse = 1; + else if (line[i] == ']') break; + else if (line[i] != ' ') + if (parse) + key += tolower(line[i]); + } + + // get the label enclosed in ()'s + parse = 0; + + for (i = 0; i < line_length; i++) { + if (line[i] == '(') { + index = 0; + parse = 1; + } else if (line[i] == ')') break; + else if (index++ >= 0) { + if (line[i] == '\\' && i < line_length - 1) i++; + label[index - 1] = line[i]; + } + } + + if (parse) { + label[index] = '\0'; + label_length = index; + } else { + label[0] = '\0'; + label_length = 0; + } + + // get the command enclosed in {}'s + parse = 0; + index = -1; + for (i = 0; i < line_length; i++) { + if (line[i] == '{') { + index = 0; + parse = 1; + } else if (line[i] == '}') break; + else if (index++ >= 0) { + if (line[i] == '\\' && i < line_length - 1) i++; + command[index - 1] = line[i]; + } + } + + if (parse) { + command[index] = '\0'; + command_length = index; + } else { + command[0] = '\0'; + command_length = 0; + } + + switch (key) { + case 311: //end + return ((menu->getCount() == 0) ? True : False); + + break; + + case 333: // nop + menu->insert(label); + + break; + + case 421: // exec + if ((! *label) && (! *command)) { + fprintf(stderr, i18n->getMessage(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->getMessage(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->getMessage(ScreenSet, ScreenSTYLEError, + "BScreen::parseMenuFile: [style] error, " + "no menu label and/or filename defined\n")); + continue; + } + + char style[MAXPATHLEN]; + + // perform shell style ~ home directory expansion + char *homedir = 0; + int homedir_len = 0; + if (*command == '~' && *(command + 1) == '/') { + homedir = getenv("HOME"); + homedir_len = strlen(homedir); + } + + if (homedir && homedir_len != 0) { + strncpy(style, homedir, homedir_len); + + strncpy(style + homedir_len, command + 1, + command_length - 1); + *(style + command_length + homedir_len - 1) = '\0'; + } else { + strncpy(style, command, command_length); + *(style + command_length) = '\0'; + } + + menu->insert(label, BScreen::SetStyle, style); + } + + break; + + case 630: // config + if (! *label) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenCONFIGError, + "BScreen::parseMenufile: [config] error, " + "no label defined")); + continue; + } + + menu->insert(label, configmenu); + + break; + + case 740: // include + { + if (! *label) { + fprintf(stderr, i18n->getMessage(ScreenSet, ScreenINCLUDEError, + "BScreen::parseMenuFile: [include] error, " + "no filename defined\n")); + continue; + } + + char newfile[MAXPATHLEN]; + + // perform shell style ~ home directory expansion + char *homedir = 0; + int homedir_len = 0; + if (*label == '~' && *(label + 1) == '/') { + homedir = getenv("HOME"); + homedir_len = strlen(homedir); + } + + if (homedir && homedir_len != 0) { + strncpy(newfile, homedir, homedir_len); + + strncpy(newfile + homedir_len, label + 1, + label_length - 1); + *(newfile + label_length + homedir_len - 1) = '\0'; + } else { + strncpy(newfile, label, label_length); + *(newfile + label_length) = '\0'; + } + + if (newfile) { + FILE *submenufile = fopen(newfile, "r"); + + if (submenufile) { + struct stat buf; + if (fstat(fileno(submenufile), &buf) || + (! S_ISREG(buf.st_mode))) { + fprintf(stderr, + i18n->getMessage(ScreenSet, ScreenINCLUDEErrorReg, + "BScreen::parseMenuFile: [include] error: " + "'%s' is not a regular file\n"), newfile); + break; + } + + if (! feof(submenufile)) { + if (! parseMenuFile(submenufile, menu)) + openbox->saveMenuFilename(newfile); + + fclose(submenufile); + } + } else + perror(newfile); + } + } + + break; + + case 767: // submenu + { + if (! *label) { + fprintf(stderr, i18n->getMessage(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->insert(submenu); + } + + break; + + case 773: // restart + { + if (! *label) { + fprintf(stderr, i18n->getMessage(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->getMessage(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->getMessage(ScreenSet, ScreenSTYLESDIRError, + "BScreen::parseMenuFile: [stylesdir/stylesmenu]" + " error, no directory defined\n")); + continue; + } + + char stylesdir[MAXPATHLEN]; + + char *directory = ((newmenu) ? command : label); + int directory_length = ((newmenu) ? command_length : label_length); + + // perform shell style ~ home directory expansion + char *homedir = 0; + int homedir_len = 0; + + if (*directory == '~' && *(directory + 1) == '/') { + homedir = getenv("HOME"); + homedir_len = strlen(homedir); + } + + if (homedir && homedir_len != 0) { + strncpy(stylesdir, homedir, homedir_len); + + strncpy(stylesdir + homedir_len, directory + 1, + directory_length - 1); + *(stylesdir + directory_length + homedir_len - 1) = '\0'; + } else { + strncpy(stylesdir, directory, directory_length); + *(stylesdir + directory_length) = '\0'; + } + + struct stat statbuf; + + if (! stat(stylesdir, &statbuf)) { + if (S_ISDIR(statbuf.st_mode)) { + Rootmenu *stylesmenu; + + if (newmenu) + stylesmenu = new Rootmenu(this); + else + stylesmenu = menu; + + DIR *d = opendir(stylesdir); + int entries = 0; + struct dirent *p; + + // get the total number of directory entries + while ((p = readdir(d))) entries++; + rewinddir(d); + + char **ls = new char* [entries]; + int index = 0; + while ((p = readdir(d))) + ls[index++] = bstrdup(p->d_name); + + closedir(d); + + std::sort(ls, ls + entries, dcmp()); + + int n, slen = strlen(stylesdir); + for (n = 0; n < entries; n++) { + if (ls[n][strlen(ls[n])-1] != '~') { + int nlen = strlen(ls[n]); + char style[MAXPATHLEN + 1]; + + strncpy(style, stylesdir, slen); + *(style + slen) = '/'; + strncpy(style + slen + 1, ls[n], nlen + 1); + + if ((! stat(style, &statbuf)) && S_ISREG(statbuf.st_mode)) + stylesmenu->insert(ls[n], BScreen::SetStyle, style); + } + + delete [] ls[n]; + } + + delete [] ls; + + stylesmenu->update(); + + if (newmenu) { + stylesmenu->setLabel(label); + menu->insert(label, stylesmenu); + rootmenuList->insert(stylesmenu); + } + + openbox->saveMenuFilename(stylesdir); + } else { + fprintf(stderr, i18n->getMessage(ScreenSet, + ScreenSTYLESDIRErrorNotDir, + "BScreen::parseMenuFile:" + " [stylesdir/stylesmenu] error, %s is not a" + " directory\n"), stylesdir); + } + } else { + fprintf(stderr, + i18n->getMessage(ScreenSet, ScreenSTYLESDIRErrorNoExist, + "BScreen::parseMenuFile: [stylesdir/stylesmenu]" + " error, %s does not exist\n"), stylesdir); + } + + break; + } + + case 1090: // workspaces + { + if (! *label) { + fprintf(stderr, + i18n->getMessage(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) { + openbox->grab(); + + XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), NoEventMask); + XSync(getBaseDisplay()->getXDisplay(), False); + + LinkedListIterator it(workspacesList); + for (Workspace *w = it.current(); w; it++, w = it.current()) + w->shutdown(); + + while (iconList->count()) { + iconList->first()->restore(); + delete iconList->first(); + } + +#ifdef SLIT + slit->shutdown(); +#endif // SLIT + + openbox->ungrab(); +} + + +void BScreen::showPosition(int x, int y) { + if (! geom_visible) { + XMoveResizeWindow(getBaseDisplay()->getXDisplay(), geom_window, + (getWidth() - geom_w) / 2, + (getHeight() - geom_h) / 2, geom_w, geom_h); + XMapWindow(getBaseDisplay()->getXDisplay(), geom_window); + XRaiseWindow(getBaseDisplay()->getXDisplay(), geom_window); + + geom_visible = True; + } + + char label[1024]; + + sprintf(label, i18n->getMessage(ScreenSet, ScreenPositionFormat, + "X: %4d x Y: %4d"), x, y); + + XClearWindow(getBaseDisplay()->getXDisplay(), geom_window); + + if (i18n->multibyte()) { + XmbDrawString(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.fontset, resource.wstyle.l_text_focus_gc, + resource.bevel_width, resource.bevel_width - + resource.wstyle.fontset_extents->max_ink_extent.y, + label, strlen(label)); + } else { + XDrawString(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.l_text_focus_gc, + resource.bevel_width, + resource.wstyle.font->ascent + + resource.bevel_width, label, strlen(label)); + } +} + + +void BScreen::showGeometry(unsigned int gx, unsigned int gy) { + if (! geom_visible) { + XMoveResizeWindow(getBaseDisplay()->getXDisplay(), geom_window, + (getWidth() - geom_w) / 2, + (getHeight() - geom_h) / 2, geom_w, geom_h); + XMapWindow(getBaseDisplay()->getXDisplay(), geom_window); + XRaiseWindow(getBaseDisplay()->getXDisplay(), geom_window); + + geom_visible = True; + } + + char label[1024]; + + sprintf(label, i18n->getMessage(ScreenSet, ScreenGeometryFormat, + "W: %4d x H: %4d"), gx, gy); + + XClearWindow(getBaseDisplay()->getXDisplay(), geom_window); + + if (i18n->multibyte()) { + XmbDrawString(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.fontset, resource.wstyle.l_text_focus_gc, + resource.bevel_width, resource.bevel_width - + resource.wstyle.fontset_extents->max_ink_extent.y, + label, strlen(label)); + } else { + XDrawString(getBaseDisplay()->getXDisplay(), geom_window, + resource.wstyle.l_text_focus_gc, + resource.bevel_width, + resource.wstyle.font->ascent + + resource.bevel_width, label, strlen(label)); + } +} + + +void BScreen::hideGeometry(void) { + if (geom_visible) { + XUnmapWindow(getBaseDisplay()->getXDisplay(), geom_window); + geom_visible = False; + } +} diff --git a/src/Screen.h b/src/Screen.h new file mode 100644 index 00000000..d49668f9 --- /dev/null +++ b/src/Screen.h @@ -0,0 +1,349 @@ +// Screen.h for Openbox +// 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 __Screen_hh +#define __Screen_hh + +#include +#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 "BaseDisplay.h" +#include "Configmenu.h" +#include "Iconmenu.h" +#include "LinkedList.h" +#include "Netizen.h" +#include "Rootmenu.h" +#include "Timer.h" +#include "Workspace.h" +#include "Workspacemenu.h" +#include "openbox.h" +#ifdef SLIT +# include "Slit.h" +#endif // SLIT +#include "Image.h" + +// forward declaration +class BScreen; + +struct WindowStyle { + BColor f_focus, f_unfocus, l_text_focus, l_text_unfocus, b_pic_focus, + b_pic_unfocus; + BTexture t_focus, t_unfocus, l_focus, l_unfocus, h_focus, h_unfocus, + b_focus, b_unfocus, b_pressed, g_focus, g_unfocus; + GC l_text_focus_gc, l_text_unfocus_gc, b_pic_focus_gc, b_pic_unfocus_gc; + + XFontSet fontset; + XFontSetExtents *fontset_extents; + XFontStruct *font; + + int justify; +}; + +struct ToolbarStyle { + BColor l_text, w_text, c_text, b_pic; + BTexture toolbar, label, window, button, pressed, clock; + GC l_text_gc, w_text_gc, c_text_gc, b_pic_gc; + + XFontSet fontset; + XFontSetExtents *fontset_extents; + XFontStruct *font; + + int justify; +}; + +struct MenuStyle { + BColor t_text, f_text, h_text, d_text; + BTexture title, frame, hilite; + GC t_text_gc, f_text_gc, h_text_gc, d_text_gc, hilite_gc; + + XFontSet t_fontset, f_fontset; + XFontSetExtents *t_fontset_extents, *f_fontset_extents; + XFontStruct *t_font, *f_font; + + int t_justify, f_justify, bullet, bullet_pos; +}; + + +class BScreen : public ScreenInfo { +private: + Bool root_colormap_installed, managed, geom_visible; + GC opGC; + Pixmap geom_pixmap; + Window geom_window; + + Openbox *openbox; + BImageControl *image_control; + Configmenu *configmenu; + Iconmenu *iconmenu; + Rootmenu *rootmenu; + + LinkedList *rootmenuList; + LinkedList *netizenList; + LinkedList *iconList; + +#ifdef SLIT + Slit *slit; +#endif // SLIT + + Toolbar *toolbar; + Workspace *current_workspace; + Workspacemenu *workspacemenu; + + unsigned int geom_w, geom_h; + unsigned long event_mask; + + LinkedList *workspaceNames; + LinkedList *workspacesList; + + struct resource { + WindowStyle wstyle; + ToolbarStyle tstyle; + MenuStyle mstyle; + + Bool toolbar_on_top, toolbar_auto_hide, sloppy_focus, auto_raise, + auto_edge_balance, image_dither, ordered_dither, opaque_move, full_max, + focus_new, focus_last; + BColor border_color; + XrmDatabase stylerc; + + int workspaces, toolbar_placement, toolbar_width_percent, placement_policy, + edge_snap_threshold, row_direction, col_direction; + +#ifdef SLIT + Bool slit_on_top, slit_auto_hide; + int slit_placement, slit_direction; +#endif // SLIT + + unsigned int handle_width, bevel_width, frame_width, border_width; + unsigned int zones; // number of zones to be used when alt-resizing a window + +#ifdef HAVE_STRFTIME + char *strftime_format; +#else // !HAVE_STRFTIME + Bool clock24hour; + int date_format; +#endif // HAVE_STRFTIME + + char *root_command; + } resource; + + +protected: + Bool parseMenuFile(FILE *, Rootmenu *); + + void readDatabaseTexture(char *, char *, BTexture *, unsigned long); + void readDatabaseColor(char *, char *, BColor *, unsigned long); + + void readDatabaseFontSet(char *, char *, XFontSet *); + XFontSet createFontSet(char *); + void readDatabaseFont(char *, char *, XFontStruct **); + + void InitMenu(void); + void LoadStyle(void); + + +public: + BScreen(Openbox *, int); + ~BScreen(void); + + inline const Bool &isToolbarOnTop(void) const + { return resource.toolbar_on_top; } + inline const Bool &doToolbarAutoHide(void) const + { return resource.toolbar_auto_hide; } + inline const Bool &isSloppyFocus(void) const + { return resource.sloppy_focus; } + inline const Bool &isRootColormapInstalled(void) const + { return root_colormap_installed; } + inline const Bool &doAutoRaise(void) const { return resource.auto_raise; } + inline const Bool &isScreenManaged(void) const { return managed; } + inline const Bool &doImageDither(void) const + { return resource.image_dither; } + inline const Bool &doOrderedDither(void) const + { return resource.ordered_dither; } + inline const Bool &doOpaqueMove(void) const { return resource.opaque_move; } + inline const Bool &doFullMax(void) const { return resource.full_max; } + inline const Bool &doFocusNew(void) const { return resource.focus_new; } + inline const Bool &doFocusLast(void) const { return resource.focus_last; } + + inline const GC &getOpGC() const { return opGC; } + + inline Openbox *getOpenbox(void) { return openbox; } + inline BColor *getBorderColor(void) { return &resource.border_color; } + inline BImageControl *getImageControl(void) { return image_control; } + inline Rootmenu *getRootmenu(void) { return rootmenu; } + +#ifdef SLIT + inline const Bool &isSlitOnTop(void) const { return resource.slit_on_top; } + inline const Bool &doSlitAutoHide(void) const + { return resource.slit_auto_hide; } + inline Slit *getSlit(void) { return slit; } + inline const int &getSlitPlacement(void) const + { return resource.slit_placement; } + inline const int &getSlitDirection(void) const + { return resource.slit_direction; } + inline void saveSlitPlacement(int p) { resource.slit_placement = p; } + inline void saveSlitDirection(int d) { resource.slit_direction = d; } + inline void saveSlitOnTop(Bool t) { resource.slit_on_top = t; } + inline void saveSlitAutoHide(Bool t) { resource.slit_auto_hide = t; } +#endif // SLIT + + inline int getWindowZones(void) const + { return resource.zones; } + inline void saveWindowZones(int z) { resource.zones = z; } + + inline Toolbar *getToolbar(void) { return toolbar; } + + inline Workspace *getWorkspace(int w) { return workspacesList->find(w); } + inline Workspace *getCurrentWorkspace(void) { return current_workspace; } + + inline Workspacemenu *getWorkspacemenu(void) { return workspacemenu; } + + inline const unsigned int &getHandleWidth(void) const + { return resource.handle_width; } + inline const unsigned int &getBevelWidth(void) const + { return resource.bevel_width; } + inline const unsigned int &getFrameWidth(void) const + { return resource.frame_width; } + inline const unsigned int &getBorderWidth(void) const + { return resource.border_width; } + + inline const int getCurrentWorkspaceID() + { return current_workspace->getWorkspaceID(); } + inline const int getCount(void) { return workspacesList->count(); } + inline const int getIconCount(void) { return iconList->count(); } + inline const int &getNumberOfWorkspaces(void) const + { return resource.workspaces; } + inline const int &getToolbarPlacement(void) const + { return resource.toolbar_placement; } + inline const int &getToolbarWidthPercent(void) const + { return resource.toolbar_width_percent; } + inline const int &getPlacementPolicy(void) const + { return resource.placement_policy; } + inline const int &getEdgeSnapThreshold(void) const + { return resource.edge_snap_threshold; } + inline const int &getRowPlacementDirection(void) const + { return resource.row_direction; } + inline const int &getColPlacementDirection(void) const + { return resource.col_direction; } + + inline void saveRootCommand(const char *cmd) { + if (resource.root_command != NULL) + delete [] resource.root_command; + if (cmd != NULL) + resource.root_command = bstrdup(cmd); + else + resource.root_command = NULL; + } + inline const char *getRootCommand(void) const + { return resource.root_command; } + + inline void setRootColormapInstalled(Bool r) { root_colormap_installed = r; } + inline void saveSloppyFocus(Bool s) { resource.sloppy_focus = s; } + inline void saveAutoRaise(Bool a) { resource.auto_raise = a; } + inline void saveWorkspaces(int w) { resource.workspaces = w; } + inline void saveToolbarOnTop(Bool r) { resource.toolbar_on_top = r; } + inline void saveToolbarAutoHide(Bool r) { resource.toolbar_auto_hide = r; } + inline void saveToolbarWidthPercent(int w) + { resource.toolbar_width_percent = w; } + inline void saveToolbarPlacement(int p) { resource.toolbar_placement = p; } + inline void savePlacementPolicy(int p) { resource.placement_policy = p; } + inline void saveRowPlacementDirection(int d) { resource.row_direction = d; } + inline void saveColPlacementDirection(int d) { resource.col_direction = d; } + inline void saveEdgeSnapThreshold(int t) + { resource.edge_snap_threshold = t; } + inline void saveImageDither(Bool d) { resource.image_dither = d; } + inline void saveOpaqueMove(Bool o) { resource.opaque_move = o; } + inline void saveFullMax(Bool f) { resource.full_max = f; } + inline void saveFocusNew(Bool f) { resource.focus_new = f; } + inline void saveFocusLast(Bool f) { resource.focus_last = f; } + inline void iconUpdate(void) { iconmenu->update(); } + +#ifdef HAVE_STRFTIME + inline char *getStrftimeFormat(void) { return resource.strftime_format; } + void saveStrftimeFormat(char *); +#else // !HAVE_STRFTIME + inline int getDateFormat(void) { return resource.date_format; } + inline void saveDateFormat(int f) { resource.date_format = f; } + inline Bool isClock24Hour(void) { return resource.clock24hour; } + inline void saveClock24Hour(Bool c) { resource.clock24hour = 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; } + + OpenboxWindow *getIcon(int); + + int addWorkspace(void); + int removeLastWorkspace(void); + + void removeWorkspaceNames(void); + void addWorkspaceName(char *); + void addNetizen(Netizen *); + void removeNetizen(Window); + void addIcon(OpenboxWindow *); + void removeIcon(OpenboxWindow *); + char* getNameOfWorkspace(int); + void changeWorkspaceID(int); + void raiseWindows(Window *, int); + void reassociateWindow(OpenboxWindow *, int, Bool); + void prevFocus(void); + void nextFocus(void); + void raiseFocus(void); + void reconfigure(void); + void rereadMenu(void); + void shutdown(void); + void showPosition(int, int); + void showGeometry(unsigned int, unsigned int); + void hideGeometry(void); + + void updateNetizenCurrentWorkspace(void); + void updateNetizenWorkspaceCount(void); + void updateNetizenWindowFocus(void); + void updateNetizenWindowAdd(Window, unsigned long); + void updateNetizenWindowDel(Window); + void updateNetizenConfigNotify(XEvent *); + void updateNetizenWindowRaise(Window); + void updateNetizenWindowLower(Window); + + enum { RowSmartPlacement = 1, ColSmartPlacement, CascadePlacement, LeftRight, + RightLeft, TopBottom, BottomTop }; + enum { LeftJustify = 1, RightJustify, CenterJustify }; + enum { RoundBullet = 1, TriangleBullet, SquareBullet, NoBullet }; + enum { Restart = 1, RestartOther, Exit, Shutdown, Execute, Reconfigure, + WindowShade, WindowIconify, WindowMaximize, WindowClose, WindowRaise, + WindowLower, WindowStick, WindowKill, SetStyle }; +}; + + +#endif // __Screen_hh diff --git a/src/Slit.cc b/src/Slit.cc new file mode 100644 index 00000000..2eb940e7 --- /dev/null +++ b/src/Slit.cc @@ -0,0 +1,773 @@ +// Slit.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#ifdef SLIT + +#include + +#include "i18n.h" +#include "openbox.h" +#include "Image.h" +#include "Screen.h" +#include "Slit.h" +#include "Toolbar.h" + + +Slit::Slit(BScreen *scr) { + screen = scr; + openbox = screen->getOpenbox(); + + on_top = screen->isSlitOnTop(); + hidden = do_auto_hide = screen->doSlitAutoHide(); + + display = screen->getBaseDisplay()->getXDisplay(); + frame.window = frame.pixmap = None; + + timer = new BTimer(openbox, this); + timer->setTimeout(openbox->getAutoRaiseDelay()); + timer->fireOnce(True); + + clientList = new LinkedList; + + 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()->getPixel(); + attrib.colormap = screen->getColormap(); + attrib.override_redirect = True; + attrib.event_mask = SubstructureRedirectMask | ButtonPressMask | + EnterWindowMask | LeaveWindowMask; + + frame.x = frame.y = 0; + frame.width = frame.height = 1; + + frame.window = + XCreateWindow(display, screen->getRootWindow(), frame.x, frame.y, + frame.width, frame.height, screen->getBorderWidth(), + screen->getDepth(), InputOutput, screen->getVisual(), + create_mask, &attrib); + openbox->saveSlitSearch(frame.window, this); + + reconfigure(); +} + + +Slit::~Slit() { + openbox->grab(); + + if (timer->isTiming()) timer->stop(); + delete timer; + + delete clientList; + delete slitmenu; + + screen->getImageControl()->removeImage(frame.pixmap); + + openbox->removeSlitSearch(frame.window); + + XDestroyWindow(display, frame.window); + + openbox->ungrab(); +} + + +void Slit::addClient(Window w) { + openbox->grab(); + + if (openbox->validateWindow(w)) { + SlitClient *client = new SlitClient; + client->client_window = w; + + XWMHints *wmhints = XGetWMHints(display, w); + + if (wmhints) { + if ((wmhints->flags & IconWindowHint) && + (wmhints->icon_window != None)) { + 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->width = attrib.width; + client->height = attrib.height; + } else { + client->width = client->height = 64; + } + + XSetWindowBorderWidth(display, client->window, 0); + + 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); + XFlush(display); + + clientList->insert(client); + + openbox->saveSlitSearch(client->client_window, this); + openbox->saveSlitSearch(client->icon_window, this); + reconfigure(); + } + + openbox->ungrab(); +} + + +void Slit::removeClient(SlitClient *client, Bool remap) { + openbox->removeSlitSearch(client->client_window); + openbox->removeSlitSearch(client->icon_window); + clientList->remove(client); + + screen->removeNetizen(client->window); + + if (remap && openbox->validateWindow(client->window)) { + XSelectInput(display, frame.window, NoEventMask); + XSelectInput(display, client->window, NoEventMask); + XReparentWindow(display, client->window, screen->getRootWindow(), + client->x, client->y); + XChangeSaveSet(display, client->window, SetModeDelete); + XSelectInput(display, frame.window, SubstructureRedirectMask | + ButtonPressMask | EnterWindowMask | LeaveWindowMask); + XFlush(display); + } + + delete client; + client = (SlitClient *) 0; +} + + +void Slit::removeClient(Window w, Bool remap) { + openbox->grab(); + + Bool reconf = False; + + LinkedListIterator it(clientList); + for (SlitClient *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->window == w) { + removeClient(tmp, remap); + reconf = True; + + break; + } + } + + if (reconf) reconfigure(); + + openbox->ungrab(); +} + + +void Slit::reconfigure(void) { + frame.width = 0; + frame.height = 0; + LinkedListIterator it(clientList); + SlitClient *client; + + switch (screen->getSlitDirection()) { + case Vertical: + for (client = it.current(); client; it++, client = it.current()) { + frame.height += client->height + screen->getBevelWidth(); + + if (frame.width < client->width) + frame.width = client->width; + } + + if (frame.width < 1) + frame.width = 1; + else + frame.width += (screen->getBevelWidth() * 2); + + if (frame.height < 1) + frame.height = 1; + else + frame.height += screen->getBevelWidth(); + + break; + + case Horizontal: + for (client = it.current(); client; it++, client = it.current()) { + frame.width += client->width + screen->getBevelWidth(); + + if (frame.height < client->height) + frame.height = client->height; + } + + if (frame.width < 1) + frame.width = 1; + else + frame.width += screen->getBevelWidth(); + + if (frame.height < 1) + frame.height = 1; + else + frame.height += (screen->getBevelWidth() * 2); + + break; + } + + reposition(); + + XSetWindowBorderWidth(display ,frame.window, screen->getBorderWidth()); + XSetWindowBorder(display, frame.window, + screen->getBorderColor()->getPixel()); + + if (! clientList->count()) + XUnmapWindow(display, frame.window); + else + XMapWindow(display, frame.window); + + Pixmap tmp = frame.pixmap; + BImageControl *image_ctrl = screen->getImageControl(); + BTexture *texture = &(screen->getToolbarStyle()->toolbar); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.pixmap = None; + XSetWindowBackground(display, frame.window, + texture->getColor()->getPixel()); + } else { + frame.pixmap = image_ctrl->renderImage(frame.width, frame.height, + texture); + XSetWindowBackgroundPixmap(display, frame.window, frame.pixmap); + } + if (tmp) image_ctrl->removeImage(tmp); + XClearWindow(display, frame.window); + + int x, y; + it.reset(); + + switch (screen->getSlitDirection()) { + case Vertical: + x = 0; + y = screen->getBevelWidth(); + + for (client = it.current(); client; it++, client = it.current()) { + x = (frame.width - client->width) / 2; + + XMoveResizeWindow(display, client->window, x, y, + client->width, client->height); + XMapWindow(display, client->window); + + // for ICCCM compliance + client->x = x; + client->y = 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->width; + event.xconfigure.height = client->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->height + screen->getBevelWidth(); + } + + break; + + case Horizontal: + x = screen->getBevelWidth(); + y = 0; + + for (client = it.current(); client; it++, client = it.current()) { + y = (frame.height - client->height) / 2; + + XMoveResizeWindow(display, client->window, x, y, + client->width, client->height); + XMapWindow(display, client->window); + + // for ICCCM compliance + client->x = x; + client->y = 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->width; + event.xconfigure.height = client->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->width + screen->getBevelWidth(); + } + + break; + } + + slitmenu->reconfigure(); +} + + +void Slit::reposition(void) { + // place the slit in the appropriate place + switch (screen->getSlitPlacement()) { + case TopLeft: + frame.x = 0; + frame.y = 0; + if (screen->getSlitDirection() == Vertical) { + frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.width; + frame.y_hidden = 0; + } else { + frame.x_hidden = 0; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + } + break; + + case CenterLeft: + frame.x = 0; + frame.y = (screen->getHeight() - frame.height) / 2; + frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.width; + frame.y_hidden = frame.y; + break; + + case BottomLeft: + frame.x = 0; + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + if (screen->getSlitDirection() == Vertical) { + frame.x_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.width; + frame.y_hidden = frame.y; + } else { + frame.x_hidden = 0; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + } + break; + + case TopCenter: + frame.x = (screen->getWidth() - frame.width) / 2; + frame.y = 0; + frame.x_hidden = frame.x; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + break; + + case BottomCenter: + frame.x = (screen->getWidth() - frame.width) / 2; + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + frame.x_hidden = frame.x; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + break; + + case TopRight: + frame.x = screen->getWidth() - frame.width + - (screen->getBorderWidth() * 2); + frame.y = 0; + if (screen->getSlitDirection() == Vertical) { + frame.x_hidden = screen->getWidth() - screen->getBevelWidth() + - screen->getBorderWidth(); + frame.y_hidden = 0; + } else { + frame.x_hidden = frame.x; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + } + break; + + case CenterRight: + default: + frame.x = screen->getWidth() - frame.width + - (screen->getBorderWidth() * 2); + frame.y = (screen->getHeight() - frame.height) / 2; + frame.x_hidden = screen->getWidth() - screen->getBevelWidth() + - screen->getBorderWidth(); + frame.y_hidden = frame.y; + break; + + case BottomRight: + frame.x = screen->getWidth() - frame.width + - (screen->getBorderWidth() * 2); + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + if (screen->getSlitDirection() == Vertical) { + frame.x_hidden = screen->getWidth() - screen->getBevelWidth() + - screen->getBorderWidth(); + frame.y_hidden = frame.y; + } else { + frame.x_hidden = frame.x; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + } + break; + } + + Toolbar *tbar = screen->getToolbar(); + int sw = frame.width + (screen->getBorderWidth() * 2), + sh = frame.height + (screen->getBorderWidth() * 2), + tw = tbar->getWidth() + screen->getBorderWidth(), + th = tbar->getHeight() + screen->getBorderWidth(); + + if (tbar->getX() < frame.x + sw && tbar->getX() + tw > frame.x && + tbar->getY() < frame.y + sh && tbar->getY() + th > frame.y) { + if (frame.y < th) { + frame.y += tbar->getExposedHeight(); + if (screen->getSlitDirection() == Vertical) + frame.y_hidden += tbar->getExposedHeight(); + else + frame.y_hidden = frame.y; + } else { + frame.y -= tbar->getExposedHeight(); + if (screen->getSlitDirection() == Vertical) + frame.y_hidden -= tbar->getExposedHeight(); + else + frame.y_hidden = frame.y; + } + } + + if (hidden) + XMoveResizeWindow(display, frame.window, frame.x_hidden, + frame.y_hidden, frame.width, frame.height); + else + XMoveResizeWindow(display, frame.window, frame.x, + frame.y, frame.width, frame.height); +} + + +void Slit::shutdown(void) { + while (clientList->count()) + removeClient(clientList->first()); +} + + +void Slit::buttonPressEvent(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(XCrossingEvent *) { + if (! do_auto_hide) + return; + + if (hidden) { + if (! timer->isTiming()) timer->start(); + } else { + if (timer->isTiming()) timer->stop(); + } +} + + +void Slit::leaveNotifyEvent(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(XConfigureRequestEvent *e) { + openbox->grab(); + + if (openbox->validateWindow(e->window)) { + Bool reconf = False; + 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); + + LinkedListIterator it(clientList); + SlitClient *client = it.current(); + for (; client; it++, client = it.current()) + if (client->window == e->window) + if (client->width != ((unsigned) e->width) || + client->height != ((unsigned) e->height)) { + client->width = (unsigned) e->width; + client->height = (unsigned) e->height; + + reconf = True; + + break; + } + + if (reconf) reconfigure(); + + } + + openbox->ungrab(); +} + + +void Slit::timeout(void) { + hidden = ! hidden; + if (hidden) + XMoveWindow(display, frame.window, frame.x_hidden, frame.y_hidden); + else + XMoveWindow(display, frame.window, frame.x, frame.y); +} + + +Slitmenu::Slitmenu(Slit *sl) : Basemenu(sl->screen) { + slit = sl; + + setLabel(i18n->getMessage(SlitSet, SlitSlitTitle, "Slit")); + setInternalMenu(); + + directionmenu = new Directionmenu(this); + placementmenu = new Placementmenu(this); + + insert(i18n->getMessage(CommonSet, CommonDirectionTitle, "Direction"), + directionmenu); + insert(i18n->getMessage(CommonSet, CommonPlacementTitle, "Placement"), + placementmenu); + insert(i18n->getMessage(CommonSet, CommonAlwaysOnTop, "Always on top"), 1); + insert(i18n->getMessage(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, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + if (! item) return; + + switch (item->function()) { + case 1: { // always on top + Bool change = ((slit->isOnTop()) ? False : True); + slit->on_top = change; + setItemSelected(2, change); + + if (slit->isOnTop()) slit->screen->raiseWindows((Window *) 0, 0); + break; + } + + case 2: { // auto hide + Bool change = ((slit->doAutoHide()) ? False : True); + slit->do_auto_hide = change; + setItemSelected(3, change); + + 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) { + slitmenu = sm; + + setLabel(i18n->getMessage(SlitSet, SlitSlitDirection, "Slit Direction")); + setInternalMenu(); + + insert(i18n->getMessage(CommonSet, CommonDirectionHoriz, "Horizontal"), + Slit::Horizontal); + insert(i18n->getMessage(CommonSet, CommonDirectionVert, "Vertical"), + Slit::Vertical); + + update(); + + if (sm->slit->screen->getSlitDirection() == Slit::Horizontal) + setItemSelected(0, True); + else + setItemSelected(1, True); +} + + +void Slitmenu::Directionmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + if (! item) return; + + slitmenu->slit->screen->saveSlitDirection(item->function()); + + if (item->function() == Slit::Horizontal) { + setItemSelected(0, True); + setItemSelected(1, False); + } else { + setItemSelected(0, False); + setItemSelected(1, True); + } + + hide(); + slitmenu->slit->reconfigure(); +} + + +Slitmenu::Placementmenu::Placementmenu(Slitmenu *sm) + : Basemenu(sm->slit->screen) { + slitmenu = sm; + + setLabel(i18n->getMessage(SlitSet, SlitSlitPlacement, "Slit Placement")); + setMinimumSublevels(3); + setInternalMenu(); + + insert(i18n->getMessage(CommonSet, CommonPlacementTopLeft, "Top Left"), + Slit::TopLeft); + insert(i18n->getMessage(CommonSet, CommonPlacementCenterLeft, "Center Left"), + Slit::CenterLeft); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomLeft, "Bottom Left"), + Slit::BottomLeft); + insert(i18n->getMessage(CommonSet, CommonPlacementTopCenter, "Top Center"), + Slit::TopCenter); + insert(""); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomCenter, + "Bottom Center"), + Slit::BottomCenter); + insert(i18n->getMessage(CommonSet, CommonPlacementTopRight, "Top Right"), + Slit::TopRight); + insert(i18n->getMessage(CommonSet, CommonPlacementCenterRight, + "Center Right"), + Slit::CenterRight); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomRight, + "Bottom Right"), + Slit::BottomRight); + + update(); +} + + +void Slitmenu::Placementmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + if (! (item && item->function())) return; + + slitmenu->slit->screen->saveSlitPlacement(item->function()); + hide(); + slitmenu->slit->reconfigure(); +} + + +#endif // SLIT diff --git a/src/Slit.h b/src/Slit.h new file mode 100644 index 00000000..1cb89751 --- /dev/null +++ b/src/Slit.h @@ -0,0 +1,159 @@ +// Slit.h for Openbox +// 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 __Slit_hh +#define __Slit_hh + +#include +#include + +#include "Basemenu.h" +#include "LinkedList.h" + +// forward declaration +class Slit; +class Slitmenu; + +class Slitmenu : public Basemenu { +private: + class Directionmenu : public Basemenu { + private: + Slitmenu *slitmenu; + + protected: + virtual void itemSelected(int, int); + + public: + Directionmenu(Slitmenu *); + }; + + class Placementmenu : public Basemenu { + private: + Slitmenu *slitmenu; + + protected: + virtual void itemSelected(int, int); + + public: + Placementmenu(Slitmenu *); + }; + + Directionmenu *directionmenu; + Placementmenu *placementmenu; + + Slit *slit; + + friend class Directionmenu; + friend class Placementmenu; + friend class Slit; + + +protected: + virtual void itemSelected(int, int); + virtual void internal_hide(void); + + +public: + Slitmenu(Slit *); + virtual ~Slitmenu(void); + + inline Basemenu *getDirectionmenu(void) { return directionmenu; } + inline Basemenu *getPlacementmenu(void) { return placementmenu; } + + void reconfigure(void); +}; + + +class Slit : public TimeoutHandler { +private: + class SlitClient { + public: + Window window, client_window, icon_window; + + int x, y; + unsigned int width, height; + }; + + Bool on_top, hidden, do_auto_hide; + Display *display; + + Openbox *openbox; + BScreen *screen; + BTimer *timer; + + LinkedList *clientList; + Slitmenu *slitmenu; + + struct frame { + Pixmap pixmap; + Window window; + + int x, y, x_hidden, y_hidden; + unsigned int width, height; + } frame; + + friend class Slitmenu; + friend class Slitmenu::Directionmenu; + friend class Slitmenu::Placementmenu; + + +public: + Slit(BScreen *); + virtual ~Slit(); + + inline const Bool &isOnTop(void) const { return on_top; } + inline const Bool &isHidden(void) const { return hidden; } + inline const Bool &doAutoHide(void) const { return do_auto_hide; } + + inline Slitmenu *getMenu() { return slitmenu; } + + inline const Window &getWindowID() const { return frame.window; } + + inline const int &getX(void) const + { return ((hidden) ? frame.x_hidden : frame.x); } + inline const int &getY(void) const + { return ((hidden) ? frame.y_hidden : frame.y); } + + inline const unsigned int &getWidth(void) const { return frame.width; } + inline const unsigned int &getHeight(void) const { return frame.height; } + + void addClient(Window); + void removeClient(SlitClient *, Bool = True); + void removeClient(Window, Bool = True); + void reconfigure(void); + void reposition(void); + void shutdown(void); + + void buttonPressEvent(XButtonEvent *); + void enterNotifyEvent(XCrossingEvent *); + void leaveNotifyEvent(XCrossingEvent *); + void configureRequestEvent(XConfigureRequestEvent *); + + 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/Timer.cc b/src/Timer.cc new file mode 100644 index 00000000..95985a01 --- /dev/null +++ b/src/Timer.cc @@ -0,0 +1,76 @@ +// Timer.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "BaseDisplay.h" +#include "Timer.h" + +BTimer::BTimer(BaseDisplay *d, TimeoutHandler *h) { + display = d; + handler = h; + + once = timing = False; +} + +BTimer::~BTimer(void) { + if (timing) stop(); +} + +void BTimer::setTimeout(long t) { + _timeout.tv_sec = t / 1000; + _timeout.tv_usec = t; + _timeout.tv_usec -= (_timeout.tv_sec * 1000); + _timeout.tv_usec *= 1000; +} + +void BTimer::setTimeout(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; + display->addTimer(this); + } +} + +void BTimer::stop(void) { + timing = False; + + display->removeTimer(this); +} + +void BTimer::fireTimeout(void) { + if (handler) handler->timeout(); +} diff --git a/src/Timer.h b/src/Timer.h new file mode 100644 index 00000000..410d658e --- /dev/null +++ b/src/Timer.h @@ -0,0 +1,78 @@ +// Timer.h for Openbox +// 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 __Timer_hh +#define __Timer_hh + +#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 BTimer; +class TimeoutHandler; +class BaseDisplay; + +class TimeoutHandler { +public: + virtual void timeout(void) = 0; +}; + +class BTimer { + friend class BaseDisplay; +private: + BaseDisplay *display; + TimeoutHandler *handler; + int timing, once; + + timeval _start, _timeout; + +protected: + void fireTimeout(void); + +public: + BTimer(BaseDisplay *, TimeoutHandler *); + virtual ~BTimer(void); + + inline const int &isTiming(void) const { return timing; } + inline const int &doOnce(void) const { return once; } + + inline const timeval &getTimeout(void) const { return _timeout; } + inline const timeval &getStartTime(void) const { return _start; } + + inline void fireOnce(int o) { once = o; } + + void setTimeout(long); + void setTimeout(timeval); + void start(void); + void stop(void); +}; + +#endif // __Timer_hh + diff --git a/src/Toolbar.cc b/src/Toolbar.cc new file mode 100644 index 00000000..d2e39c85 --- /dev/null +++ b/src/Toolbar.cc @@ -0,0 +1,1260 @@ +// Toolbar.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "openbox.h" +#include "Clientmenu.h" +#include "Iconmenu.h" +#include "Rootmenu.h" +#include "Screen.h" +#include "Toolbar.h" +#include "Window.h" +#include "Workspace.h" +#include "Workspacemenu.h" + +#include +#include + +#ifdef STDC_HEADERS +# include +#endif // STDC_HEADERS + +#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 + + +Toolbar::Toolbar(BScreen *scrn) { + screen = scrn; + openbox = screen->getOpenbox(); + + // get the clock updating every minute + clock_timer = new BTimer(openbox, this); + timeval now; + gettimeofday(&now, 0); + clock_timer->setTimeout((60 - (now.tv_sec % 60)) * 1000); + clock_timer->start(); + + hide_handler.toolbar = this; + hide_timer = new BTimer(openbox, &hide_handler); + hide_timer->setTimeout(openbox->getAutoRaiseDelay()); + hide_timer->fireOnce(True); + + image_ctrl = screen->getImageControl(); + + on_top = screen->isToolbarOnTop(); + hidden = do_auto_hide = screen->doToolbarAutoHide(); + + editing = False; + new_workspace_name = (char *) 0; + new_name_pos = 0; + frame.grab_x = frame.grab_y = 0; + + toolbarmenu = new Toolbarmenu(this); + + display = openbox->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()->getPixel(); + 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); + openbox->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); + openbox->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); + openbox->saveToolbarSearch(frame.window_label, this); + + frame.clock = + XCreateWindow(display, frame.window, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, &attrib); + openbox->saveToolbarSearch(frame.clock, this); + + frame.psbutton = + XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, &attrib); + openbox->saveToolbarSearch(frame.psbutton, this); + + frame.nsbutton = + XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, &attrib); + openbox->saveToolbarSearch(frame.nsbutton, this); + + frame.pwbutton = + XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, &attrib); + openbox->saveToolbarSearch(frame.pwbutton, this); + + frame.nwbutton = + XCreateWindow(display ,frame.window, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, &attrib); + openbox->saveToolbarSearch(frame.nwbutton, this); + + frame.base = frame.label = frame.wlabel = frame.clk = frame.button = + frame.pbutton = None; + + reconfigure(); + + XMapSubwindows(display, frame.window); + XMapWindow(display, frame.window); +} + + +Toolbar::~Toolbar(void) { + XUnmapWindow(display, frame.window); + + if (frame.base) image_ctrl->removeImage(frame.base); + if (frame.label) image_ctrl->removeImage(frame.label); + if (frame.wlabel) image_ctrl->removeImage(frame.wlabel); + if (frame.clk) image_ctrl->removeImage(frame.clk); + if (frame.button) image_ctrl->removeImage(frame.button); + if (frame.pbutton) image_ctrl->removeImage(frame.pbutton); + + openbox->removeToolbarSearch(frame.window); + openbox->removeToolbarSearch(frame.workspace_label); + openbox->removeToolbarSearch(frame.window_label); + openbox->removeToolbarSearch(frame.clock); + openbox->removeToolbarSearch(frame.psbutton); + openbox->removeToolbarSearch(frame.nsbutton); + openbox->removeToolbarSearch(frame.pwbutton); + openbox->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::reconfigure(void) { + frame.bevel_w = screen->getBevelWidth(); + frame.width = screen->getWidth() * screen->getToolbarWidthPercent() / 100; + + if (i18n->multibyte()) + frame.height = + screen->getToolbarStyle()->fontset_extents->max_ink_extent.height; + else + frame.height = screen->getToolbarStyle()->font->ascent + + screen->getToolbarStyle()->font->descent; + frame.button_w = frame.height; + frame.height += 2; + frame.label_h = frame.height; + frame.height += (frame.bevel_w * 2); + + switch (screen->getToolbarPlacement()) { + case TopLeft: + frame.x = 0; + frame.y = 0; + frame.x_hidden = 0; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + break; + + case BottomLeft: + frame.x = 0; + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + frame.x_hidden = 0; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + break; + + case TopCenter: + frame.x = (screen->getWidth() - frame.width) / 2; + frame.y = 0; + frame.x_hidden = frame.x; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + break; + + case BottomCenter: + default: + frame.x = (screen->getWidth() - frame.width) / 2; + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + frame.x_hidden = frame.x; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + break; + + case TopRight: + frame.x = screen->getWidth() - frame.width + - (screen->getBorderWidth() * 2); + frame.y = 0; + frame.x_hidden = frame.x; + frame.y_hidden = screen->getBevelWidth() - screen->getBorderWidth() + - frame.height; + break; + + case BottomRight: + frame.x = screen->getWidth() - frame.width + - (screen->getBorderWidth() * 2); + frame.y = screen->getHeight() - frame.height + - (screen->getBorderWidth() * 2); + frame.x_hidden = frame.x; + frame.y_hidden = screen->getHeight() - screen->getBevelWidth() + - screen->getBorderWidth(); + break; + } + +#ifdef HAVE_STRFTIME + time_t ttmp = time(NULL); + struct tm *tt = 0; + + if (ttmp != -1) { + tt = localtime(&ttmp); + if (tt) { + char t[1024], *time_string = (char *) 0; + int len = strftime(t, 1024, screen->getStrftimeFormat(), tt); + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, t, len, &ink, + &logical); + frame.clock_w = logical.width; + + // ben's additional solution to pad some space beside the numbers + frame.clock_w += + screen->getToolbarStyle()->fontset_extents->max_logical_extent.width * + 4; + + // brad's solution, which is currently buggy, too big + //frame.clock_w = + // screen->getToolbarStyle()->fontset_extents->max_logical_extent.width + // * len; + } else { + frame.clock_w = XTextWidth(screen->getToolbarStyle()->font, t, len); + // ben's additional solution to pad some space beside the numbers + frame.clock_w += screen->getToolbarStyle()->font->max_bounds.width * 4; + // brad's solution again, too big + //frame.clock_w = screen->getToolbarStyle()->font->max_bounds.width * len; + } + frame.clock_w += (frame.bevel_w * 4); + + delete [] time_string; + } else { + frame.clock_w = 0; + } + } else { + frame.clock_w = 0; + } +#else // !HAVE_STRFTIME + frame.clock_w = + XTextWidth(screen->getToolbarStyle()->font, + i18n->getMessage(ToolbarSet, ToolbarNoStrftimeLength, + "00:00000"), + strlen(i18n->getMessage(ToolbarSet, ToolbarNoStrftimeLength, + "00:00000"))) + (frame.bevel_w * 4); +#endif // HAVE_STRFTIME + + int i; + unsigned int w = 0; + frame.workspace_label_w = 0; + + for (i = 0; i < screen->getCount(); i++) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + screen->getWorkspace(i)->getName(), + strlen(screen->getWorkspace(i)->getName()), + &ink, &logical); + w = logical.width; + } else { + w = XTextWidth(screen->getToolbarStyle()->font, + screen->getWorkspace(i)->getName(), + strlen(screen->getWorkspace(i)->getName())); + } + w += (frame.bevel_w * 4); + + if (w > frame.workspace_label_w) frame.workspace_label_w = w; + } + + if (frame.workspace_label_w < frame.clock_w) + frame.workspace_label_w = frame.clock_w; + else if (frame.workspace_label_w > frame.clock_w) + frame.clock_w = frame.workspace_label_w; + + frame.window_label_w = + (frame.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.width, frame.height); + } else { + XMoveResizeWindow(display, frame.window, frame.x, frame.y, + frame.width, frame.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.width - frame.clock_w - + frame.bevel_w, frame.bevel_w, frame.clock_w, + frame.label_h); + + Pixmap tmp = frame.base; + BTexture *texture = &(screen->getToolbarStyle()->toolbar); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.base = None; + XSetWindowBackground(display, frame.window, + texture->getColor()->getPixel()); + } else { + frame.base = + image_ctrl->renderImage(frame.width, frame.height, texture); + XSetWindowBackgroundPixmap(display, frame.window, frame.base); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.label; + texture = &(screen->getToolbarStyle()->window); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.label = None; + XSetWindowBackground(display, frame.window_label, + texture->getColor()->getPixel()); + } else { + frame.label = + image_ctrl->renderImage(frame.window_label_w, frame.label_h, texture); + XSetWindowBackgroundPixmap(display, frame.window_label, frame.label); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.wlabel; + texture = &(screen->getToolbarStyle()->label); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.wlabel = None; + XSetWindowBackground(display, frame.workspace_label, + texture->getColor()->getPixel()); + } else { + frame.wlabel = + image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture); + XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.clk; + texture = &(screen->getToolbarStyle()->clock); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.clk = None; + XSetWindowBackground(display, frame.clock, + texture->getColor()->getPixel()); + } else { + frame.clk = + image_ctrl->renderImage(frame.clock_w, frame.label_h, texture); + XSetWindowBackgroundPixmap(display, frame.clock, frame.clk); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.button; + texture = &(screen->getToolbarStyle()->button); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.button = None; + + frame.button_pixel = texture->getColor()->getPixel(); + 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 { + frame.button = + image_ctrl->renderImage(frame.button_w, frame.button_w, texture); + + XSetWindowBackgroundPixmap(display, frame.psbutton, frame.button); + XSetWindowBackgroundPixmap(display, frame.nsbutton, frame.button); + XSetWindowBackgroundPixmap(display, frame.pwbutton, frame.button); + XSetWindowBackgroundPixmap(display, frame.nwbutton, frame.button); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.pbutton; + texture = &(screen->getToolbarStyle()->pressed); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.pbutton = None; + frame.pbutton_pixel = texture->getColor()->getPixel(); + } else { + frame.pbutton = + image_ctrl->renderImage(frame.button_w, frame.button_w, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + XSetWindowBorder(display, frame.window, + screen->getBorderColor()->getPixel()); + 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(); +} + + +#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() == Openbox::B_EuropeanDate) + sprintf(t, 18n->getMessage(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->getMessage(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->getMessage(ToolbarSet, ToolbarNoStrftimeTimeFormat24, + " %02d:%02d "), + frame.hour, frame.minute); + else + sprintf(t, i18n->getMessage(ToolbarSet, ToolbarNoStrftimeTimeFormat12, + "%02d:%02d %sm"), + ((frame.hour > 12) ? frame.hour - 12 : + ((frame.hour == 0) ? 12 : frame.hour)), frame.minute, + ((frame.hour >= 12) ? + i18n->getMessage(ToolbarSet, + ToolbarNoStrftimeTimeFormatP, "p") : + i18n->getMessage(ToolbarSet, + ToolbarNoStrftimeTimeFormatA, "a"))); + } +#endif // HAVE_STRFTIME + + int dx = (frame.bevel_w * 2), dlen = strlen(t); + unsigned int l; + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + t, dlen, &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getToolbarStyle()->font, t, dlen); + } + + l += (frame.bevel_w * 4); + + if (l > frame.clock_w) { + for (; dlen >= 0; dlen--) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + t, dlen, &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getToolbarStyle()->font, t, dlen); + } + l+= (frame.bevel_w * 4); + + if (l < frame.clock_w) + break; + } + } + switch (screen->getToolbarStyle()->justify) { + case BScreen::RightJustify: + dx += frame.clock_w - l; + break; + + case BScreen::CenterJustify: + dx += (frame.clock_w - l) / 2; + break; + } + + ToolbarStyle *style = screen->getToolbarStyle(); + if (i18n->multibyte()) + XmbDrawString(display, frame.clock, style->fontset, style->c_text_gc, + dx, (1 - style->fontset_extents->max_ink_extent.y), + t, dlen); + else + XDrawString(display, frame.clock, style->c_text_gc, dx, + (style->font->ascent + 1), t, dlen); + } +} + + +void Toolbar::redrawWindowLabel(Bool redraw) { + if (screen->getOpenbox()->getFocusedWindow()) { + if (redraw) + XClearWindow(display, frame.window_label); + + OpenboxWindow *foc = screen->getOpenbox()->getFocusedWindow(); + if (foc->getScreen() != screen) return; + + int dx = (frame.bevel_w * 2), dlen = strlen(*foc->getTitle()); + unsigned int l; + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, *foc->getTitle(), + dlen, &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getToolbarStyle()->font, *foc->getTitle(), dlen); + } + l += (frame.bevel_w * 4); + + if (l > frame.window_label_w) { + for (; dlen >= 0; dlen--) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + *foc->getTitle(), dlen, &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getToolbarStyle()->font, + *foc->getTitle(), dlen); + } + l += (frame.bevel_w * 4); + + if (l < frame.window_label_w) + break; + } + } + switch (screen->getToolbarStyle()->justify) { + case BScreen::RightJustify: + dx += frame.window_label_w - l; + break; + + case BScreen::CenterJustify: + dx += (frame.window_label_w - l) / 2; + break; + } + + ToolbarStyle *style = screen->getToolbarStyle(); + if (i18n->multibyte()) + XmbDrawString(display, frame.window_label, style->fontset, + style->w_text_gc, dx, + (1 - style->fontset_extents->max_ink_extent.y), + *foc->getTitle(), dlen); + else + XDrawString(display, frame.window_label, style->w_text_gc, dx, + (style->font->ascent + 1), *foc->getTitle(), dlen); + } else { + XClearWindow(display, frame.window_label); + } +} + + +void Toolbar::redrawWorkspaceLabel(Bool redraw) { + if (screen->getCurrentWorkspace()->getName()) { + if (redraw) + XClearWindow(display, frame.workspace_label); + + int dx = (frame.bevel_w * 2), dlen = + strlen(screen->getCurrentWorkspace()->getName()); + unsigned int l; + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + screen->getCurrentWorkspace()->getName(), dlen, + &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getToolbarStyle()->font, + screen->getCurrentWorkspace()->getName(), dlen); + } + l += (frame.bevel_w * 4); + + if (l > frame.workspace_label_w) { + for (; dlen >= 0; dlen--) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + screen->getCurrentWorkspace()->getName(), dlen, + &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getWindowStyle()->font, + screen->getCurrentWorkspace()->getName(), dlen); + } + l += (frame.bevel_w * 4); + + if (l < frame.workspace_label_w) + break; + } + } + switch (screen->getToolbarStyle()->justify) { + case BScreen::RightJustify: + dx += frame.workspace_label_w - l; + break; + + case BScreen::CenterJustify: + dx += (frame.workspace_label_w - l) / 2; + break; + } + + ToolbarStyle *style = screen->getToolbarStyle(); + if (i18n->multibyte()) + XmbDrawString(display, frame.workspace_label, style->fontset, + style->l_text_gc, dx, + (1 - style->fontset_extents->max_ink_extent.y), + (char *) screen->getCurrentWorkspace()->getName(), dlen); + else + XDrawString(display, frame.workspace_label, style->l_text_gc, dx, + (style->font->ascent + 1), + (char *) screen->getCurrentWorkspace()->getName(), dlen); + } +} + + +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); + } + + int hh = frame.button_w / 2, hw = frame.button_w / 2; + + XPoint pts[3]; + pts[0].x = hw - 2; pts[0].y = hh; + pts[1].x = 4; pts[1].y = 2; + pts[2].x = 0; pts[2].y = -4; + + XFillPolygon(display, frame.psbutton, screen->getToolbarStyle()->b_pic_gc, + pts, 3, Convex, CoordModePrevious); +} + + +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); + } + + int hh = frame.button_w / 2, hw = frame.button_w / 2; + + XPoint pts[3]; + pts[0].x = hw - 2; pts[0].y = hh - 2; + pts[1].x = 4; pts[1].y = 2; + pts[2].x = -4; pts[2].y = 2; + + XFillPolygon(display, frame.nsbutton, screen->getToolbarStyle()->b_pic_gc, + pts, 3, Convex, CoordModePrevious); +} + + +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); + } + + int hh = frame.button_w / 2, hw = frame.button_w / 2; + + XPoint pts[3]; + pts[0].x = hw - 2; pts[0].y = hh; + pts[1].x = 4; pts[1].y = 2; + pts[2].x = 0; pts[2].y = -4; + + XFillPolygon(display, frame.pwbutton, screen->getToolbarStyle()->b_pic_gc, + pts, 3, Convex, CoordModePrevious); +} + + +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); + } + + int hh = frame.button_w / 2, hw = frame.button_w / 2; + + XPoint pts[3]; + pts[0].x = hw - 2; pts[0].y = hh - 2; + pts[1].x = 4; pts[1].y = 2; + pts[2].x = -4; pts[2].y = 2; + + XFillPolygon(display, frame.nwbutton, screen->getToolbarStyle()->b_pic_gc, + pts, 3, Convex, CoordModePrevious); +} + + +void Toolbar::edit(void) { + Window window; + int foo; + + editing = True; + if (XGetInputFocus(display, &window, &foo) && + window == frame.workspace_label) + return; + + XSetInputFocus(display, frame.workspace_label, + ((screen->isSloppyFocus()) ? RevertToPointerRoot : + RevertToParent), + CurrentTime); + XClearWindow(display, frame.workspace_label); + + openbox->setNoFocus(True); + if (openbox->getFocusedWindow()) + openbox->getFocusedWindow()->setFocusFlag(False); + + XDrawRectangle(display, frame.workspace_label, + screen->getWindowStyle()->l_text_focus_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 + Pixmap tmp = frame.wlabel; + BTexture *texture = &(screen->getWindowStyle()->l_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.wlabel = None; + XSetWindowBackground(display, frame.workspace_label, + texture->getColor()->getPixel()); + } else { + frame.wlabel = + image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture); + XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel); + } + if (tmp) image_ctrl->removeImage(tmp); +} + + +void Toolbar::buttonPressEvent(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()) { + 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(); + } else + toolbarmenu->hide(); + } +} + + + +void Toolbar::buttonReleaseEvent(XButtonEvent *re) { + if (re->button == 1) { + if (re->window == frame.psbutton) { + redrawPrevWorkspaceButton(False, True); + + if (re->x >= 0 && re->x < (signed) frame.button_w && + re->y >= 0 && re->y < (signed) frame.button_w) + if (screen->getCurrentWorkspace()->getWorkspaceID() > 0) + screen->changeWorkspaceID(screen->getCurrentWorkspace()-> + getWorkspaceID() - 1); + else + screen->changeWorkspaceID(screen->getCount() - 1); + } else if (re->window == frame.nsbutton) { + redrawNextWorkspaceButton(False, True); + + if (re->x >= 0 && re->x < (signed) frame.button_w && + re->y >= 0 && re->y < (signed) frame.button_w) + if (screen->getCurrentWorkspace()->getWorkspaceID() < + screen->getCount() - 1) + screen->changeWorkspaceID(screen->getCurrentWorkspace()-> + getWorkspaceID() + 1); + else + screen->changeWorkspaceID(0); + } else if (re->window == frame.pwbutton) { + redrawPrevWindowButton(False, True); + + if (re->x >= 0 && re->x < (signed) frame.button_w && + re->y >= 0 && re->y < (signed) frame.button_w) + screen->prevFocus(); + } else if (re->window == frame.nwbutton) { + redrawNextWindowButton(False, True); + + if (re->x >= 0 && re->x < (signed) frame.button_w && + re->y >= 0 && re->y < (signed) 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(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(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(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(XKeyEvent *ke) { + if (ke->window == frame.workspace_label && editing) { + openbox->grab(); + + if (! new_workspace_name) { + new_workspace_name = new char[128]; + new_name_pos = 0; + + if (! new_workspace_name) return; + } + + KeySym ks; + char keychar[1]; + XLookupString(ke, keychar, 1, &ks, 0); + + // either we are told to end with a return or we hit the end of the buffer + if (ks == XK_Return || new_name_pos == 127) { + *(new_workspace_name + new_name_pos) = 0; + + editing = False; + + openbox->setNoFocus(False); + if (openbox->getFocusedWindow()) { + openbox->getFocusedWindow()->setInputFocus(); + openbox->getFocusedWindow()->setFocusFlag(True); + } else { + XSetInputFocus(display, PointerRoot, None, CurrentTime); + } + // check to make sure that new_name[0] != 0... otherwise we have a null + // workspace name which causes serious problems, especially for the + // Openbox::LoadRC() method. + if (*new_workspace_name) { + screen->getCurrentWorkspace()->setName(new_workspace_name); + screen->getCurrentWorkspace()->getMenu()->hide(); + screen->getWorkspacemenu()-> + remove(screen->getCurrentWorkspace()->getWorkspaceID() + 2); + screen->getWorkspacemenu()-> + insert(screen->getCurrentWorkspace()->getName(), + screen->getCurrentWorkspace()->getMenu(), + screen->getCurrentWorkspace()->getWorkspaceID() + 2); + screen->getWorkspacemenu()->update(); + } + + delete [] new_workspace_name; + new_workspace_name = (char *) 0; + new_name_pos = 0; + + // reset the background to that of the workspace label (its normal + // setting) + Pixmap tmp = frame.wlabel; + BTexture *texture = &(screen->getToolbarStyle()->label); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.wlabel = None; + XSetWindowBackground(display, frame.workspace_label, + texture->getColor()->getPixel()); + } else { + frame.wlabel = + image_ctrl->renderImage(frame.workspace_label_w, frame.label_h, texture); + XSetWindowBackgroundPixmap(display, frame.workspace_label, frame.wlabel); + } + if (tmp) image_ctrl->removeImage(tmp); + + reconfigure(); + } 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 + new_name_pos) = '\0'; + } else { + *new_workspace_name = '\0'; + } + } else { + *(new_workspace_name + new_name_pos) = *keychar; + ++new_name_pos; + *(new_workspace_name + new_name_pos) = '\0'; + } + + XClearWindow(display, frame.workspace_label); + int l = strlen(new_workspace_name), tw, x; + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getToolbarStyle()->fontset, + new_workspace_name, l, &ink, &logical); + tw = logical.width; + } else { + tw = XTextWidth(screen->getToolbarStyle()->font, + new_workspace_name, l); + } + x = (frame.workspace_label_w - tw) / 2; + + if (x < (signed) frame.bevel_w) x = frame.bevel_w; + + WindowStyle *style = screen->getWindowStyle(); + if (i18n->multibyte()) + XmbDrawString(display, frame.workspace_label, style->fontset, + style->l_text_focus_gc, x, + (1 - style->fontset_extents->max_ink_extent.y), + new_workspace_name, l); + else + XDrawString(display, frame.workspace_label, style->l_text_focus_gc, x, + (style->font->ascent + 1), + new_workspace_name, l); + + XDrawRectangle(display, frame.workspace_label, + screen->getWindowStyle()->l_text_focus_gc, x + tw, 0, 1, + frame.label_h - 1); + } + + openbox->ungrab(); + } +} + + +void Toolbar::timeout(void) { + checkClock(True); + + timeval now; + gettimeofday(&now, 0); + clock_timer->setTimeout((60 - (now.tv_sec % 60)) * 1000); +} + + +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.x, toolbar->frame.y); +} + + +Toolbarmenu::Toolbarmenu(Toolbar *tb) : Basemenu(tb->screen) { + toolbar = tb; + + setLabel(i18n->getMessage(ToolbarSet, ToolbarToolbarTitle, "Toolbar")); + setInternalMenu(); + + placementmenu = new Placementmenu(this); + + insert(i18n->getMessage(CommonSet, CommonPlacementTitle, "Placement"), + placementmenu); + insert(i18n->getMessage(CommonSet, CommonAlwaysOnTop, "Always on top"), 1); + insert(i18n->getMessage(CommonSet, CommonAutoHide, "Auto hide"), 2); + insert(i18n->getMessage(ToolbarSet, ToolbarEditWkspcName, + "Edit current workspace name"), 3); + + update(); + + if (toolbar->isOnTop()) setItemSelected(1, True); + if (toolbar->doAutoHide()) setItemSelected(2, True); +} + + +Toolbarmenu::~Toolbarmenu(void) { + delete placementmenu; +} + + +void Toolbarmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + if (! item) return; + + switch (item->function()) { + case 1: { // always on top + Bool change = ((toolbar->isOnTop()) ? False : True); + toolbar->on_top = change; + setItemSelected(1, change); + + if (toolbar->isOnTop()) toolbar->screen->raiseWindows((Window *) 0, 0); + break; + } + + case 2: { // auto hide + Bool change = ((toolbar->doAutoHide()) ? False : True); + toolbar->do_auto_hide = change; + setItemSelected(2, change); + +#ifdef SLIT + toolbar->screen->getSlit()->reposition(); +#endif // SLIT + 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) { + placementmenu->reconfigure(); + + Basemenu::reconfigure(); +} + + +Toolbarmenu::Placementmenu::Placementmenu(Toolbarmenu *tm) + : Basemenu(tm->toolbar->screen) { + toolbarmenu = tm; + + setLabel(i18n->getMessage(ToolbarSet, ToolbarToolbarPlacement, + "Toolbar Placement")); + setInternalMenu(); + setMinimumSublevels(3); + + insert(i18n->getMessage(CommonSet, CommonPlacementTopLeft, + "Top Left"), Toolbar::TopLeft); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomLeft, + "Bottom Left"), Toolbar::BottomLeft); + insert(i18n->getMessage(CommonSet, CommonPlacementTopCenter, + "Top Center"), Toolbar::TopCenter); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomCenter, + "Bottom Center"), Toolbar::BottomCenter); + insert(i18n->getMessage(CommonSet, CommonPlacementTopRight, + "Top Right"), Toolbar::TopRight); + insert(i18n->getMessage(CommonSet, CommonPlacementBottomRight, + "Bottom Right"), Toolbar::BottomRight); + update(); +} + + +void Toolbarmenu::Placementmenu::itemSelected(int button, int index) { + if (button != 1) + return; + + BasemenuItem *item = find(index); + if (! item) return; + + toolbarmenu->toolbar->screen->saveToolbarPlacement(item->function()); + hide(); + toolbarmenu->toolbar->reconfigure(); + +#ifdef SLIT + // reposition the slit as well to make sure it doesn't intersect the + // toolbar + toolbarmenu->toolbar->screen->getSlit()->reposition(); +#endif // SLIT +} diff --git a/src/Toolbar.h b/src/Toolbar.h new file mode 100644 index 00000000..17c46984 --- /dev/null +++ b/src/Toolbar.h @@ -0,0 +1,156 @@ +// Toolbar.h for Openbox +// 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 __Toolbar_hh +#define __Toolbar_hh + +#include + +#include "Basemenu.h" +#include "Timer.h" + +// forward declaration +class Toolbar; + +class Toolbarmenu : public Basemenu { +private: + class Placementmenu : public Basemenu { + private: + Toolbarmenu *toolbarmenu; + + protected: + virtual void itemSelected(int, int); + + public: + Placementmenu(Toolbarmenu *); + }; + + Toolbar *toolbar; + Placementmenu *placementmenu; + + friend class Placementmenu; + friend class Toolbar; + + +protected: + virtual void itemSelected(int, int); + virtual void internal_hide(void); + +public: + Toolbarmenu(Toolbar *); + ~Toolbarmenu(void); + + inline Basemenu *getPlacementmenu(void) { return placementmenu; } + + void reconfigure(void); +}; + + +class Toolbar : public TimeoutHandler { +private: + Bool on_top, editing, hidden, do_auto_hide; + Display *display; + + struct frame { + 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, y, x_hidden, y_hidden, hour, minute, grab_x, grab_y; + unsigned int width, height, window_label_w, workspace_label_w, clock_w, + button_w, bevel_w, label_h; + } frame; + + class HideHandler : public TimeoutHandler { + public: + Toolbar *toolbar; + + virtual void timeout(void); + } hide_handler; + + Openbox *openbox; + BImageControl *image_ctrl; + BScreen *screen; + BTimer *clock_timer, *hide_timer; + Toolbarmenu *toolbarmenu; + + char *new_workspace_name; + size_t new_name_pos; + + friend class HideHandler; + friend class Toolbarmenu; + friend class Toolbarmenu::Placementmenu; + + +public: + Toolbar(BScreen *); + virtual ~Toolbar(void); + + inline Toolbarmenu *getMenu(void) { return toolbarmenu; } + + inline const Bool &isEditing(void) const { return editing; } + inline const Bool &isOnTop(void) const { return on_top; } + inline const Bool &isHidden(void) const { return hidden; } + inline const Bool &doAutoHide(void) const { return do_auto_hide; } + + inline const Window &getWindowID(void) const { return frame.window; } + + inline const unsigned int &getWidth(void) const { return frame.width; } + inline const unsigned int &getHeight(void) const { return frame.height; } + inline const unsigned int &getExposedHeight(void) const + { return ((do_auto_hide) ? frame.bevel_w : frame.height); } + inline const int &getX(void) const + { return ((hidden) ? frame.x_hidden : frame.x); } + inline const int &getY(void) const + { return ((hidden) ? frame.y_hidden : frame.y); } + + void buttonPressEvent(XButtonEvent *); + void buttonReleaseEvent(XButtonEvent *); + void enterNotifyEvent(XCrossingEvent *); + void leaveNotifyEvent(XCrossingEvent *); + void exposeEvent(XExposeEvent *); + void keyPressEvent(XKeyEvent *); + + void redrawWindowLabel(Bool = False); + void redrawWorkspaceLabel(Bool = False); + void redrawPrevWorkspaceButton(Bool = False, Bool = False); + void redrawNextWorkspaceButton(Bool = False, Bool = False); + void redrawPrevWindowButton(Bool = False, Bool = False); + void redrawNextWindowButton(Bool = False, Bool = False); + void edit(void); + void reconfigure(void); + +#ifdef HAVE_STRFTIME + void checkClock(Bool = False); +#else // HAVE_STRFTIME + void checkClock(Bool = False, Bool = False); +#endif // HAVE_STRFTIME + + virtual void timeout(void); + + enum { TopLeft = 1, BottomLeft, TopCenter, + BottomCenter, TopRight, BottomRight }; +}; + + +#endif // __Toolbar_hh diff --git a/src/Window.cc b/src/Window.cc new file mode 100644 index 00000000..4133ac00 --- /dev/null +++ b/src/Window.cc @@ -0,0 +1,3244 @@ +// Window.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include +#include + +#ifdef STDC_HEADERS +# include +#endif // STDC_HEADERS + +#ifdef DEBUG +# ifdef HAVE_STDIO_H +# include +# endif // HAVE_STDIO_H +#endif // DEBUG + +#include "i18n.h" +#include "openbox.h" +#include "Iconmenu.h" +#include "Screen.h" +#include "Toolbar.h" +#include "Window.h" +#include "Windowmenu.h" +#include "Workspace.h" +#ifdef SLIT +# include "Slit.h" +#endif // SLIT + +/* + * Initializes the class with default values/the window's set initial values. + */ +OpenboxWindow::OpenboxWindow(Openbox *b, Window w, BScreen *s) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(WindowSet, WindowCreating, + "OpenboxWindow::OpenboxWindow(): creating 0x%lx\n"), + w); +#endif // DEBUG + + client.window = w; + openbox = b; + display = openbox->getXDisplay(); + + openbox->grab(); + if (! validateClient()) return; + + // fetch client size and placement + XWindowAttributes wattrib; + if ((! XGetWindowAttributes(display, client.window, &wattrib)) || + (! wattrib.screen) || wattrib.override_redirect) { +#ifdef DEBUG + fprintf(stderr, + i18n->getMessage(WindowSet, WindowXGetWindowAttributesFail, + "OpenboxWindow::OpenboxWindow(): XGetWindowAttributes " + "failed\n")); +#endif // DEBUG + + b->ungrab(); + return; + } + + if (s) { + screen = s; + } else { + screen = openbox->searchScreen(RootWindowOfScreen(wattrib.screen)); + if (! screen) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(WindowSet, WindowCannotFindScreen, + "OpenboxWindow::OpenboxWindow(): can't find screen\n" + "\tfor root window 0x%lx\n"), + RootWindowOfScreen(wattrib.screen)); +#endif // DEBUG + + b->ungrab(); + return; + } + } + + flags.moving = flags.resizing = flags.shaded = flags.visible = + flags.iconic = flags.transient = flags.focused = + flags.stuck = flags.modal = flags.send_focus_message = + flags.shaped = flags.managed = False; + flags.maximized = 0; + + openbox_attrib.workspace = workspace_number = window_number = -1; + + openbox_attrib.flags = openbox_attrib.attrib = openbox_attrib.stack + = openbox_attrib.decoration = 0l; + openbox_attrib.premax_x = openbox_attrib.premax_y = 0; + openbox_attrib.premax_w = openbox_attrib.premax_h = 0; + + frame.window = frame.plate = frame.title = frame.handle = None; + frame.close_button = frame.iconify_button = frame.maximize_button = None; + frame.right_grip = frame.left_grip = None; + + frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None; + frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None; + frame.pbutton = frame.ugrip = frame.fgrip = None; + + decorations.titlebar = decorations.border = decorations.handle = True; + decorations.iconify = decorations.maximize = decorations.menu = True; + functions.resize = functions.move = functions.iconify = + functions.maximize = True; + functions.close = decorations.close = False; + + client.wm_hint_flags = client.normal_hint_flags = 0; + client.transient_for = client.transient = 0; + client.title = 0; + client.title_len = 0; + client.icon_title = 0; + client.mwm_hint = (MwmHints *) 0; + client.openbox_hint = (OpenboxHints *) 0; + + // get 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.x = wattrib.x; + client.y = wattrib.y; + client.width = wattrib.width; + client.height = wattrib.height; + client.old_bw = wattrib.border_width; + + windowmenu = 0; + lastButtonPressTime = 0; + image_ctrl = screen->getImageControl(); + + timer = new BTimer(openbox, this); + timer->setTimeout(openbox->getAutoRaiseDelay()); + timer->fireOnce(True); + + getOpenboxHints(); + if (! client.openbox_hint) + getMWMHints(); + + // get size, aspect, minimum/maximum size and other hints set by the + // client + getWMProtocols(); + getWMHints(); + getWMNormalHints(); + +#ifdef SLIT + if (client.initial_state == WithdrawnState) { + screen->getSlit()->addClient(client.window); + delete this; + + b->ungrab(); + return; + } +#endif // SLIT + + flags.managed = True; + openbox->saveWindowSearch(client.window, this); + + // determine if this is a transient window + Window win; + if (XGetTransientForHint(display, client.window, &win)) { + if (win && (win != client.window)) { + OpenboxWindow *tr; + if ((tr = openbox->searchWindow(win))) { + while (tr->client.transient) tr = tr->client.transient; + client.transient_for = tr; + tr->client.transient = this; + flags.stuck = client.transient_for->flags.stuck; + flags.transient = True; + } else if (win == client.window_group) { + if ((tr = openbox->searchGroup(win, this))) { + while (tr->client.transient) tr = tr->client.transient; + client.transient_for = tr; + tr->client.transient = this; + flags.stuck = client.transient_for->flags.stuck; + flags.transient = True; + } + } + } + + if (win == screen->getRootWindow()) flags.modal = True; + } + + // adjust the window decorations based on transience and window sizes + if (flags.transient) + decorations.maximize = decorations.handle = functions.maximize = False; + + if ((client.normal_hint_flags & PMinSize) && + (client.normal_hint_flags & PMaxSize) && + client.max_width <= client.min_width && + client.max_height <= client.min_height) { + decorations.maximize = decorations.handle = + functions.resize = functions.maximize = False; + } + upsize(); + + Bool place_window = True; + if (openbox->isStartup() || flags.transient || + client.normal_hint_flags & (PPosition|USPosition)) { + setGravityOffsets(); + + if ((openbox->isStartup()) || + (frame.x >= 0 && + (signed) (frame.y + frame.y_border) >= 0 && + frame.x <= (signed) screen->getWidth() && + frame.y <= (signed) screen->getHeight())) + place_window = False; + } + + frame.window = createToplevelWindow(frame.x, frame.y, frame.width, + frame.height, + frame.border_w); + openbox->saveWindowSearch(frame.window, this); + + frame.plate = createChildWindow(frame.window); + openbox->saveWindowSearch(frame.plate, this); + + if (decorations.titlebar) { + frame.title = createChildWindow(frame.window); + frame.label = createChildWindow(frame.title); + openbox->saveWindowSearch(frame.title, this); + openbox->saveWindowSearch(frame.label, this); + } + + if (decorations.handle) { + frame.handle = createChildWindow(frame.window); + openbox->saveWindowSearch(frame.handle, this); + + frame.left_grip = + createChildWindow(frame.handle, openbox->getLowerLeftAngleCursor()); + openbox->saveWindowSearch(frame.left_grip, this); + + frame.right_grip = + createChildWindow(frame.handle, openbox->getLowerRightAngleCursor()); + openbox->saveWindowSearch(frame.right_grip, this); + } + + associateClientWindow(); + + if (! screen->isSloppyFocus()) + openbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, + GrabModeSync, GrabModeSync, None, None); + + openbox->grabButton(Button1, Mod1Mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, None, openbox->getMoveCursor()); + openbox->grabButton(Button2, Mod1Mask, frame.window, True, + ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None); + openbox->grabButton(Button3, Mod1Mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, None, None); + + positionWindows(); + XRaiseWindow(display, frame.plate); + XMapSubwindows(display, frame.plate); + if (decorations.titlebar) XMapSubwindows(display, frame.title); + XMapSubwindows(display, frame.window); + + if (decorations.menu) + windowmenu = new Windowmenu(this); + + decorate(); + + if (workspace_number < 0 || workspace_number >= screen->getCount()) + screen->getCurrentWorkspace()->addWindow(this, place_window); + else + screen->getWorkspace(workspace_number)->addWindow(this, place_window); + + configure(frame.x, frame.y, frame.width, frame.height); + + if (flags.shaded) { + flags.shaded = False; + shade(); + } + + if (flags.maximized && functions.maximize) { + unsigned int button = flags.maximized; + flags.maximized = 0; + maximize(button); + } + + setFocusFlag(False); + + openbox->ungrab(); +} + + +OpenboxWindow::~OpenboxWindow(void) { + if (flags.moving || flags.resizing) { + screen->hideGeometry(); + XUngrabPointer(display, CurrentTime); + } + + if (workspace_number != -1 && window_number != -1) + screen->getWorkspace(workspace_number)->removeWindow(this); + else if (flags.iconic) + screen->removeIcon(this); + + if (timer) { + if (timer->isTiming()) timer->stop(); + delete timer; + } + + if (windowmenu) delete windowmenu; + + if (client.title) + delete [] client.title; + + if (client.icon_title) + delete [] client.icon_title; + + if (client.mwm_hint) + XFree(client.mwm_hint); + + if (client.openbox_hint) + XFree(client.openbox_hint); + + if (client.window_group) + openbox->removeGroupSearch(client.window_group); + + if (flags.transient && client.transient_for) + client.transient_for->client.transient = client.transient; + if (client.transient) + client.transient->client.transient_for = client.transient_for; + + if (frame.close_button) { + openbox->removeWindowSearch(frame.close_button); + XDestroyWindow(display, frame.close_button); + } + + if (frame.iconify_button) { + openbox->removeWindowSearch(frame.iconify_button); + XDestroyWindow(display, frame.iconify_button); + } + + if (frame.maximize_button) { + openbox->removeWindowSearch(frame.maximize_button); + XDestroyWindow(display, frame.maximize_button); + } + + if (frame.title) { + if (frame.ftitle) + image_ctrl->removeImage(frame.ftitle); + + if (frame.utitle) + image_ctrl->removeImage(frame.utitle); + + if (frame.flabel) + image_ctrl->removeImage(frame.flabel); + + if( frame.ulabel) + image_ctrl->removeImage(frame.ulabel); + + openbox->removeWindowSearch(frame.label); + openbox->removeWindowSearch(frame.title); + XDestroyWindow(display, frame.label); + XDestroyWindow(display, frame.title); + } + + if (frame.handle) { + if (frame.fhandle) + image_ctrl->removeImage(frame.fhandle); + + if (frame.uhandle) + image_ctrl->removeImage(frame.uhandle); + + if (frame.fgrip) + image_ctrl->removeImage(frame.fgrip); + + if (frame.ugrip) + image_ctrl->removeImage(frame.ugrip); + + openbox->removeWindowSearch(frame.handle); + openbox->removeWindowSearch(frame.right_grip); + openbox->removeWindowSearch(frame.left_grip); + XDestroyWindow(display, frame.right_grip); + XDestroyWindow(display, frame.left_grip); + XDestroyWindow(display, frame.handle); + } + + if (frame.fbutton) + image_ctrl->removeImage(frame.fbutton); + + if (frame.ubutton) + image_ctrl->removeImage(frame.ubutton); + + if (frame.pbutton) + image_ctrl->removeImage(frame.pbutton); + + if (frame.plate) { + openbox->removeWindowSearch(frame.plate); + XDestroyWindow(display, frame.plate); + } + + if (frame.window) { + openbox->removeWindowSearch(frame.window); + XDestroyWindow(display, frame.window); + } + + if (flags.managed) { + openbox->removeWindowSearch(client.window); + screen->removeNetizen(client.window); + } +} + + +/* + * Creates a new top level window, with a given location, size, and border + * width. + * Returns: the newly created window + */ +Window OpenboxWindow::createToplevelWindow(int x, int y, unsigned int width, + unsigned int height, + unsigned int borderwidth) +{ + 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 = ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | EnterWindowMask; + + return XCreateWindow(display, screen->getRootWindow(), x, y, width, height, + borderwidth, screen->getDepth(), InputOutput, + screen->getVisual(), create_mask, + &attrib_create); +} + + +/* + * Creates a child window, and optionally associates a given cursor with + * the new window. + */ +Window OpenboxWindow::createChildWindow(Window parent, Cursor cursor) { + XSetWindowAttributes attrib_create; + unsigned long create_mask = CWBackPixmap | CWBorderPixel | + CWEventMask; + + attrib_create.background_pixmap = None; + attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask | + EnterWindowMask | LeaveWindowMask; + + if (cursor) { + create_mask |= CWCursor; + attrib_create.cursor = cursor; + } + + return XCreateWindow(display, parent, 0, 0, 1, 1, 0, screen->getDepth(), + InputOutput, screen->getVisual(), create_mask, + &attrib_create); +} + + +void OpenboxWindow::associateClientWindow(void) { + XSetWindowBorderWidth(display, client.window, 0); + getWMName(); + getWMIconName(); + + XChangeSaveSet(display, client.window, SetModeInsert); + XSetWindowAttributes attrib_set; + + XSelectInput(display, frame.plate, NoEventMask); + XReparentWindow(display, client.window, frame.plate, 0, 0); + XSelectInput(display, frame.plate, SubstructureRedirectMask); + + XFlush(display); + + attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask | + FocusChangeMask; + attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask; + + XChangeWindowAttributes(display, client.window, CWEventMask|CWDontPropagate, + &attrib_set); + +#ifdef SHAPE + if (openbox->hasShapeExtensions()) { + XShapeSelectInput(display, client.window, ShapeNotifyMask); + + int foo; + unsigned int ufoo; + + XShapeQueryExtents(display, client.window, &flags.shaped, &foo, &foo, + &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, &ufoo); + + if (flags.shaped) { + XShapeCombineShape(display, frame.window, ShapeBounding, + frame.mwm_border_w, frame.y_border + + frame.mwm_border_w, client.window, + ShapeBounding, ShapeSet); + + int num = 1; + XRectangle xrect[2]; + xrect[0].x = xrect[0].y = 0; + xrect[0].width = frame.width; + xrect[0].height = frame.y_border; + + if (decorations.handle) { + xrect[1].x = 0; + xrect[1].y = frame.y_handle; + xrect[1].width = frame.width; + xrect[1].height = frame.handle_h + frame.border_w; + num++; + } + + XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0, + xrect, num, ShapeUnion, Unsorted); + } + } +#endif // SHAPE + + if (decorations.iconify) createIconifyButton(); + if (decorations.maximize) createMaximizeButton(); + if (decorations.close) createCloseButton(); + + if (frame.ubutton) { + if (frame.close_button) + XSetWindowBackgroundPixmap(display, frame.close_button, frame.ubutton); + if (frame.maximize_button) + XSetWindowBackgroundPixmap(display, frame.maximize_button, + frame.ubutton); + if (frame.iconify_button) + XSetWindowBackgroundPixmap(display, frame.iconify_button, frame.ubutton); + } else { + if (frame.close_button) + XSetWindowBackground(display, frame.close_button, frame.ubutton_pixel); + if (frame.maximize_button) + XSetWindowBackground(display, frame.maximize_button, + frame.ubutton_pixel); + if (frame.iconify_button) + XSetWindowBackground(display, frame.iconify_button, frame.ubutton_pixel); + } +} + + +void OpenboxWindow::decorate(void) { + Pixmap tmp = frame.fbutton; + BTexture *texture = &(screen->getWindowStyle()->b_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.fbutton = None; + frame.fbutton_pixel = texture->getColor()->getPixel(); + } else { + frame.fbutton = + image_ctrl->renderImage(frame.button_w, frame.button_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.ubutton; + texture = &(screen->getWindowStyle()->b_unfocus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.ubutton = None; + frame.ubutton_pixel = texture->getColor()->getPixel(); + } else { + frame.ubutton = + image_ctrl->renderImage(frame.button_w, frame.button_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.pbutton; + texture = &(screen->getWindowStyle()->b_pressed); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.pbutton = None; + frame.pbutton_pixel = texture->getColor()->getPixel(); + } else { + frame.pbutton = + image_ctrl->renderImage(frame.button_w, frame.button_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + if (decorations.titlebar) { + tmp = frame.ftitle; + texture = &(screen->getWindowStyle()->t_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.ftitle = None; + frame.ftitle_pixel = texture->getColor()->getPixel(); + } else { + frame.ftitle = + image_ctrl->renderImage(frame.width, frame.title_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.utitle; + texture = &(screen->getWindowStyle()->t_unfocus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.utitle = None; + frame.utitle_pixel = texture->getColor()->getPixel(); + } else { + frame.utitle = + image_ctrl->renderImage(frame.width, frame.title_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + XSetWindowBorder(display, frame.title, + screen->getBorderColor()->getPixel()); + + decorateLabel(); + } + + if (decorations.border) { + frame.fborder_pixel = screen->getWindowStyle()->f_focus.getPixel(); + frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.getPixel(); + openbox_attrib.flags |= AttribDecoration; + openbox_attrib.decoration = DecorNormal; + } else { + openbox_attrib.flags |= AttribDecoration; + openbox_attrib.decoration = DecorNone; + } + + if (decorations.handle) { + tmp = frame.fhandle; + texture = &(screen->getWindowStyle()->h_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.fhandle = None; + frame.fhandle_pixel = texture->getColor()->getPixel(); + } else { + frame.fhandle = + image_ctrl->renderImage(frame.width, frame.handle_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.uhandle; + texture = &(screen->getWindowStyle()->h_unfocus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.uhandle = None; + frame.uhandle_pixel = texture->getColor()->getPixel(); + } else { + frame.uhandle = + image_ctrl->renderImage(frame.width, frame.handle_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.fgrip; + texture = &(screen->getWindowStyle()->g_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.fgrip = None; + frame.fgrip_pixel = texture->getColor()->getPixel(); + } else { + frame.fgrip = + image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.ugrip; + texture = &(screen->getWindowStyle()->g_unfocus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.ugrip = None; + frame.ugrip_pixel = texture->getColor()->getPixel(); + } else { + frame.ugrip = + image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + XSetWindowBorder(display, frame.handle, + screen->getBorderColor()->getPixel()); + XSetWindowBorder(display, frame.left_grip, + screen->getBorderColor()->getPixel()); + XSetWindowBorder(display, frame.right_grip, + screen->getBorderColor()->getPixel()); + } + + XSetWindowBorder(display, frame.window, + screen->getBorderColor()->getPixel()); +} + + +void OpenboxWindow::decorateLabel(void) { + Pixmap tmp = frame.flabel; + BTexture *texture = &(screen->getWindowStyle()->l_focus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.flabel = None; + frame.flabel_pixel = texture->getColor()->getPixel(); + } else { + frame.flabel = + image_ctrl->renderImage(frame.label_w, frame.label_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); + + tmp = frame.ulabel; + texture = &(screen->getWindowStyle()->l_unfocus); + if (texture->getTexture() == (BImage_Flat | BImage_Solid)) { + frame.ulabel = None; + frame.ulabel_pixel = texture->getColor()->getPixel(); + } else { + frame.ulabel = + image_ctrl->renderImage(frame.label_w, frame.label_h, texture); + } + if (tmp) image_ctrl->removeImage(tmp); +} + + +void OpenboxWindow::createCloseButton(void) { + if (decorations.close && frame.title != None) { + frame.close_button = createChildWindow(frame.title); + openbox->saveWindowSearch(frame.close_button, this); + } +} + + +void OpenboxWindow::createIconifyButton(void) { + if (decorations.iconify && frame.title != None) { + frame.iconify_button = createChildWindow(frame.title); + openbox->saveWindowSearch(frame.iconify_button, this); + } +} + + +void OpenboxWindow::createMaximizeButton(void) { + if (decorations.maximize && frame.title != None) { + frame.maximize_button = createChildWindow(frame.title); + openbox->saveWindowSearch(frame.maximize_button, this); + } +} + + +void OpenboxWindow::positionButtons(Bool redecorate_label) { + const char *format = openbox->getTitleBarLayout(); + const unsigned int bw = frame.bevel_w + 1; + const unsigned int by = frame.bevel_w + 1; + unsigned int bx = frame.bevel_w + 1; + unsigned int bcount = strlen(format) - 1; + + if (!decorations.close) + bcount--; + if (!decorations.maximize) + bcount--; + if (!decorations.iconify) + bcount--; + frame.label_w = frame.width - bx * 2 - (frame.button_w + bw) * bcount; + + bool hasclose, hasiconify, hasmaximize; + hasclose = hasiconify = hasmaximize = false; + + for (int i = 0; format[i] != '\0' && i < 4; i++) { + switch(format[i]) { + case 'C': + if (decorations.close && frame.close_button != None) { + XMoveResizeWindow(display, frame.close_button, bx, by, + frame.button_w, frame.button_h); + XMapWindow(display, frame.close_button); + XClearWindow(display, frame.close_button); + bx += frame.button_w + bw; + hasclose = true; + } else if (frame.close_button) + XUnmapWindow(display, frame.close_button); + break; + case 'I': + if (decorations.iconify && frame.iconify_button != None) { + XMoveResizeWindow(display, frame.iconify_button, bx, by, + frame.button_w, frame.button_h); + XMapWindow(display, frame.iconify_button); + XClearWindow(display, frame.iconify_button); + bx += frame.button_w + bw; + hasiconify = true; + } else if (frame.close_button) + XUnmapWindow(display, frame.close_button); + break; + case 'M': + if (decorations.maximize && frame.maximize_button != None) { + XMoveResizeWindow(display, frame.maximize_button, bx, by, + frame.button_w, frame.button_h); + XMapWindow(display, frame.maximize_button); + XClearWindow(display, frame.maximize_button); + bx += frame.button_w + bw; + hasmaximize = true; + } else if (frame.close_button) + XUnmapWindow(display, frame.close_button); + break; + case 'L': + XMoveResizeWindow(display, frame.label, bx, by - 1, + frame.label_w, frame.label_h); + bx += frame.label_w + bw; + break; + } + } + + if (!hasclose) { + openbox->removeWindowSearch(frame.close_button); + XDestroyWindow(display, frame.close_button); + } + if (!hasiconify) { + openbox->removeWindowSearch(frame.iconify_button); + XDestroyWindow(display, frame.iconify_button); + } + if (!hasmaximize) { + openbox->removeWindowSearch(frame.maximize_button); + XDestroyWindow(display, frame.maximize_button); + } + if (redecorate_label) + decorateLabel(); + redrawLabel(); + redrawAllButtons(); +} + + +void OpenboxWindow::reconfigure(void) { + upsize(); + + client.x = frame.x + frame.mwm_border_w + frame.border_w; + client.y = frame.y + frame.y_border + frame.mwm_border_w + + frame.border_w; + + if (client.title) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getWindowStyle()->fontset, + client.title, client.title_len, &ink, &logical); + client.title_text_w = logical.width; + } else { + client.title_text_w = XTextWidth(screen->getWindowStyle()->font, + client.title, client.title_len); + } + client.title_text_w += (frame.bevel_w * 4); + } + + positionWindows(); + decorate(); + + XClearWindow(display, frame.window); + setFocusFlag(flags.focused); + + configure(frame.x, frame.y, frame.width, frame.height); + + if (! screen->isSloppyFocus()) + openbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, + GrabModeSync, GrabModeSync, None, None); + else + openbox->ungrabButton(Button1, 0, frame.plate); + + if (windowmenu) { + windowmenu->move(windowmenu->getX(), frame.y + frame.title_h); + windowmenu->reconfigure(); + } +} + + +void OpenboxWindow::positionWindows(void) { + XResizeWindow(display, frame.window, frame.width, + ((flags.shaded) ? frame.title_h : frame.height)); + XSetWindowBorderWidth(display, frame.window, frame.border_w); + XSetWindowBorderWidth(display, frame.plate, frame.mwm_border_w); + XMoveResizeWindow(display, frame.plate, 0, frame.y_border, + client.width, client.height); + XMoveResizeWindow(display, client.window, 0, 0, client.width, client.height); + + if (decorations.titlebar) { + XSetWindowBorderWidth(display, frame.title, frame.border_w); + XMoveResizeWindow(display, frame.title, -frame.border_w, + -frame.border_w, frame.width, frame.title_h); + + positionButtons(); + } else if (frame.title) { + XUnmapWindow(display, frame.title); + } + if (decorations.handle) { + XSetWindowBorderWidth(display, frame.handle, frame.border_w); + XSetWindowBorderWidth(display, frame.left_grip, frame.border_w); + XSetWindowBorderWidth(display, frame.right_grip, frame.border_w); + + XMoveResizeWindow(display, frame.handle, -frame.border_w, + frame.y_handle - frame.border_w, + frame.width, frame.handle_h); + XMoveResizeWindow(display, frame.left_grip, -frame.border_w, + -frame.border_w, frame.grip_w, frame.grip_h); + XMoveResizeWindow(display, frame.right_grip, + frame.width - frame.grip_w - frame.border_w, + -frame.border_w, frame.grip_w, frame.grip_h); + XMapSubwindows(display, frame.handle); + } else if (frame.handle) { + XUnmapWindow(display, frame.handle); + } +} + + +void OpenboxWindow::getWMName(void) { + if (client.title) { + delete [] client.title; + client.title = (char *) 0; + } + + XTextProperty text_prop; + char **list; + int num; + + if (XGetWMName(display, client.window, &text_prop)) { + if (text_prop.value && text_prop.nitems > 0) { + if (text_prop.encoding != XA_STRING) { + text_prop.nitems = strlen((char *) text_prop.value); + + if ((XmbTextPropertyToTextList(display, &text_prop, + &list, &num) == Success) && + (num > 0) && *list) { + client.title = bstrdup(*list); + XFreeStringList(list); + } else { + client.title = bstrdup((char *) text_prop.value); + } + } else { + client.title = bstrdup((char *) text_prop.value); + } + XFree((char *) text_prop.value); + } else { + client.title = bstrdup(i18n->getMessage(WindowSet, WindowUnnamed, + "Unnamed")); + } + } else { + client.title = bstrdup(i18n->getMessage(WindowSet, WindowUnnamed, + "Unnamed")); + } + client.title_len = strlen(client.title); + + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getWindowStyle()->fontset, + client.title, client.title_len, &ink, &logical); + client.title_text_w = logical.width; + } else { + client.title_len = strlen(client.title); + client.title_text_w = XTextWidth(screen->getWindowStyle()->font, + client.title, client.title_len); + } + + client.title_text_w += (frame.bevel_w * 4); +} + + +void OpenboxWindow::getWMIconName(void) { + if (client.icon_title) { + delete [] client.icon_title; + client.icon_title = (char *) 0; + } + + XTextProperty text_prop; + char **list; + int num; + + if (XGetWMIconName(display, client.window, &text_prop)) { + if (text_prop.value && text_prop.nitems > 0) { + if (text_prop.encoding != XA_STRING) { + text_prop.nitems = strlen((char *) text_prop.value); + + if ((XmbTextPropertyToTextList(display, &text_prop, + &list, &num) == Success) && + (num > 0) && *list) { + client.icon_title = bstrdup(*list); + XFreeStringList(list); + } else { + client.icon_title = bstrdup((char *) text_prop.value); + } + } else { + client.icon_title = bstrdup((char *) text_prop.value); + } + XFree((char *) text_prop.value); + } else { + client.icon_title = bstrdup(client.title); + } + } else { + client.icon_title = bstrdup(client.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 OpenboxWindow::getWMProtocols(void) { + 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] == openbox->getWMDeleteAtom()) + functions.close = decorations.close = True; + else if (proto[i] == openbox->getWMTakeFocusAtom()) + flags.send_focus_message = True; + else if (proto[i] == openbox->getOpenboxStructureMessagesAtom()) + 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 OpenboxWindow::getWMHints(void) { + XWMHints *wmhint = XGetWMHints(display, client.window); + if (! wmhint) { + flags.visible = True; + flags.iconic = False; + focus_mode = F_Passive; + client.window_group = None; + client.initial_state = NormalState; + return; + } + client.wm_hint_flags = wmhint->flags; + if (wmhint->flags & InputHint) { + if (wmhint->input == True) { + if (flags.send_focus_message) + focus_mode = F_LocallyActive; + else + focus_mode = F_Passive; + } else { + if (flags.send_focus_message) + focus_mode = F_GloballyActive; + else + focus_mode = F_NoInput; + } + } else { + focus_mode = F_Passive; + } + + if (wmhint->flags & StateHint) + client.initial_state = wmhint->initial_state; + else + client.initial_state = NormalState; + + if (wmhint->flags & WindowGroupHint) { + if (! client.window_group) { + client.window_group = wmhint->window_group; + openbox->saveGroupSearch(client.window_group, this); + } + } else { + client.window_group = None; + } + 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 OpenboxWindow::getWMNormalHints(void) { + long icccm_mask; + XSizeHints sizehint; + + client.min_width = client.min_height = + client.base_width = client.base_height = + client.width_inc = client.height_inc = 1; + client.max_width = screen->getWidth(); + client.max_height = screen->getHeight(); + client.min_aspect_x = client.min_aspect_y = + client.max_aspect_x = client.max_aspect_y = 1; + client.win_gravity = NorthWestGravity; + + if (! XGetWMNormalHints(display, client.window, &sizehint, &icccm_mask)) + return; + + client.normal_hint_flags = sizehint.flags; + + if (sizehint.flags & PMinSize) { + client.min_width = sizehint.min_width; + client.min_height = sizehint.min_height; + } + + if (sizehint.flags & PMaxSize) { + client.max_width = sizehint.max_width; + client.max_height = sizehint.max_height; + } + + if (sizehint.flags & PResizeInc) { + client.width_inc = sizehint.width_inc; + client.height_inc = sizehint.height_inc; + } + + 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; + } + + 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 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 OpenboxWindow::getMWMHints(void) { + int format; + Atom atom_return; + unsigned long num, len; + + int ret = XGetWindowProperty(display, client.window, + openbox->getMotifWMHintsAtom(), 0, + PropMwmHintsElements, False, + openbox->getMotifWMHintsAtom(), &atom_return, + &format, &num, &len, + (unsigned char **) &client.mwm_hint); + + if (ret != Success || !client.mwm_hint || num != PropMwmHintsElements) + return; + + if (client.mwm_hint->flags & MwmHintsDecorations) { + if (client.mwm_hint->decorations & MwmDecorAll) { + decorations.titlebar = decorations.handle = decorations.border = + decorations.iconify = decorations.maximize = + decorations.close = decorations.menu = True; + } else { + decorations.titlebar = decorations.handle = decorations.border = + decorations.iconify = decorations.maximize = + decorations.close = decorations.menu = False; + + if (client.mwm_hint->decorations & MwmDecorBorder) + decorations.border = True; + if (client.mwm_hint->decorations & MwmDecorHandle) + decorations.handle = True; + if (client.mwm_hint->decorations & MwmDecorTitle) + decorations.titlebar = True; + if (client.mwm_hint->decorations & MwmDecorMenu) + decorations.menu = True; + if (client.mwm_hint->decorations & MwmDecorIconify) + decorations.iconify = True; + if (client.mwm_hint->decorations & MwmDecorMaximize) + decorations.maximize = True; + } + } + + if (client.mwm_hint->flags & MwmHintsFunctions) { + if (client.mwm_hint->functions & MwmFuncAll) { + functions.resize = functions.move = functions.iconify = + functions.maximize = functions.close = True; + } else { + functions.resize = functions.move = functions.iconify = + functions.maximize = functions.close = False; + + if (client.mwm_hint->functions & MwmFuncResize) + functions.resize = True; + if (client.mwm_hint->functions & MwmFuncMove) + functions.move = True; + if (client.mwm_hint->functions & MwmFuncIconify) + functions.iconify = True; + if (client.mwm_hint->functions & MwmFuncMaximize) + functions.maximize = True; + if (client.mwm_hint->functions & MwmFuncClose) + functions.close = True; + } + } +} + + +/* + * Gets the openbox 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. + */ +void OpenboxWindow::getOpenboxHints(void) { + int format; + Atom atom_return; + unsigned long num, len; + + int ret = XGetWindowProperty(display, client.window, + openbox->getOpenboxHintsAtom(), 0, + PropOpenboxHintsElements, False, + openbox->getOpenboxHintsAtom(), &atom_return, + &format, &num, &len, + (unsigned char **) &client.openbox_hint); + if (ret != Success || !client.openbox_hint || + num != PropOpenboxHintsElements) + return; + + if (client.openbox_hint->flags & AttribShaded) + flags.shaded = (client.openbox_hint->attrib & AttribShaded); + + if ((client.openbox_hint->flags & AttribMaxHoriz) && + (client.openbox_hint->flags & AttribMaxVert)) + flags.maximized = (client.openbox_hint->attrib & + (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; + else if (client.openbox_hint->flags & AttribMaxVert) + flags.maximized = (client.openbox_hint->attrib & AttribMaxVert) ? 2 : 0; + else if (client.openbox_hint->flags & AttribMaxHoriz) + flags.maximized = (client.openbox_hint->attrib & AttribMaxHoriz) ? 3 : 0; + + if (client.openbox_hint->flags & AttribOmnipresent) + flags.stuck = (client.openbox_hint->attrib & AttribOmnipresent); + + if (client.openbox_hint->flags & AttribWorkspace) + workspace_number = client.openbox_hint->workspace; + + // if (client.openbox_hint->flags & AttribStack) + // don't yet have always on top/bottom for openbox yet... working + // on that + + if (client.openbox_hint->flags & AttribDecoration) { + switch (client.openbox_hint->decoration) { + case DecorNone: + decorations.titlebar = decorations.border = decorations.handle = + decorations.iconify = decorations.maximize = + decorations.menu = False; + functions.resize = functions.move = functions.iconify = + functions.maximize = False; + + break; + + case DecorTiny: + decorations.titlebar = decorations.iconify = decorations.menu = + functions.move = functions.iconify = True; + decorations.border = decorations.handle = decorations.maximize = + functions.resize = functions.maximize = False; + + break; + + case DecorTool: + decorations.titlebar = decorations.menu = functions.move = True; + decorations.iconify = decorations.border = decorations.handle = + decorations.maximize = functions.resize = functions.maximize = + functions.iconify = False; + + break; + + case DecorNormal: + default: + decorations.titlebar = decorations.border = decorations.handle = + decorations.iconify = decorations.maximize = + decorations.menu = True; + functions.resize = functions.move = functions.iconify = + functions.maximize = True; + + break; + } + + reconfigure(); + } +} + + +void OpenboxWindow::configure(int dx, int dy, + unsigned int dw, unsigned int dh) { + Bool send_event = (frame.x != dx || frame.y != dy); + + if ((dw != frame.width) || (dh != frame.height)) { + if ((((signed) frame.width) + dx) < 0) dx = 0; + if ((((signed) frame.height) + dy) < 0) dy = 0; + + frame.x = dx; + frame.y = dy; + frame.width = dw; + frame.height = dh; + + downsize(); + +#ifdef SHAPE + if (openbox->hasShapeExtensions() && flags.shaped) { + XShapeCombineShape(display, frame.window, ShapeBounding, + frame.mwm_border_w, frame.y_border + + frame.mwm_border_w, client.window, + ShapeBounding, ShapeSet); + + int num = 1; + XRectangle xrect[2]; + xrect[0].x = xrect[0].y = 0; + xrect[0].width = frame.width; + xrect[0].height = frame.y_border; + + if (decorations.handle) { + xrect[1].x = 0; + xrect[1].y = frame.y_handle; + xrect[1].width = frame.width; + xrect[1].height = frame.handle_h + frame.border_w; + num++; + } + + XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0, + xrect, num, ShapeUnion, Unsorted); + } +#endif // SHAPE + + XMoveWindow(display, frame.window, frame.x, frame.y); + + positionWindows(); + decorate(); + setFocusFlag(flags.focused); + redrawAllButtons(); + } else { + frame.x = dx; + frame.y = dy; + + XMoveWindow(display, frame.window, frame.x, frame.y); + + if (! flags.moving) send_event = True; + } + + if (send_event && ! flags.moving) { + client.x = dx + frame.mwm_border_w + frame.border_w; + client.y = dy + frame.y_border + frame.mwm_border_w + + frame.border_w; + + XEvent event; + event.type = ConfigureNotify; + + event.xconfigure.display = display; + event.xconfigure.event = client.window; + event.xconfigure.window = client.window; + event.xconfigure.x = client.x; + event.xconfigure.y = client.y; + event.xconfigure.width = client.width; + event.xconfigure.height = client.height; + event.xconfigure.border_width = client.old_bw; + event.xconfigure.above = frame.window; + event.xconfigure.override_redirect = False; + + XSendEvent(display, client.window, True, NoEventMask, &event); + + screen->updateNetizenConfigNotify(&event); + } +} + + +Bool OpenboxWindow::setInputFocus(void) { + if (((signed) (frame.x + frame.width)) < 0) { + if (((signed) (frame.y + frame.y_border)) < 0) + configure(frame.border_w, frame.border_w, frame.width, frame.height); + else if (frame.y > (signed) screen->getHeight()) + configure(frame.border_w, screen->getHeight() - frame.height, + frame.width, frame.height); + else + configure(frame.border_w, frame.y + frame.border_w, + frame.width, frame.height); + } else if (frame.x > (signed) screen->getWidth()) { + if (((signed) (frame.y + frame.y_border)) < 0) + configure(screen->getWidth() - frame.width, frame.border_w, + frame.width, frame.height); + else if (frame.y > (signed) screen->getHeight()) + configure(screen->getWidth() - frame.width, + screen->getHeight() - frame.height, frame.width, frame.height); + else + configure(screen->getWidth() - frame.width, + frame.y + frame.border_w, frame.width, frame.height); + } + + openbox->grab(); + if (! validateClient()) return False; + + Bool ret = False; + + if (client.transient && flags.modal) { + ret = client.transient->setInputFocus(); + } else if (! flags.focused) { + if (focus_mode == F_LocallyActive || focus_mode == F_Passive) + XSetInputFocus(display, client.window, + RevertToPointerRoot, CurrentTime); + else + XSetInputFocus(display, screen->getRootWindow(), + RevertToNone, CurrentTime); + + openbox->setFocusedWindow(this); + + if (flags.send_focus_message) { + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = openbox->getWMProtocolsAtom(); + ce.xclient.display = display; + ce.xclient.window = client.window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = openbox->getWMTakeFocusAtom(); + ce.xclient.data.l[1] = openbox->getLastTime(); + ce.xclient.data.l[2] = 0l; + ce.xclient.data.l[3] = 0l; + ce.xclient.data.l[4] = 0l; + XSendEvent(display, client.window, False, NoEventMask, &ce); + } + + if (screen->isSloppyFocus() && screen->doAutoRaise()) + timer->start(); + + ret = True; + } + + openbox->ungrab(); + + return ret; +} + + +void OpenboxWindow::iconify(void) { + if (flags.iconic) return; + + if (windowmenu) windowmenu->hide(); + + setState(IconicState); + + XSelectInput(display, client.window, NoEventMask); + XUnmapWindow(display, client.window); + XSelectInput(display, client.window, + PropertyChangeMask | StructureNotifyMask | FocusChangeMask); + + XUnmapWindow(display, frame.window); + flags.visible = False; + flags.iconic = True; + + screen->getWorkspace(workspace_number)->removeWindow(this); + + if (flags.transient && client.transient_for && + !client.transient_for->flags.iconic) { + client.transient_for->iconify(); + } + screen->addIcon(this); + + if (client.transient && !client.transient->flags.iconic) { + client.transient->iconify(); + } +} + + +void OpenboxWindow::deiconify(Bool reassoc, Bool raise) { + if (flags.iconic || reassoc) + screen->reassociateWindow(this, -1, False); + else if (workspace_number != screen->getCurrentWorkspace()->getWorkspaceID()) + return; + + setState(NormalState); + + XSelectInput(display, client.window, NoEventMask); + XMapWindow(display, client.window); + XSelectInput(display, client.window, + PropertyChangeMask | StructureNotifyMask | FocusChangeMask); + + XMapSubwindows(display, frame.window); + XMapWindow(display, frame.window); + + if (flags.iconic && screen->doFocusNew()) setInputFocus(); + + flags.visible = True; + flags.iconic = False; + + if (reassoc && client.transient) client.transient->deiconify(True, False); + + if (raise) + screen->getWorkspace(workspace_number)->raiseWindow(this); +} + + +void OpenboxWindow::close(void) { + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = openbox->getWMProtocolsAtom(); + ce.xclient.display = display; + ce.xclient.window = client.window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = openbox->getWMDeleteAtom(); + 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(display, client.window, False, NoEventMask, &ce); +} + + +void OpenboxWindow::withdraw(void) { + flags.visible = False; + flags.iconic = False; + + XUnmapWindow(display, frame.window); + + XSelectInput(display, client.window, NoEventMask); + XUnmapWindow(display, client.window); + XSelectInput(display, client.window, + PropertyChangeMask | StructureNotifyMask | FocusChangeMask); + + if (windowmenu) windowmenu->hide(); +} + + +void OpenboxWindow::maximize(unsigned int button) { + // 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; + + openbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert); + openbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert); + + // when a resize is begun, 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(openbox_attrib.premax_x, openbox_attrib.premax_y, + openbox_attrib.premax_w, openbox_attrib.premax_h); + + openbox_attrib.premax_x = openbox_attrib.premax_y = 0; + openbox_attrib.premax_w = openbox_attrib.premax_h = 0; + + redrawAllButtons(); + setState(current_state); + return; + } + + int dx = 0, dy = 0; + unsigned int dw, dh; + + openbox_attrib.premax_x = frame.x; + openbox_attrib.premax_y = frame.y; + openbox_attrib.premax_w = frame.width; + openbox_attrib.premax_h = frame.height; + + dw = screen->getWidth(); + dw -= frame.border_w * 2; + dw -= frame.mwm_border_w * 2; + dw -= client.base_width; + + dh = screen->getHeight(); + dh -= frame.border_w * 2; + dh -= frame.mwm_border_w * 2; + dh -= ((frame.handle_h + frame.border_w) * decorations.handle); + dh -= client.base_height; + dh -= frame.y_border; + + if (! screen->doFullMax()) + dh -= screen->getToolbar()->getExposedHeight() + frame.border_w; + + 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; + + dw -= (dw % client.width_inc); + dw += client.base_width; + dw += frame.mwm_border_w * 2; + + dh -= (dh % client.height_inc); + dh += client.base_height; + dh += frame.y_border; + dh += ((frame.handle_h + frame.border_w) * decorations.handle); + dh += frame.mwm_border_w * 2; + + dx += ((screen->getWidth() - dw) / 2) - frame.border_w; + + if (screen->doFullMax()) { + dy += ((screen->getHeight() - dh) / 2) - frame.border_w; + } else { + dy += (((screen->getHeight() - screen->getToolbar()->getExposedHeight()) + - dh) / 2) - frame.border_w; + + switch (screen->getToolbarPlacement()) { + case Toolbar::TopLeft: + case Toolbar::TopCenter: + case Toolbar::TopRight: + dy += screen->getToolbar()->getExposedHeight() + + frame.border_w; + break; + } + } + + switch(button) { + case 1: + openbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert; + openbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert; + break; + + case 2: + openbox_attrib.flags |= AttribMaxVert; + openbox_attrib.attrib |= AttribMaxVert; + + dw = frame.width; + dx = frame.x; + break; + + case 3: + openbox_attrib.flags |= AttribMaxHoriz; + openbox_attrib.attrib |= AttribMaxHoriz; + + dh = frame.height; + dy = frame.y; + break; + } + + if (flags.shaded) { + openbox_attrib.flags ^= AttribShaded; + openbox_attrib.attrib ^= AttribShaded; + flags.shaded = False; + } + + flags.maximized = button; + + configure(dx, dy, dw, dh); + screen->getWorkspace(workspace_number)->raiseWindow(this); + redrawAllButtons(); + setState(current_state); +} + + +void OpenboxWindow::setWorkspace(int n) { + workspace_number = n; + + openbox_attrib.flags |= AttribWorkspace; + openbox_attrib.workspace = workspace_number; +} + + +void OpenboxWindow::shade(void) { + if (!decorations.titlebar) + return; + + if (flags.shaded) { + XResizeWindow(display, frame.window, frame.width, frame.height); + flags.shaded = False; + openbox_attrib.flags ^= AttribShaded; + openbox_attrib.attrib ^= AttribShaded; + + setState(NormalState); + } else { + XResizeWindow(display, frame.window, frame.width, frame.title_h); + flags.shaded = True; + openbox_attrib.flags |= AttribShaded; + openbox_attrib.attrib |= AttribShaded; + + setState(IconicState); + } +} + + +void OpenboxWindow::stick(void) { + if (flags.stuck) { + openbox_attrib.flags ^= AttribOmnipresent; + openbox_attrib.attrib ^= AttribOmnipresent; + + flags.stuck = False; + + if (! flags.iconic) + screen->reassociateWindow(this, -1, True); + + setState(current_state); + } else { + flags.stuck = True; + + openbox_attrib.flags |= AttribOmnipresent; + openbox_attrib.attrib |= AttribOmnipresent; + + setState(current_state); + } +} + + +void OpenboxWindow::setFocusFlag(Bool focus) { + flags.focused = focus; + + if (decorations.titlebar) { + if (flags.focused) { + if (frame.ftitle) + XSetWindowBackgroundPixmap(display, frame.title, frame.ftitle); + else + XSetWindowBackground(display, frame.title, frame.ftitle_pixel); + } else { + if (frame.utitle) + XSetWindowBackgroundPixmap(display, frame.title, frame.utitle); + else + XSetWindowBackground(display, frame.title, frame.utitle_pixel); + } + XClearWindow(display, frame.title); + + redrawLabel(); + redrawAllButtons(); + } + + if (decorations.handle) { + if (flags.focused) { + if (frame.fhandle) + XSetWindowBackgroundPixmap(display, frame.handle, frame.fhandle); + else + XSetWindowBackground(display, frame.handle, frame.fhandle_pixel); + + if (frame.fgrip) { + XSetWindowBackgroundPixmap(display, frame.right_grip, frame.fgrip); + XSetWindowBackgroundPixmap(display, frame.left_grip, frame.fgrip); + } else { + XSetWindowBackground(display, frame.right_grip, frame.fgrip_pixel); + XSetWindowBackground(display, frame.left_grip, frame.fgrip_pixel); + } + } else { + if (frame.uhandle) + XSetWindowBackgroundPixmap(display, frame.handle, frame.uhandle); + else + XSetWindowBackground(display, frame.handle, frame.uhandle_pixel); + + if (frame.ugrip) { + XSetWindowBackgroundPixmap(display, frame.right_grip, frame.ugrip); + XSetWindowBackgroundPixmap(display, frame.left_grip, frame.ugrip); + } else { + XSetWindowBackground(display, frame.right_grip, frame.ugrip_pixel); + XSetWindowBackground(display, frame.left_grip, frame.ugrip_pixel); + } + } + XClearWindow(display, frame.handle); + XClearWindow(display, frame.right_grip); + XClearWindow(display, frame.left_grip); + } + + if (decorations.border) { + if (flags.focused) + XSetWindowBorder(display, frame.plate, frame.fborder_pixel); + else + XSetWindowBorder(display, frame.plate, frame.uborder_pixel); + } + + if (screen->isSloppyFocus() && screen->doAutoRaise() && timer->isTiming()) + timer->stop(); +} + + +void OpenboxWindow::installColormap(Bool install) { + openbox->grab(); + if (! validateClient()) return; + + int i = 0, ncmap = 0; + Colormap *cmaps = XListInstalledColormaps(display, client.window, &ncmap); + XWindowAttributes wattrib; + if (cmaps) { + if (XGetWindowAttributes(display, 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(display, 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(display, wattrib.colormap); + } + } + } + + XFree(cmaps); + } + + openbox->ungrab(); +} + + +void OpenboxWindow::setState(unsigned long new_state) { + current_state = new_state; + + unsigned long state[2]; + state[0] = (unsigned long) current_state; + state[1] = (unsigned long) None; + XChangeProperty(display, client.window, openbox->getWMStateAtom(), + openbox->getWMStateAtom(), 32, PropModeReplace, + (unsigned char *) state, 2); + + XChangeProperty(display, client.window, + openbox->getOpenboxAttributesAtom(), + openbox->getOpenboxAttributesAtom(), 32, PropModeReplace, + (unsigned char *) &openbox_attrib, + PropOpenboxAttributesElements); +} + + +Bool OpenboxWindow::getState(void) { + current_state = 0; + + Atom atom_return; + Bool ret = False; + int foo; + unsigned long *state, ulfoo, nitems; + + if ((XGetWindowProperty(display, client.window, openbox->getWMStateAtom(), + 0l, 2l, False, openbox->getWMStateAtom(), + &atom_return, &foo, &nitems, &ulfoo, + (unsigned char **) &state) != Success) || + (! state)) { + openbox->ungrab(); + return False; + } + + if (nitems >= 1) { + current_state = (unsigned long) state[0]; + + ret = True; + } + + XFree((void *) state); + + return ret; +} + + +void OpenboxWindow::setGravityOffsets(void) { + // x coordinates for each gravity type + const int x_west = client.x; + const int x_east = client.x + client.width - frame.width; + const int x_center = client.x + client.width - frame.width/2; + // y coordinates for each gravity type + const int y_north = client.y; + const int y_south = client.y + client.height - frame.height; + const int y_center = client.y + client.height - frame.height/2; + + switch (client.win_gravity) { + case NorthWestGravity: + default: + frame.x = x_west; + frame.y = y_north; + break; + case NorthGravity: + frame.x = x_center; + frame.y = y_north; + break; + case NorthEastGravity: + frame.x = x_east; + frame.y = y_north; + break; + case SouthWestGravity: + frame.x = x_west; + frame.y = y_south; + break; + case SouthGravity: + frame.x = x_center; + frame.y = y_south; + break; + case SouthEastGravity: + frame.x = x_east; + frame.y = y_south; + break; + case WestGravity: + frame.x = x_west; + frame.y = y_center; + break; + case EastGravity: + frame.x = x_east; + frame.y = y_center; + break; + case CenterGravity: + frame.x = x_center; + frame.y = y_center; + break; + case ForgetGravity: + case StaticGravity: + frame.x = client.x - frame.mwm_border_w + frame.border_w; + frame.y = client.y - frame.y_border - frame.mwm_border_w - frame.border_w; + break; + } +} + + +void OpenboxWindow::restoreAttributes(void) { + if (! getState()) current_state = NormalState; + + Atom atom_return; + int foo; + unsigned long ulfoo, nitems; + + OpenboxAttributes *net; + int ret = XGetWindowProperty(display, client.window, + openbox->getOpenboxAttributesAtom(), 0l, + PropOpenboxAttributesElements, False, + openbox->getOpenboxAttributesAtom(), + &atom_return, &foo, &nitems, &ulfoo, + (unsigned char **) &net); + if (ret != Success || !net || nitems != PropOpenboxAttributesElements) + return; + + openbox_attrib.flags = net->flags; + openbox_attrib.attrib = net->attrib; + openbox_attrib.decoration = net->decoration; + openbox_attrib.workspace = net->workspace; + openbox_attrib.stack = net->stack; + openbox_attrib.premax_x = net->premax_x; + openbox_attrib.premax_y = net->premax_y; + openbox_attrib.premax_w = net->premax_w; + openbox_attrib.premax_h = net->premax_h; + + XFree((void *) net); + + if (openbox_attrib.flags & AttribShaded && + openbox_attrib.attrib & AttribShaded) { + int save_state = + ((current_state == IconicState) ? NormalState : current_state); + + flags.shaded = False; + shade(); + + current_state = save_state; + } + + if (((int) openbox_attrib.workspace != screen->getCurrentWorkspaceID()) && + ((int) openbox_attrib.workspace < screen->getCount())) { + screen->reassociateWindow(this, openbox_attrib.workspace, True); + + if (current_state == NormalState) current_state = WithdrawnState; + } else if (current_state == WithdrawnState) { + current_state = NormalState; + } + + if (openbox_attrib.flags & AttribOmnipresent && + openbox_attrib.attrib & AttribOmnipresent) { + flags.stuck = False; + stick(); + + current_state = NormalState; + } + + if ((openbox_attrib.flags & AttribMaxHoriz) || + (openbox_attrib.flags & AttribMaxVert)) { + int x = openbox_attrib.premax_x, y = openbox_attrib.premax_y; + unsigned int w = openbox_attrib.premax_w, h = openbox_attrib.premax_h; + flags.maximized = 0; + + unsigned int m = False; + if ((openbox_attrib.flags & AttribMaxHoriz) && + (openbox_attrib.flags & AttribMaxVert)) + m = (openbox_attrib.attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0; + else if (openbox_attrib.flags & AttribMaxVert) + m = (openbox_attrib.attrib & AttribMaxVert) ? 2 : 0; + else if (openbox_attrib.flags & AttribMaxHoriz) + m = (openbox_attrib.attrib & AttribMaxHoriz) ? 3 : 0; + + if (m) maximize(m); + + openbox_attrib.premax_x = x; + openbox_attrib.premax_y = y; + openbox_attrib.premax_w = w; + openbox_attrib.premax_h = h; + } + + setState(current_state); +} + + +/* + * The reverse of the setGravityOffsets function. Uses the frame window's + * position to find the window's reference point. + */ +void OpenboxWindow::restoreGravity(void) { + // x coordinates for each gravity type + const int x_west = frame.x; + const int x_east = frame.x + frame.width - client.width; + const int x_center = frame.x + (frame.width/2) - client.width; + // y coordinates for each gravity type + const int y_north = frame.y; + const int y_south = frame.y + frame.height - client.height; + const int y_center = frame.y + (frame.height/2) - client.height; + + switch(client.win_gravity) { + default: + case NorthWestGravity: + client.x = x_west; + client.y = y_north; + break; + case NorthGravity: + client.x = x_center; + client.y = y_north; + break; + case NorthEastGravity: + client.x = x_east; + client.y = y_north; + break; + case SouthWestGravity: + client.x = x_west; + client.y = y_south; + break; + case SouthGravity: + client.x = x_center; + client.y = y_south; + break; + case SouthEastGravity: + client.x = x_east; + client.y = y_south; + break; + case WestGravity: + client.x = x_west; + client.y = y_center; + break; + case EastGravity: + client.x = x_east; + client.y = y_center; + break; + case CenterGravity: + client.x = x_center; + client.y = y_center; + break; + case ForgetGravity: + case StaticGravity: + client.x = frame.x + frame.mwm_border_w + frame.border_w; + client.y = frame.y + frame.y_border + frame.mwm_border_w + + frame.border_w; + break; + } +} + + +void OpenboxWindow::redrawLabel(void) { + int dx = frame.bevel_w * 2, dlen = client.title_len; + unsigned int l = client.title_text_w; + + if (flags.focused) { + if (frame.flabel) + XSetWindowBackgroundPixmap(display, frame.label, frame.flabel); + else + XSetWindowBackground(display, frame.label, frame.flabel_pixel); + } else { + if (frame.ulabel) + XSetWindowBackgroundPixmap(display, frame.label, frame.ulabel); + else + XSetWindowBackground(display, frame.label, frame.ulabel_pixel); + } + XClearWindow(display, frame.label); + + if (client.title_text_w > frame.label_w) { + for (; dlen >= 0; dlen--) { + if (i18n->multibyte()) { + XRectangle ink, logical; + XmbTextExtents(screen->getWindowStyle()->fontset, client.title, dlen, + &ink, &logical); + l = logical.width; + } else { + l = XTextWidth(screen->getWindowStyle()->font, client.title, dlen); + } + l += (frame.bevel_w * 4); + + if (l < frame.label_w) + break; + } + } + + switch (screen->getWindowStyle()->justify) { + case BScreen::RightJustify: + dx += frame.label_w - l; + break; + + case BScreen::CenterJustify: + dx += (frame.label_w - l) / 2; + break; + } + + WindowStyle *style = screen->getWindowStyle(); + GC text_gc = (flags.focused) ? style->l_text_focus_gc : + style->l_text_unfocus_gc; + if (i18n->multibyte()) + XmbDrawString(display, frame.label, style->fontset, text_gc, dx, + (1 - style->fontset_extents->max_ink_extent.y), + client.title, dlen); + else + XDrawString(display, frame.label, text_gc, dx, + (style->font->ascent + 1), client.title, dlen); +} + + +void OpenboxWindow::redrawAllButtons(void) { + if (frame.iconify_button) redrawIconifyButton(False); + if (frame.maximize_button) redrawMaximizeButton(flags.maximized); + if (frame.close_button) redrawCloseButton(False); +} + + +void OpenboxWindow::redrawIconifyButton(Bool pressed) { + if (! pressed) { + if (flags.focused) { + if (frame.fbutton) + XSetWindowBackgroundPixmap(display, frame.iconify_button, + frame.fbutton); + else + XSetWindowBackground(display, frame.iconify_button, + frame.fbutton_pixel); + } else { + if (frame.ubutton) + XSetWindowBackgroundPixmap(display, frame.iconify_button, + frame.ubutton); + else + XSetWindowBackground(display, frame.iconify_button, + frame.ubutton_pixel); + } + } else { + if (frame.pbutton) + XSetWindowBackgroundPixmap(display, frame.iconify_button, frame.pbutton); + else + XSetWindowBackground(display, frame.iconify_button, frame.pbutton_pixel); + } + XClearWindow(display, frame.iconify_button); + + XDrawRectangle(display, frame.iconify_button, + ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc : + screen->getWindowStyle()->b_pic_unfocus_gc), + 2, (frame.button_h - 5), (frame.button_w - 5), 2); +} + + +void OpenboxWindow::redrawMaximizeButton(Bool pressed) { + if (! pressed) { + if (flags.focused) { + if (frame.fbutton) + XSetWindowBackgroundPixmap(display, frame.maximize_button, + frame.fbutton); + else + XSetWindowBackground(display, frame.maximize_button, + frame.fbutton_pixel); + } else { + if (frame.ubutton) + XSetWindowBackgroundPixmap(display, frame.maximize_button, + frame.ubutton); + else + XSetWindowBackground(display, frame.maximize_button, + frame.ubutton_pixel); + } + } else { + if (frame.pbutton) + XSetWindowBackgroundPixmap(display, frame.maximize_button, + frame.pbutton); + else + XSetWindowBackground(display, frame.maximize_button, + frame.pbutton_pixel); + } + XClearWindow(display, frame.maximize_button); + + XDrawRectangle(display, frame.maximize_button, + ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc : + screen->getWindowStyle()->b_pic_unfocus_gc), + 2, 2, (frame.button_w - 5), (frame.button_h - 5)); + XDrawLine(display, frame.maximize_button, + ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc : + screen->getWindowStyle()->b_pic_unfocus_gc), + 2, 3, (frame.button_w - 3), 3); +} + + +void OpenboxWindow::redrawCloseButton(Bool pressed) { + if (! pressed) { + if (flags.focused) { + if (frame.fbutton) + XSetWindowBackgroundPixmap(display, frame.close_button, + frame.fbutton); + else + XSetWindowBackground(display, frame.close_button, + frame.fbutton_pixel); + } else { + if (frame.ubutton) + XSetWindowBackgroundPixmap(display, frame.close_button, + frame.ubutton); + else + XSetWindowBackground(display, frame.close_button, + frame.ubutton_pixel); + } + } else { + if (frame.pbutton) + XSetWindowBackgroundPixmap(display, frame.close_button, frame.pbutton); + else + XSetWindowBackground(display, frame.close_button, frame.pbutton_pixel); + } + XClearWindow(display, frame.close_button); + + XDrawLine(display, frame.close_button, + ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc : + screen->getWindowStyle()->b_pic_unfocus_gc), 2, 2, + (frame.button_w - 3), (frame.button_h - 3)); + XDrawLine(display, frame.close_button, + ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc : + screen->getWindowStyle()->b_pic_unfocus_gc), 2, + (frame.button_h - 3), + (frame.button_w - 3), 2); +} + + +void OpenboxWindow::mapRequestEvent(XMapRequestEvent *re) { + if (re->window == client.window) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(WindowSet, WindowMapRequest, + "OpenboxWindow::mapRequestEvent() for 0x%lx\n"), + client.window); +#endif // DEBUG + + openbox->grab(); + if (! validateClient()) return; + + Bool get_state_ret = getState(); + if (! (get_state_ret && openbox->isStartup())) { + if ((client.wm_hint_flags & StateHint) && + (! (current_state == NormalState || current_state == IconicState))) + current_state = client.initial_state; + else + current_state = NormalState; + } else if (flags.iconic) { + current_state = NormalState; + } + + switch (current_state) { + case IconicState: + iconify(); + break; + + case WithdrawnState: + withdraw(); + break; + + case NormalState: + case InactiveState: + case ZoomState: + default: + deiconify(False); + break; + } + + openbox->ungrab(); + } +} + + +void OpenboxWindow::mapNotifyEvent(XMapEvent *ne) { + if ((ne->window == client.window) && (! ne->override_redirect) + && (flags.visible)) { + openbox->grab(); + if (! validateClient()) return; + + if (decorations.titlebar) positionButtons(); + + setState(NormalState); + + redrawAllButtons(); + + if (flags.transient || screen->doFocusNew()) + setInputFocus(); + else + setFocusFlag(False); + + flags.visible = True; + flags.iconic = False; + + openbox->ungrab(); + } +} + + +void OpenboxWindow::unmapNotifyEvent(XUnmapEvent *ue) { + if (ue->window == client.window) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(WindowSet, WindowUnmapNotify, + "OpenboxWindow::unmapNotifyEvent() for 0x%lx\n"), + client.window); +#endif // DEBUG + + openbox->grab(); + if (! validateClient()) return; + + XChangeSaveSet(display, client.window, SetModeDelete); + XSelectInput(display, client.window, NoEventMask); + + XDeleteProperty(display, client.window, openbox->getWMStateAtom()); + XDeleteProperty(display, client.window, + openbox->getOpenboxAttributesAtom()); + + XUnmapWindow(display, frame.window); + XUnmapWindow(display, client.window); + + XEvent dummy; + if (! XCheckTypedWindowEvent(display, client.window, ReparentNotify, + &dummy)) { +#ifdef DEBUG + fprintf(stderr, i18n->getMessage(WindowSet, WindowUnmapNotifyReparent, + "OpenboxWindow::unmapNotifyEvent(): reparent 0x%lx to " + "root.\n"), client.window); +#endif // DEBUG + + restoreGravity(); + XReparentWindow(display, client.window, screen->getRootWindow(), + client.x, client.y); + } + + XFlush(display); + + openbox->ungrab(); + + delete this; + } +} + + +void OpenboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) { + if (de->window == client.window) { + XUnmapWindow(display, frame.window); + + delete this; + } +} + + +void OpenboxWindow::propertyNotifyEvent(Atom atom) { + openbox->grab(); + if (! validateClient()) return; + + switch(atom) { + case XA_WM_CLASS: + case XA_WM_CLIENT_MACHINE: + case XA_WM_COMMAND: + break; + + case XA_WM_TRANSIENT_FOR: + // determine if this is a transient window + Window win; + if (XGetTransientForHint(display, client.window, &win)) { + if (win && (win != client.window)) { + if ((client.transient_for = openbox->searchWindow(win))) { + client.transient_for->client.transient = this; + flags.stuck = client.transient_for->flags.stuck; + flags.transient = True; + } else if (win == client.window_group) { + //jr This doesn't look quite right... + if ((client.transient_for = openbox->searchGroup(win, this))) { + client.transient_for->client.transient = this; + flags.stuck = client.transient_for->flags.stuck; + flags.transient = True; + } + } + } + + if (win == screen->getRootWindow()) flags.modal = True; + } + + // adjust the window decorations based on transience + if (flags.transient) + decorations.maximize = decorations.handle = functions.maximize = False; + + reconfigure(); + + break; + + case XA_WM_HINTS: + getWMHints(); + break; + + case XA_WM_ICON_NAME: + getWMIconName(); + if (flags.iconic) screen->iconUpdate(); + break; + + case XA_WM_NAME: + getWMName(); + + if (decorations.titlebar) + redrawLabel(); + + if (! flags.iconic) + screen->getWorkspace(workspace_number)->update(); + + break; + + case XA_WM_NORMAL_HINTS: { + getWMNormalHints(); + + if ((client.normal_hint_flags & PMinSize) && + (client.normal_hint_flags & PMaxSize)) { + if (client.max_width <= client.min_width && + client.max_height <= client.min_height) + decorations.maximize = decorations.handle = + functions.resize = functions.maximize = False; + else + decorations.maximize = decorations.handle = + functions.resize = functions.maximize = True; + } + + int x = frame.x, y = frame.y; + unsigned int w = frame.width, h = frame.height; + + upsize(); + + if ((x != frame.x) || (y != frame.y) || + (w != frame.width) || (h != frame.height)) + reconfigure(); + + break; + } + + default: + if (atom == openbox->getWMProtocolsAtom()) { + getWMProtocols(); + + if (decorations.close && (! frame.close_button)) { + createCloseButton(); + if (decorations.titlebar) positionButtons(True); + if (windowmenu) windowmenu->reconfigure(); + } + } + + break; + } + + openbox->ungrab(); +} + + +void OpenboxWindow::exposeEvent(XExposeEvent *ee) { + if (frame.label == ee->window && decorations.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); +} + + +void OpenboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) { + if (cr->window == client.window) { + openbox->grab(); + if (! validateClient()) return; + + int cx = frame.x, cy = frame.y; + unsigned int cw = frame.width, ch = frame.height; + + if (cr->value_mask & CWBorderWidth) + client.old_bw = cr->border_width; + + if (cr->value_mask & CWX) + cx = cr->x - frame.mwm_border_w - frame.border_w; + + if (cr->value_mask & CWY) + cy = cr->y - frame.y_border - frame.mwm_border_w - + frame.border_w; + + if (cr->value_mask & CWWidth) + cw = cr->width + (frame.mwm_border_w * 2); + + if (cr->value_mask & CWHeight) + ch = cr->height + frame.y_border + (frame.mwm_border_w * 2) + + (frame.border_w * decorations.handle) + frame.handle_h; + + if (frame.x != cx || frame.y != cy || + frame.width != cw || frame.height != ch) + configure(cx, cy, cw, ch); + + if (cr->value_mask & CWStackMode) { + switch (cr->detail) { + case Above: + case TopIf: + default: + if (flags.iconic) deiconify(); + screen->getWorkspace(workspace_number)->raiseWindow(this); + break; + + case Below: + case BottomIf: + if (flags.iconic) deiconify(); + screen->getWorkspace(workspace_number)->lowerWindow(this); + break; + } + } + + openbox->ungrab(); + } +} + + +void OpenboxWindow::buttonPressEvent(XButtonEvent *be) { + openbox->grab(); + if (! validateClient()) + return; + + int stack_change = 1; // < 0 means to lower the window + // > 0 means to raise the window + // 0 means to leave it where it is + + // alt + left/right click begins interactively moving/resizing the window + // when the mouse is moved + if (be->state == Mod1Mask && (be->button == 1 || be->button == 3)) { + frame.grab_x = be->x_root - frame.x - frame.border_w; + frame.grab_y = be->y_root - frame.y - frame.border_w; + if (be->button == 3) { + if (screen->getWindowZones() == 4 && + be->y < (signed) frame.height / 2) { + resize_zone = ZoneTop; + } else { + resize_zone = ZoneBottom; + } + if (screen->getWindowZones() >= 2 && + be->x < (signed) frame.width / 2) { + resize_zone |= ZoneLeft; + } else { + resize_zone |= ZoneRight; + } + } + // control + left click on the titlebar shades the window + } else if (be->state == ControlMask && be->button == 1) { + if (be->window == frame.title || + be->window == frame.label) + shade(); + // left click + } else if (be->state == 0 && be->button == 1) { + if (windowmenu && windowmenu->isVisible()) + windowmenu->hide(); + + if (be->window == frame.maximize_button) { + redrawMaximizeButton(True); + } else if (be->window == frame.iconify_button) { + redrawIconifyButton(True); + } else if (be->window == frame.close_button) { + redrawCloseButton(True); + } else if (be->window == frame.plate) { + XAllowEvents(display, ReplayPointer, be->time); + } else if (be->window == frame.title || + be->window == frame.label) { + // shade the window when the titlebar is double clicked + if ( (be->time - lastButtonPressTime) <= + openbox->getDoubleClickInterval()) { + lastButtonPressTime = 0; + shade(); + } else { + lastButtonPressTime = be->time; + } + // clicking and dragging on the titlebar moves the window, so on a click + // we need to save the coords of the click in case the user drags + frame.grab_x = be->x_root - frame.x - frame.border_w; + frame.grab_y = be->y_root - frame.y - frame.border_w; + } else if (be->window == frame.handle || + be->window == frame.left_grip || + be->window == frame.right_grip || + be->window == frame.window) { + // clicking and dragging on the window's frame moves the window, so on a + // click we need to save the coords of the click in case the user drags + frame.grab_x = be->x_root - frame.x - frame.border_w; + frame.grab_y = be->y_root - frame.y - frame.border_w; + if (be->window == frame.left_grip) + resize_zone = ZoneBottom | ZoneLeft; + else if (be->window == frame.right_grip) + resize_zone = ZoneBottom | ZoneRight; + } + // middle click + } else if (be->state == 0 && be->button == 2) { + if (be->window == frame.maximize_button) { + redrawMaximizeButton(True); + // a middle click anywhere on the window's frame except for on the buttons + // will lower the window + } else if (! (be->window == frame.iconify_button || + be->window == frame.close_button) ) { + stack_change = -1; + } + // right click + } else if (be->state == 0 && be->button == 3) { + if (be->window == frame.maximize_button) { + redrawMaximizeButton(True); + // a right click on the window's frame will show or hide the window's + // windowmenu + } else if (be->window == frame.title || + be->window == frame.label || + be->window == frame.handle || + be->window == frame.window) { + int mx, my; + if (windowmenu) { + if (windowmenu->isVisible()) { + windowmenu->hide(); + } else { + // get the coords for the menu + mx = be->x_root - windowmenu->getWidth() / 2; + if (be->window == frame.title || be->window == frame.label) { + my = frame.y + frame.title_h; + } else if (be->window = frame.handle) { + my = frame.y + frame.y_handle - windowmenu->getHeight(); + } else { // (be->window == frame.window) + if (be->y <= (signed) frame.bevel_w) { + my = frame.y + frame.y_border; + } else { + my = be->y_root - (windowmenu->getHeight() / 2); + } + } + + if (mx > (signed) (frame.x + frame.width - + windowmenu->getWidth())) { + mx = frame.x + frame.width - windowmenu->getWidth(); + } else if (mx < frame.x) { + mx = frame.x; + } + + if (my > (signed) (frame.y + frame.y_handle - + windowmenu->getHeight())) { + my = frame.y + frame.y_handle - windowmenu->getHeight(); + } else if (my < (signed) (frame.y + + ((decorations.titlebar) ? frame.title_h : frame.y_border))) { + my = frame.y + + ((decorations.titlebar) ? frame.title_h : frame.y_border); + } + + windowmenu->move(mx, my); + windowmenu->show(); + XRaiseWindow(display, windowmenu->getWindowID()); + XRaiseWindow(display, windowmenu->getSendToMenu()->getWindowID()); + stack_change = 0; // dont raise the window overtop of the menu + } + } + } + // mouse wheel up + } else if (be->state == 0 && be->button == 4) { + if ((be->window == frame.label || + be->window == frame.title) && + !flags.shaded) + shade(); + // mouse wheel down + } else if (be->state == 0 && be->button == 5) { + if ((be->window == frame.label || + be->window == frame.title) && + flags.shaded) + shade(); + } + + if (! (flags.focused || screen->isSloppyFocus()) ) { + setInputFocus(); // any click focus' the window in 'click to focus' + } + if (stack_change < 0) { + screen->getWorkspace(workspace_number)->lowerWindow(this); + } else if (stack_change > 0) { + screen->getWorkspace(workspace_number)->raiseWindow(this); + } + + openbox->ungrab(); +} + + +void OpenboxWindow::buttonReleaseEvent(XButtonEvent *re) { + openbox->grab(); + if (! validateClient()) + return; + + // alt + middle button released + if (re->state == (Mod1Mask & Button2Mask) && re->button == 2) { + if (re->window == frame.window) { + XUngrabPointer(display, CurrentTime); // why? i dont know + } + // left button released + } else if (re->button == 1) { + if (re->window == frame.maximize_button) { + if (re->state == Button1Mask && // only the left button was depressed + (re->x >= 0) && ((unsigned) re->x <= frame.button_w) && + (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) { + maximize(re->button); + } else { + redrawMaximizeButton(False); + } + } else if (re->window == frame.iconify_button) { + if (re->state == Button1Mask && // only the left button was depressed + (re->x >= 0) && ((unsigned) re->x <= frame.button_w) && + (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) { + iconify(); + } else { + redrawIconifyButton(False); + } + } else if (re->window == frame.close_button) { + if (re->state == Button1Mask && // only the left button was depressed + (re->x >= 0) && ((unsigned) re->x <= frame.button_w) && + (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) { + close(); + } else { + redrawCloseButton(False); + } + } + // middle button released + } else if (re->button == 2) { + if (re->window == frame.maximize_button) { + if (re->state == Button2Mask && // only the middle button was depressed + (re->x >= 0) && ((unsigned) re->x <= frame.button_w) && + (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) { + maximize(re->button); + } else { + redrawMaximizeButton(False); + } + } + // right button released + } else if (re->button == 3) { + if (re->window == frame.maximize_button) { + if (re->state == Button3Mask && // only the right button was depressed + (re->x >= 0) && ((unsigned) re->x <= frame.button_w) && + (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) { + maximize(re->button); + } else { + redrawMaximizeButton(False); + } + } + } + + // when the window is being interactively moved, a button release stops the + // move where it is + if (flags.moving) { + flags.moving = False; + + openbox->maskWindowEvents(0, (OpenboxWindow *) 0); + if (!screen->doOpaqueMove()) { + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.move_x, frame.move_y, frame.resize_w - 1, + frame.resize_h - 1); + + configure(frame.move_x, frame.move_y, frame.width, frame.height); + openbox->ungrab(); + } else { + configure(frame.x, frame.y, frame.width, frame.height); + } + screen->hideGeometry(); + XUngrabPointer(display, CurrentTime); + // when the window is being interactively resized, a button release stops the + // resizing + } else if (flags.resizing) { + flags.resizing = False; + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.resize_x, frame.resize_y, + frame.resize_w - 1, frame.resize_h - 1); + screen->hideGeometry(); + if (resize_zone & ZoneLeft) { + left_fixsize(); + } else { // when resizing with "Alt+Button3", the resize is the same as if + // done with the right grip (the right side of the window is what + // moves) + right_fixsize(); + } + // unset maximized state when resized after fully maximized + if (flags.maximized == 1) { + maximize(0); + } + configure(frame.resize_x, frame.resize_y, + frame.resize_w - (frame.border_w * 2), + frame.resize_h - (frame.border_w * 2)); + openbox->ungrab(); + XUngrabPointer(display, CurrentTime); + resize_zone = 0; + } + + openbox->ungrab(); +} + + +void OpenboxWindow::motionNotifyEvent(XMotionEvent *me) { + if (!flags.resizing && (me->state & Button1Mask) && functions.move && + (frame.title == me->window || frame.label == me->window || + frame.handle == me->window || frame.window == me->window)) { + if (! flags.moving) { + XGrabPointer(display, me->window, False, Button1MotionMask | + ButtonReleaseMask, GrabModeAsync, GrabModeAsync, + None, openbox->getMoveCursor(), CurrentTime); + + if (windowmenu && windowmenu->isVisible()) + windowmenu->hide(); + + flags.moving = True; + + openbox->maskWindowEvents(client.window, this); + + if (! screen->doOpaqueMove()) { + openbox->grab(); + + frame.move_x = frame.x; + frame.move_y = frame.y; + frame.resize_w = frame.width + (frame.border_w * 2); + frame.resize_h = ((flags.shaded) ? frame.title_h : frame.height) + + (frame.border_w * 2); + + screen->showPosition(frame.x, frame.y); + + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.move_x, frame.move_y, + frame.resize_w - 1, frame.resize_h - 1); + } + } else { + int dx = me->x_root - frame.grab_x, dy = me->y_root - frame.grab_y; + + dx -= frame.border_w; + dy -= frame.border_w; + + int snap_distance = screen->getEdgeSnapThreshold(); + if (snap_distance) { + int drx = screen->getWidth() - (dx + frame.snap_w); + + if (dx < drx && (dx > 0 && dx < snap_distance) || + (dx < 0 && dx > -snap_distance) ) + dx = 0; + else if ( (drx > 0 && drx < snap_distance) || + (drx < 0 && drx > -snap_distance) ) + dx = screen->getWidth() - frame.snap_w; + + int dtty, dbby, dty, dby; + switch (screen->getToolbarPlacement()) { + case Toolbar::TopLeft: + case Toolbar::TopCenter: + case Toolbar::TopRight: + dtty = screen->getToolbar()->getExposedHeight() + + frame.border_w; + dbby = screen->getHeight(); + break; + + default: + dtty = 0; + dbby = screen->getToolbar()->getY(); + break; + } + + dty = dy - dtty; + dby = dbby - (dy + frame.snap_h); + + if ( (dy > 0 && dty < snap_distance) || + (dy < 0 && dty > -snap_distance) ) + dy = dtty; + else if ( (dby > 0 && dby < snap_distance) || + (dby < 0 && dby > -snap_distance) ) + dy = dbby - frame.snap_h; + } + + if (screen->doOpaqueMove()) { + configure(dx, dy, frame.width, frame.height); + } else { + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.move_x, frame.move_y, frame.resize_w - 1, + frame.resize_h - 1); + + frame.move_x = dx; + frame.move_y = dy; + + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.move_x, frame.move_y, frame.resize_w - 1, + frame.resize_h - 1); + } + + screen->showPosition(dx, dy); + } + } else if (functions.resize && + (((me->state & Button1Mask) && (me->window == frame.right_grip || + me->window == frame.left_grip)) || + (me->state & (Mod1Mask | Button3Mask) && + me->window == frame.window))) { + Bool left = resize_zone & ZoneLeft; + + if (! flags.resizing) { + Cursor cursor; + if (resize_zone & ZoneTop) + cursor = (resize_zone & ZoneLeft) ? + openbox->getUpperLeftAngleCursor() : + openbox->getUpperRightAngleCursor(); + else + cursor = (resize_zone & ZoneLeft) ? + openbox->getLowerLeftAngleCursor() : + openbox->getLowerRightAngleCursor(); + XGrabPointer(display, me->window, False, ButtonMotionMask | + ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, + cursor, CurrentTime); + + flags.resizing = True; + + openbox->grab(); + + int gx, gy; + if (resize_zone & ZoneRight) + frame.grab_x = me->x - screen->getBorderWidth(); + else + frame.grab_x = me->x + screen->getBorderWidth(); + if (resize_zone & ZoneTop) + frame.grab_y = me->y + screen->getBorderWidth() * 2; + else + frame.grab_y = me->y - screen->getBorderWidth() * 2; + frame.resize_x = frame.x; + frame.resize_y = frame.y; + frame.resize_w = frame.width + (frame.border_w * 2); + frame.resize_h = frame.height + (frame.border_w * 2); + + if (left) + left_fixsize(&gx, &gy); + else + right_fixsize(&gx, &gy); + + screen->showGeometry(gx, gy); + + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.resize_x, frame.resize_y, + frame.resize_w - 1, frame.resize_h - 1); + } else { + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.resize_x, frame.resize_y, + frame.resize_w - 1, frame.resize_h - 1); + + int gx, gy; + + if (resize_zone & ZoneTop) + frame.resize_h = frame.height - (me->y - frame.grab_y); + else + frame.resize_h = frame.height + (me->y - frame.grab_y); + if (frame.resize_h < 1) frame.resize_h = 1; + + if (left) { + frame.resize_x = me->x_root - frame.grab_x; + if (frame.resize_x > (signed) (frame.x + frame.width)) + frame.resize_x = frame.resize_x + frame.width - 1; + + left_fixsize(&gx, &gy); + } else { + frame.resize_w = frame.width + (me->x - frame.grab_x); + if (frame.resize_w < 1) frame.resize_w = 1; + + right_fixsize(&gx, &gy); + } + + XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(), + frame.resize_x, frame.resize_y, + frame.resize_w - 1, frame.resize_h - 1); + + screen->showGeometry(gx, gy); + } + } +} + + +#ifdef SHAPE +void OpenboxWindow::shapeEvent(XShapeEvent *) { + if (openbox->hasShapeExtensions()) { + if (flags.shaped) { + openbox->grab(); + if (! validateClient()) return; + XShapeCombineShape(display, frame.window, ShapeBounding, + frame.mwm_border_w, frame.y_border + + frame.mwm_border_w, client.window, + ShapeBounding, ShapeSet); + + int num = 1; + XRectangle xrect[2]; + xrect[0].x = xrect[0].y = 0; + xrect[0].width = frame.width; + xrect[0].height = frame.y_border; + + if (decorations.handle) { + xrect[1].x = 0; + xrect[1].y = frame.y_handle; + xrect[1].width = frame.width; + xrect[1].height = frame.handle_h + frame.border_w; + num++; + } + + XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0, + xrect, num, ShapeUnion, Unsorted); + openbox->ungrab(); + } + } +} +#endif // SHAPE + + +Bool OpenboxWindow::validateClient(void) { + XSync(display, False); + + XEvent e; + if (XCheckTypedWindowEvent(display, client.window, DestroyNotify, &e) || + XCheckTypedWindowEvent(display, client.window, UnmapNotify, &e)) { + XPutBackEvent(display, &e); + openbox->ungrab(); + + return False; + } + + return True; +} + + +void OpenboxWindow::restore(void) { + XChangeSaveSet(display, client.window, SetModeDelete); + XSelectInput(display, client.window, NoEventMask); + + restoreGravity(); + + XUnmapWindow(display, frame.window); + XUnmapWindow(display, client.window); + + XSetWindowBorderWidth(display, client.window, client.old_bw); + XReparentWindow(display, client.window, screen->getRootWindow(), + client.x, client.y); + XMapWindow(display, client.window); + + XFlush(display); +} + + +void OpenboxWindow::timeout(void) { + screen->getWorkspace(workspace_number)->raiseWindow(this); +} + + +void OpenboxWindow::changeOpenboxHints(OpenboxHints *net) { + if ((net->flags & AttribShaded) && + ((openbox_attrib.attrib & AttribShaded) != + (net->attrib & AttribShaded))) + shade(); + + if (flags.visible && // watch out for requests when we can not be seen + (net->flags & (AttribMaxVert | AttribMaxHoriz)) && + ((openbox_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) && + ((openbox_attrib.attrib & AttribOmnipresent) != + (net->attrib & AttribOmnipresent))) + stick(); + + if ((net->flags & AttribWorkspace) && + (workspace_number != (signed) net->workspace)) { + screen->reassociateWindow(this, net->workspace, True); + + if (screen->getCurrentWorkspaceID() != (signed) net->workspace) withdraw(); + else deiconify(); + } + + if (net->flags & AttribDecoration) { + switch (net->decoration) { + case DecorNone: + decorations.titlebar = decorations.border = decorations.handle = + decorations.iconify = decorations.maximize = decorations.menu = False; + + break; + + default: + case DecorNormal: + decorations.titlebar = decorations.border = decorations.handle = + decorations.iconify = decorations.maximize = decorations.menu = True; + + break; + + case DecorTiny: + decorations.titlebar = decorations.iconify = decorations.menu = True; + decorations.border = decorations.handle = decorations.maximize = False; + + break; + + case DecorTool: + decorations.titlebar = decorations.menu = functions.move = True; + decorations.iconify = decorations.border = decorations.handle = + decorations.maximize = False; + + break; + } + if (frame.window) { + XMapSubwindows(display, frame.window); + XMapWindow(display, frame.window); + } + + reconfigure(); + setState(current_state); + } +} + + +/* + * 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 dimentions. + */ +void OpenboxWindow::upsize(void) { + frame.bevel_w = screen->getBevelWidth(); + + if (decorations.border) { + frame.border_w = screen->getBorderWidth(); + if (!flags.transient) + frame.mwm_border_w = screen->getFrameWidth(); + else + frame.mwm_border_w = 0; + } else { + frame.mwm_border_w = frame.border_w = 0; + } + + if (decorations.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(); + if (i18n->multibyte()) + frame.title_h = (style->fontset_extents->max_ink_extent.height + + (frame.bevel_w * 2) + 2); + else + frame.title_h = (style->font->ascent + style->font->descent + + (frame.bevel_w * 2) + 2); + + frame.label_h = frame.title_h - (frame.bevel_w * 2); + frame.button_w = frame.button_h = (frame.label_h - 2); + frame.y_border = frame.title_h + frame.border_w; + } else { + frame.title_h = 0; + frame.label_h = 0; + frame.button_w = frame.button_h = 0; + frame.y_border = 0; + } + + frame.border_h = client.height + frame.mwm_border_w * 2; + + if (decorations.handle) { + frame.y_handle = frame.y_border + frame.border_h + frame.border_w; + frame.grip_w = frame.button_w * 2; + frame.grip_h = frame.handle_h = screen->getHandleWidth(); + } else { + frame.y_handle = frame.y_border + frame.border_h; + frame.handle_h = 0; + frame.grip_w = frame.grip_h = 0; + } + + frame.width = client.width + (frame.mwm_border_w * 2); + frame.height = frame.y_handle + frame.handle_h; + + frame.snap_w = frame.width + (frame.border_w * 2); + frame.snap_h = frame.height + (frame.border_w * 2); +} + + +/* + * Set the size and position of the client window. + * These values are based upon the current style settings and the frame + * window's dimensions. + */ +void OpenboxWindow::downsize(void) { + frame.y_handle = frame.height - frame.handle_h; + frame.border_h = frame.y_handle - frame.y_border - + (decorations.handle ? frame.border_w : 0); + + client.x = frame.x + frame.mwm_border_w + frame.border_w; + client.y = frame.y + frame.y_border + frame.mwm_border_w + frame.border_w; + + client.width = frame.width - (frame.mwm_border_w * 2); + client.height = frame.height - frame.y_border - (frame.mwm_border_w * 2) + - frame.handle_h - (decorations.handle ? frame.border_w : 0); + + frame.y_handle = frame.border_h + frame.y_border + frame.border_w; + + frame.snap_w = frame.width + (frame.border_w * 2); + frame.snap_h = frame.height + (frame.border_w * 2); +} + + +void OpenboxWindow::right_fixsize(int *gx, int *gy) { + // calculate the size of the client window and conform it to the + // size specified by the size hints of the client window... + int dx = frame.resize_w - client.base_width - (frame.mwm_border_w * 2) - + (frame.border_w * 2) + (client.width_inc / 2); + int dy = frame.resize_h - frame.y_border - client.base_height - + frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2) + + (client.height_inc / 2); + + if (dx < (signed) client.min_width) dx = client.min_width; + if (dy < (signed) client.min_height) dy = client.min_height; + if ((unsigned) dx > client.max_width) dx = client.max_width; + if ((unsigned) dy > client.max_height) dy = client.max_height; + + dx /= client.width_inc; + dy /= client.height_inc; + + if (gx) *gx = dx; + if (gy) *gy = dy; + + dx = (dx * client.width_inc) + client.base_width; + dy = (dy * client.height_inc) + client.base_height; + + frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2); + frame.resize_h = dy + frame.y_border + frame.handle_h + + (frame.mwm_border_w * 2) + (frame.border_w * 3); + if (resize_zone & ZoneTop) + frame.resize_y = frame.y + frame.height - frame.resize_h + + screen->getBorderWidth() * 2; +} + + +void OpenboxWindow::left_fixsize(int *gx, int *gy) { + // calculate the size of the client window and conform it to the + // size specified by the size hints of the client window... + int dx = frame.x + frame.width - frame.resize_x - client.base_width - + (frame.mwm_border_w * 2) + (client.width_inc / 2); + int dy = frame.resize_h - frame.y_border - client.base_height - + frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2) + + (client.height_inc / 2); + + if (dx < (signed) client.min_width) dx = client.min_width; + if (dy < (signed) client.min_height) dy = client.min_height; + if ((unsigned) dx > client.max_width) dx = client.max_width; + if ((unsigned) dy > client.max_height) dy = client.max_height; + + dx /= client.width_inc; + dy /= client.height_inc; + + if (gx) *gx = dx; + if (gy) *gy = dy; + + dx = (dx * client.width_inc) + client.base_width; + dy = (dy * client.height_inc) + client.base_height; + + frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2); + frame.resize_x = frame.x + frame.width - frame.resize_w + + (frame.border_w * 2); + frame.resize_h = dy + frame.y_border + frame.handle_h + + (frame.mwm_border_w * 2) + (frame.border_w * 3); + if (resize_zone & ZoneTop) + frame.resize_y = frame.y + frame.height - frame.resize_h + + screen->getBorderWidth() * 2; + +} diff --git a/src/Window.h b/src/Window.h new file mode 100644 index 00000000..d6e9f809 --- /dev/null +++ b/src/Window.h @@ -0,0 +1,330 @@ +// Window.h for Openbox +// 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 __Window_hh +#define __Window_hh + +#include +#include +#ifdef SHAPE +# include +#endif // SHAPE + +#include "BaseDisplay.h" +#include "Timer.h" +#include "Windowmenu.h" + +// forward declaration +class OpenboxWindow; + +#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) +#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 OpenboxWindow : public TimeoutHandler { +private: + BImageControl *image_ctrl; + Openbox *openbox; + BScreen *screen; + Display *display; + BTimer *timer; + OpenboxAttributes openbox_attrib; + + Time lastButtonPressTime; // used for double clicks, when were we clicked + Windowmenu *windowmenu; + + int window_number, workspace_number; + unsigned long current_state; + + enum FocusMode { F_NoInput = 0, F_Passive, + F_LocallyActive, F_GloballyActive }; + FocusMode focus_mode; + + enum ResizeZones { + ZoneTop = 1 << 0, + ZoneBottom = 1 << 1, + ZoneLeft = 1 << 2, + ZoneRight = 1 << 3 + }; + unsigned int resize_zone; // bitmask of ResizeZones values + + struct _flags { + Bool moving, // is moving? + resizing, // is resizing? + shaded, // is shaded? + visible, // is visible? + iconic, // is iconified? + transient, // is a transient window? + focused, // has focus? + stuck, // is omnipresent + modal, // is modal? (must be dismissed to continue) + send_focus_message, // should we send focus messages to our client? + shaped, // does the frame use the shape extension? + managed; // under openbox's control? + // maximize is special, the number corresponds + // with a mouse button + // if 0, not maximized + unsigned int maximized; // 1 = HorizVert, 2 = Vertical, 3 = Horizontal + } flags; + + struct _client { + OpenboxWindow *transient_for, // which window are we a transient for? + *transient; // which window is our transient? + + Window window, // the client's window + window_group; // the client's window group + + char *title, *icon_title; + size_t title_len; // strlen(title) + + int x, y, + old_bw; // client's borderwidth + + unsigned int width, height, + title_text_w, // width as rendered in the current font + min_width, min_height, // can not be resized smaller + max_width, max_height, // can not be resized larger + width_inc, height_inc, // increment step + min_aspect_x, min_aspect_y, // minimum aspect ratio + max_aspect_x, max_aspect_y, // maximum aspect ratio + base_width, base_height, + win_gravity; + + unsigned long initial_state, normal_hint_flags, wm_hint_flags; + + MwmHints *mwm_hint; + OpenboxHints *openbox_hint; + } client; + + struct _functions { + Bool resize, move, iconify, maximize, close; + } functions; + + /* + * 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 + */ + + /* + * what decorations do we have? + * this is based on the type of the client window as well as user input + * the menu is not really decor, but it goes hand in hand with the decor + */ + struct _decorations { + Bool titlebar, handle, border, iconify, maximize, close, menu; + } decorations; + + struct _frame { + // u -> unfocused, f -> has focus + unsigned long ulabel_pixel, flabel_pixel, utitle_pixel, + ftitle_pixel, uhandle_pixel, fhandle_pixel, ubutton_pixel, + fbutton_pixel, pbutton_pixel, uborder_pixel, fborder_pixel, + ugrip_pixel, fgrip_pixel; + Pixmap ulabel, flabel, utitle, ftitle, uhandle, fhandle, + ubutton, fbutton, pbutton, ugrip, fgrip; + + Window window, // the frame + plate, // holds the client + title, + label, + handle, + close_button, iconify_button, maximize_button, + right_grip, left_grip; + + + unsigned int resize_w, resize_h; + int resize_x, resize_y, // size and location of box drawn while resizing + move_x, move_y; // location of box drawn while moving + + int x, y, + grab_x, grab_y, // where was the window when it was grabbed? + y_border, y_handle; // where within frame is the border and handle + + unsigned int width, height, title_h, label_w, label_h, handle_h, + button_w, button_h, grip_w, grip_h, mwm_border_w, border_h, border_w, + bevel_w, snap_w, snap_h; + } frame; + +protected: + Bool getState(void); + Window createToplevelWindow(int x, int y, unsigned int width, + unsigned int height, unsigned int borderwidth); + Window createChildWindow(Window parent, Cursor = None); + + void getWMName(void); + void getWMIconName(void); + void getWMNormalHints(void); + void getWMProtocols(void); + void getWMHints(void); + void getMWMHints(void); + void getOpenboxHints(void); + void setNetWMAttributes(void); + void associateClientWindow(void); + void decorate(void); + void decorateLabel(void); + void positionButtons(Bool redecorate_label = False); + void positionWindows(void); + void createCloseButton(void); + void createIconifyButton(void); + void createMaximizeButton(void); + void redrawLabel(void); + void redrawAllButtons(void); + void redrawCloseButton(Bool); + void redrawIconifyButton(Bool); + void redrawMaximizeButton(Bool); + void restoreGravity(void); + void setGravityOffsets(void); + void setState(unsigned long); + void upsize(void); + void downsize(void); + void right_fixsize(int *gx = 0, int *gy = 0); + void left_fixsize(int *gx = 0, int *gy = 0); + + +public: + OpenboxWindow(Openbox *b, Window w, BScreen *s = (BScreen *) 0); + virtual ~OpenboxWindow(void); + + inline Bool isTransient(void) const { return flags.transient; } + 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 isMaximizedFull(void) const { return flags.maximized == 1; } + inline Bool isStuck(void) const { return flags.stuck; } + inline Bool isIconifiable(void) const { return functions.iconify; } + inline Bool isMaximizable(void) const { return functions.maximize; } + inline Bool isResizable(void) const { return functions.resize; } + inline Bool isClosable(void) const { return functions.close; } + + inline Bool hasTitlebar(void) const { return decorations.titlebar; } + inline Bool hasTransient(void) const + { return ((client.transient) ? True : False); } + + inline OpenboxWindow *getTransient(void) { return client.transient; } + inline OpenboxWindow *getTransientFor(void) { return client.transient_for; } + + inline BScreen *getScreen(void) { return screen; } + + inline const Window &getFrameWindow(void) const { return frame.window; } + inline const Window &getClientWindow(void) const { return client.window; } + + inline Windowmenu * getWindowmenu(void) { return windowmenu; } + + inline char **getTitle(void) { return &client.title; } + inline char **getIconTitle(void) { return &client.icon_title; } + inline const int &getXFrame(void) const { return frame.x; } + inline const int &getYFrame(void) const { return frame.y; } + inline const int &getXClient(void) const { return client.x; } + inline const int &getYClient(void) const { return client.y; } + inline const int &getWorkspaceNumber(void) const { return workspace_number; } + inline const int &getWindowNumber(void) const { return window_number; } + + inline const unsigned int &getWidth(void) const { return frame.width; } + inline const unsigned int &getHeight(void) const { return frame.height; } + inline const unsigned int &getClientHeight(void) const + { return client.height; } + inline const unsigned int &getClientWidth(void) const + { return client.width; } + inline const unsigned int &getTitleHeight(void) const + { return frame.title_h; } + + inline void setWindowNumber(int n) { window_number = n; } + + Bool validateClient(void); + Bool setInputFocus(void); + + void setFocusFlag(Bool); + void iconify(void); + void deiconify(Bool reassoc = True, Bool raise = True); + void close(void); + void withdraw(void); + void maximize(unsigned int button); + void shade(void); + void stick(void); + void unstick(void); + void reconfigure(void); + void installColormap(Bool); + void restore(void); + void configure(int dx, int dy, unsigned int dw, unsigned int dh); + void setWorkspace(int n); + void changeOpenboxHints(OpenboxHints *); + void restoreAttributes(void); + + void buttonPressEvent(XButtonEvent *); + void buttonReleaseEvent(XButtonEvent *); + void motionNotifyEvent(XMotionEvent *); + void destroyNotifyEvent(XDestroyWindowEvent *); + void mapRequestEvent(XMapRequestEvent *); + void mapNotifyEvent(XMapEvent *); + void unmapNotifyEvent(XUnmapEvent *); + void propertyNotifyEvent(Atom); + void exposeEvent(XExposeEvent *); + void configureRequestEvent(XConfigureRequestEvent *); + +#ifdef SHAPE + void shapeEvent(XShapeEvent *); +#endif // SHAPE + + virtual void timeout(void); +}; + + +#endif // __Window_hh diff --git a/src/Windowmenu.cc b/src/Windowmenu.cc new file mode 100644 index 00000000..d9da5b86 --- /dev/null +++ b/src/Windowmenu.cc @@ -0,0 +1,204 @@ +// Windowmenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "openbox.h" +#include "Screen.h" +#include "Window.h" +#include "Windowmenu.h" +#include "Workspace.h" + +#ifdef STDC_HEADERS +# include +#endif // STDC_HEADERS + + +Windowmenu::Windowmenu(OpenboxWindow *win) : Basemenu(win->getScreen()) { + window = win; + screen = window->getScreen(); + + setTitleVisibility(False); + setMovable(False); + setInternalMenu(); + + sendToMenu = new SendtoWorkspacemenu(this); + insert(i18n->getMessage(WindowmenuSet, WindowmenuSendTo, "Send To ..."), + sendToMenu); + insert(i18n->getMessage(WindowmenuSet, WindowmenuShade, "Shade"), + BScreen::WindowShade); + insert(i18n->getMessage(WindowmenuSet, WindowmenuIconify, "Iconify"), + BScreen::WindowIconify); + insert(i18n->getMessage(WindowmenuSet, WindowmenuMaximize, "Maximize"), + BScreen::WindowMaximize); + insert(i18n->getMessage(WindowmenuSet, WindowmenuRaise,"Raise"), + BScreen::WindowRaise); + insert(i18n->getMessage(WindowmenuSet, WindowmenuLower, "Lower"), + BScreen::WindowLower); + insert(i18n->getMessage(WindowmenuSet, WindowmenuStick, "Stick"), + BScreen::WindowStick); + insert(i18n->getMessage(WindowmenuSet, WindowmenuKillClient, "Kill Client"), + BScreen::WindowKill); + insert(i18n->getMessage(WindowmenuSet, WindowmenuClose, "Close"), + BScreen::WindowClose); + + update(); + + setItemEnabled(1, window->hasTitlebar()); + setItemEnabled(2, window->isIconifiable()); + setItemEnabled(3, window->isMaximizable()); + setItemEnabled(8, window->isClosable()); +} + + +Windowmenu::~Windowmenu(void) { + delete sendToMenu; +} + + +void Windowmenu::show(void) { + if (isItemEnabled(1)) setItemSelected(1, window->isShaded()); + if (isItemEnabled(3)) setItemSelected(3, window->isMaximized()); + if (isItemEnabled(6)) setItemSelected(6, window->isStuck()); + + Basemenu::show(); +} + + +void Windowmenu::itemSelected(int button, int index) { + BasemenuItem *item = find(index); + + /* Added by Scott Moynes, April 8, 2002 + Ignore the middle button for every item except the maximize + button in the window menu. Maximize needs it for + horizontal/vertical maximize, however, for the others it is + inconsistent with the rest of the window behaviour. + */ + if(button != 2) { + hide(); + switch (item->function()) { + case BScreen::WindowShade: + window->shade(); + break; + + case BScreen::WindowIconify: + window->iconify(); + break; + + case BScreen::WindowMaximize: + window->maximize((unsigned int) button); + break; + + case BScreen::WindowClose: + window->close(); + break; + + case BScreen::WindowRaise: + screen->getWorkspace(window->getWorkspaceNumber())->raiseWindow(window); + break; + + case BScreen::WindowLower: + screen->getWorkspace(window->getWorkspaceNumber())->lowerWindow(window); + break; + + case BScreen::WindowStick: + window->stick(); + break; + + case BScreen::WindowKill: + XKillClient(screen->getBaseDisplay()->getXDisplay(), + window->getClientWindow()); + break; + } + } else if (item->function() == BScreen::WindowMaximize) { + hide(); + window->maximize((unsigned int) button); + } +} + + +void Windowmenu::reconfigure(void) { + setItemEnabled(1, window->hasTitlebar()); + setItemEnabled(2, window->isIconifiable()); + setItemEnabled(3, window->isMaximizable()); + setItemEnabled(8, window->isClosable()); + + sendToMenu->reconfigure(); + + Basemenu::reconfigure(); +} + + +Windowmenu::SendtoWorkspacemenu::SendtoWorkspacemenu(Windowmenu *w) + : Basemenu(w->screen) { + windowmenu = w; + + setTitleVisibility(False); + setMovable(False); + setInternalMenu(); + update(); +} + + +void Windowmenu::SendtoWorkspacemenu::itemSelected(int button, int index) { + if (button > 2) return; + + if (index <= windowmenu->screen->getCount()) { + if (index == windowmenu->screen->getCurrentWorkspaceID()) return; + if (windowmenu->window->isStuck()) windowmenu->window->stick(); + + if (button == 1) windowmenu->window->withdraw(); + windowmenu->screen->reassociateWindow(windowmenu->window, index, True); + if (button == 2) windowmenu->screen->changeWorkspaceID(index); + } + hide(); +} + + +void Windowmenu::SendtoWorkspacemenu::update(void) { + int i, r = getCount(); + + if (r != 0) + for (i = 0; i < r; ++i) + remove(0); + + for (i = 0; i < windowmenu->screen->getCount(); ++i) + insert(windowmenu->screen->getWorkspace(i)->getName()); + + Basemenu::update(); +} + + +void Windowmenu::SendtoWorkspacemenu::show(void) { + update(); + + Basemenu::show(); +} diff --git a/src/Windowmenu.h b/src/Windowmenu.h new file mode 100644 index 00000000..53206df4 --- /dev/null +++ b/src/Windowmenu.h @@ -0,0 +1,78 @@ +// Windowmenu.h for Openbox +// 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 __Windowmenu_hh +#define __Windowmenu_hh + +#include "Basemenu.h" + +// forward declaration +class Windowmenu; +class SendtoWorkspaceMenu; + +class Openbox; +class OpenboxWindow; +class Toolbar; + +class Windowmenu : public Basemenu { +private: + OpenboxWindow *window; + BScreen *screen; + + class SendtoWorkspacemenu : public Basemenu { + private: + Windowmenu *windowmenu; + + protected: + virtual void itemSelected(int, int); + + public: + SendtoWorkspacemenu(Windowmenu *); + + void update(void); + + virtual void show(void); + }; + + SendtoWorkspacemenu *sendToMenu; + + friend class SendtoWorkspacemenu; + + +protected: + virtual void itemSelected(int, int); + + +public: + Windowmenu(OpenboxWindow *); + virtual ~Windowmenu(void); + + inline Basemenu *getSendToMenu(void) { return (Basemenu *) sendToMenu; } + + void reconfigure(void); + void setClosable(void); + + virtual void show(void); +}; + + +#endif // __Windowmenu_hh diff --git a/src/Workspace.cc b/src/Workspace.cc new file mode 100644 index 00000000..fa1f7990 --- /dev/null +++ b/src/Workspace.cc @@ -0,0 +1,502 @@ +// Workspace.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include +#include + +#include "i18n.h" +#include "openbox.h" +#include "Clientmenu.h" +#include "Screen.h" +#include "Toolbar.h" +#include "Window.h" +#include "Workspace.h" +#include "Windowmenu.h" + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +#endif // STDC_HEADERS + + +Workspace::Workspace(BScreen *scrn, int i) { + screen = scrn; + + cascade_x = cascade_y = 32; + + id = i; + + stackingList = new LinkedList; + windowList = new LinkedList; + clientmenu = new Clientmenu(this); + + lastfocus = (OpenboxWindow *) 0; + + name = (char *) 0; + char *tmp = screen->getNameOfWorkspace(id); + setName(tmp); +} + + +Workspace::~Workspace(void) { + delete stackingList; + delete windowList; + delete clientmenu; + + if (name) + delete [] name; +} + + +const int Workspace::addWindow(OpenboxWindow *w, Bool place) { + if (! w) return -1; + + if (place) placeWindow(w); + + w->setWorkspace(id); + w->setWindowNumber(windowList->count()); + + stackingList->insert(w, 0); + windowList->insert(w); + + clientmenu->insert((const char **) w->getTitle()); + clientmenu->update(); + + screen->updateNetizenWindowAdd(w->getClientWindow(), id); + + raiseWindow(w); + + return w->getWindowNumber(); +} + + +const int Workspace::removeWindow(OpenboxWindow *w) { + if (! w) return -1; + + stackingList->remove(w); + + if (w->isFocused()) { + if (w->isTransient() && w->getTransientFor() && + w->getTransientFor()->isVisible()) { + w->getTransientFor()->setInputFocus(); + } else if (screen->isSloppyFocus()) { + screen->getOpenbox()->setFocusedWindow((OpenboxWindow *) 0); + } else { + OpenboxWindow *top = stackingList->first(); + if (! top || ! top->setInputFocus()) { + screen->getOpenbox()->setFocusedWindow((OpenboxWindow *) 0); + XSetInputFocus(screen->getOpenbox()->getXDisplay(), + screen->getToolbar()->getWindowID(), + RevertToParent, CurrentTime); + } + } + } + + if (lastfocus == w) + lastfocus = (OpenboxWindow *) 0; + + windowList->remove(w->getWindowNumber()); + clientmenu->remove(w->getWindowNumber()); + clientmenu->update(); + + screen->updateNetizenWindowDel(w->getClientWindow()); + + LinkedListIterator it(windowList); + OpenboxWindow *bw = it.current(); + for (int i = 0; bw; it++, i++, bw = it.current()) + bw->setWindowNumber(i); + + return windowList->count(); +} + + +void Workspace::showAll(void) { + LinkedListIterator it(stackingList); + for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) + bw->deiconify(False, False); +} + + +void Workspace::hideAll(void) { + LinkedList lst; + + LinkedListIterator it(stackingList); + for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) + lst.insert(bw, 0); + + LinkedListIterator it2(&lst); + for (OpenboxWindow *bw = it2.current(); bw; it2++, bw = it2.current()) + if (! bw->isStuck()) + bw->withdraw(); +} + + +void Workspace::removeAll(void) { + LinkedListIterator it(windowList); + for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) + bw->iconify(); +} + + +void Workspace::raiseWindow(OpenboxWindow *w) { + OpenboxWindow *win = (OpenboxWindow *) 0, *bottom = w; + + while (bottom->isTransient() && bottom->getTransientFor()) + bottom = bottom->getTransientFor(); + + int i = 1; + win = bottom; + while (win->hasTransient() && win->getTransient()) { + win = win->getTransient(); + + i++; + } + + Window *nstack = new Window[i], *curr = nstack; + Workspace *wkspc; + + win = bottom; + while (True) { + *(curr++) = win->getFrameWindow(); + screen->updateNetizenWindowRaise(win->getClientWindow()); + + if (! win->isIconic()) { + wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList->remove(win); + wkspc->stackingList->insert(win, 0); + } + + if (! win->hasTransient() || ! win->getTransient()) + break; + + win = win->getTransient(); + } + + screen->raiseWindows(nstack, i); + + delete [] nstack; +} + + +void Workspace::lowerWindow(OpenboxWindow *w) { + OpenboxWindow *win = (OpenboxWindow *) 0, *bottom = w; + + while (bottom->isTransient() && bottom->getTransientFor()) + bottom = bottom->getTransientFor(); + + int i = 1; + win = bottom; + while (win->hasTransient() && win->getTransient()) { + win = win->getTransient(); + + i++; + } + + Window *nstack = new Window[i], *curr = nstack; + Workspace *wkspc; + + while (True) { + *(curr++) = win->getFrameWindow(); + screen->updateNetizenWindowLower(win->getClientWindow()); + + if (! win->isIconic()) { + wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + wkspc->stackingList->remove(win); + wkspc->stackingList->insert(win); + } + + if (! win->getTransientFor()) + break; + + win = win->getTransientFor(); + } + + screen->getOpenbox()->grab(); + + XLowerWindow(screen->getBaseDisplay()->getXDisplay(), *nstack); + XRestackWindows(screen->getBaseDisplay()->getXDisplay(), nstack, i); + + screen->getOpenbox()->ungrab(); + + delete [] nstack; +} + + +void Workspace::reconfigure(void) { + clientmenu->reconfigure(); + + LinkedListIterator it(windowList); + for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current()) { + if (bw->validateClient()) + bw->reconfigure(); + } +} + + +OpenboxWindow *Workspace::getWindow(int index) { + if ((index >= 0) && (index < windowList->count())) + return windowList->find(index); + else + return 0; +} + + +const int Workspace::getCount(void) { + return windowList->count(); +} + + +void Workspace::update(void) { + clientmenu->update(); + screen->getToolbar()->redrawWindowLabel(True); +} + + +Bool Workspace::isCurrent(void) { + return (id == screen->getCurrentWorkspaceID()); +} + + +Bool Workspace::isLastWindow(OpenboxWindow *w) { + return (w == windowList->last()); +} + +void Workspace::setCurrent(void) { + screen->changeWorkspaceID(id); +} + + +void Workspace::setName(char *new_name) { + if (name) + delete [] name; + + if (new_name) { + name = bstrdup(new_name); + } else { + name = new char[128]; + sprintf(name, i18n->getMessage(WorkspaceSet, WorkspaceDefaultNameFormat, + "Workspace %d"), id + 1); + } + + clientmenu->setLabel(name); + clientmenu->update(); +} + + +void Workspace::shutdown(void) { + while (windowList->count()) { + windowList->first()->restore(); + delete windowList->first(); + } +} + +void Workspace::placeWindow(OpenboxWindow *win) { + Bool placed = False; + + const int win_w = win->getWidth() + (screen->getBorderWidth() * 4), + win_h = win->getHeight() + (screen->getBorderWidth() * 4), +#ifdef SLIT + slit_x = screen->getSlit()->getX() - screen->getBorderWidth(), + slit_y = screen->getSlit()->getY() - screen->getBorderWidth(), + slit_w = screen->getSlit()->getWidth() + + (screen->getBorderWidth() * 4), + slit_h = screen->getSlit()->getHeight() + + (screen->getBorderWidth() * 4), +#endif // SLIT + toolbar_x = screen->getToolbar()->getX() - screen->getBorderWidth(), + toolbar_y = screen->getToolbar()->getY() - screen->getBorderWidth(), + toolbar_w = screen->getToolbar()->getWidth() + + (screen->getBorderWidth() * 4), + toolbar_h = screen->getToolbar()->getHeight() + + (screen->getBorderWidth() * 4), + start_pos = 0, + change_y = + ((screen->getColPlacementDirection() == BScreen::TopBottom) ? 1 : -1), + change_x = + ((screen->getRowPlacementDirection() == BScreen::LeftRight) ? 1 : -1), + delta_x = 8, delta_y = 8; + + int test_x, test_y, place_x = 0, place_y = 0; + LinkedListIterator it(windowList); + + switch (screen->getPlacementPolicy()) { + case BScreen::RowSmartPlacement: { + test_y = (screen->getColPlacementDirection() == BScreen::TopBottom) ? + start_pos : screen->getHeight() - win_h - start_pos; + + while (!placed && + ((screen->getColPlacementDirection() == BScreen::BottomTop) ? + test_y > 0 : test_y + win_h < (signed) screen->getHeight())) { + test_x = (screen->getRowPlacementDirection() == BScreen::LeftRight) ? + start_pos : screen->getWidth() - win_w - start_pos; + + while (!placed && + ((screen->getRowPlacementDirection() == BScreen::RightLeft) ? + test_x > 0 : test_x + win_w < (signed) screen->getWidth())) { + placed = True; + + it.reset(); + for (OpenboxWindow *curr = it.current(); placed && curr; + it++, curr = it.current()) { + if (curr->isMaximizedFull()) // fully maximized, ignore it + continue; + int curr_w = curr->getWidth() + (screen->getBorderWidth() * 4); + int curr_h = + ((curr->isShaded()) ? curr->getTitleHeight() : curr->getHeight()) + + (screen->getBorderWidth() * 4); + + if (curr->getXFrame() < test_x + win_w && + curr->getXFrame() + curr_w > test_x && + curr->getYFrame() < test_y + win_h && + curr->getYFrame() + curr_h > test_y) { + placed = False; + } + } + + if (placed && + (toolbar_x < test_x + win_w && + toolbar_x + toolbar_w > test_x && + toolbar_y < test_y + win_h && + toolbar_y + toolbar_h > test_y) +#ifdef SLIT + || + (slit_x < test_x + win_w && + slit_x + slit_w > test_x && + slit_y < test_y + win_h && + slit_y + slit_h > test_y) +#endif // SLIT + ) + placed = False; + + if (placed) { + place_x = test_x; + place_y = test_y; + + break; + } + + test_x += (change_x * delta_x); + } + + test_y += (change_y * delta_y); + } + + break; + } + + case BScreen::ColSmartPlacement: { + test_x = (screen->getRowPlacementDirection() == BScreen::LeftRight) ? + start_pos : screen->getWidth() - win_w - start_pos; + + while (!placed && + ((screen->getRowPlacementDirection() == BScreen::RightLeft) ? + test_x > 0 : test_x + win_w < (signed) screen->getWidth())) { + test_y = (screen->getColPlacementDirection() == BScreen::TopBottom) ? + start_pos : screen->getHeight() - win_h - start_pos; + + while (!placed && + ((screen->getColPlacementDirection() == BScreen::BottomTop) ? + test_y > 0 : test_y + win_h < (signed) screen->getHeight())) { + placed = True; + + it.reset(); + for (OpenboxWindow *curr = it.current(); placed && curr; + it++, curr = it.current()) { + if (curr->isMaximizedFull()) // fully maximized, ignore it + continue; + int curr_w = curr->getWidth() + (screen->getBorderWidth() * 4); + int curr_h = + ((curr->isShaded()) ? curr->getTitleHeight() : curr->getHeight()) + + (screen->getBorderWidth() * 4); + + if (curr->getXFrame() < test_x + win_w && + curr->getXFrame() + curr_w > test_x && + curr->getYFrame() < test_y + win_h && + curr->getYFrame() + curr_h > test_y) { + placed = False; + } + } + + if (placed && + (toolbar_x < test_x + win_w && + toolbar_x + toolbar_w > test_x && + toolbar_y < test_y + win_h && + toolbar_y + toolbar_h > test_y) +#ifdef SLIT + || + (slit_x < test_x + win_w && + slit_x + slit_w > test_x && + slit_y < test_y + win_h && + slit_y + slit_h > test_y) +#endif // SLIT + ) + placed = False; + + if (placed) { + place_x = test_x; + place_y = test_y; + + break; + } + + test_y += (change_y * delta_y); + } + + test_x += (change_x * delta_x); + } + + break; + } + } // switch + + if (! placed) { + if (((unsigned) cascade_x > (screen->getWidth() / 2)) || + ((unsigned) cascade_y > (screen->getHeight() / 2))) + cascade_x = cascade_y = 32; + + place_x = cascade_x; + place_y = cascade_y; + + cascade_x += win->getTitleHeight(); + cascade_y += win->getTitleHeight(); + } + + if (place_x + win_w > (signed) screen->getWidth()) + place_x = (((signed) screen->getWidth()) - win_w) / 2; + if (place_y + win_h > (signed) screen->getHeight()) + place_y = (((signed) screen->getHeight()) - win_h) / 2; + + win->configure(place_x, place_y, win->getWidth(), win->getHeight()); +} diff --git a/src/Workspace.h b/src/Workspace.h new file mode 100644 index 00000000..f9700bdc --- /dev/null +++ b/src/Workspace.h @@ -0,0 +1,90 @@ +// Workspace.h for Openbox +// 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 __Workspace_hh +#define __Workspace_hh + +#include + +#include "LinkedList.h" + +class BScreen; +class Clientmenu; +class Workspace; +class OpenboxWindow; + +class Workspace { +private: + BScreen *screen; + OpenboxWindow *lastfocus; + Clientmenu *clientmenu; + + LinkedList *stackingList, *windowList; + + char *name; + int id, cascade_x, cascade_y; + + +protected: + void placeWindow(OpenboxWindow *); + + +public: + Workspace(BScreen *, int = 0); + ~Workspace(void); + + inline BScreen *getScreen(void) { return screen; } + + inline OpenboxWindow *getLastFocusedWindow(void) { return lastfocus; } + + inline Clientmenu *getMenu(void) { return clientmenu; } + + inline const char *getName(void) const { return name; } + + inline const int &getWorkspaceID(void) const { return id; } + + inline void setLastFocusedWindow(OpenboxWindow *w) { lastfocus = w; } + + OpenboxWindow *getWindow(int); + + Bool isCurrent(void); + Bool isLastWindow(OpenboxWindow *); + + const int addWindow(OpenboxWindow *, Bool = False); + const int removeWindow(OpenboxWindow *); + const int getCount(void); + + void showAll(void); + void hideAll(void); + void removeAll(void); + void raiseWindow(OpenboxWindow *); + void lowerWindow(OpenboxWindow *); + void reconfigure(); + void update(); + void setCurrent(void); + void setName(char *); + void shutdown(void); +}; + + +#endif // __Workspace_hh + diff --git a/src/Workspacemenu.cc b/src/Workspacemenu.cc new file mode 100644 index 00000000..bec5f455 --- /dev/null +++ b/src/Workspacemenu.cc @@ -0,0 +1,69 @@ +// Workspacemenu.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "openbox.h" +#include "Screen.h" +#include "Toolbar.h" +#include "Workspacemenu.h" +#include "Workspace.h" + + +Workspacemenu::Workspacemenu(BScreen *scrn) : Basemenu(scrn) { + screen = scrn; + + setInternalMenu(); + + setLabel(i18n->getMessage(WorkspacemenuSet, WorkspacemenuWorkspacesTitle, + "Workspaces")); + insert(i18n->getMessage(WorkspacemenuSet, WorkspacemenuNewWorkspace, + "New Workspace")); + insert(i18n->getMessage(WorkspacemenuSet, WorkspacemenuRemoveLast, + "Remove Last")); +} + + +void Workspacemenu::itemSelected(int button, int index) { + if (button != 1) + return; + + if (index == 0) + screen->addWorkspace(); + else if (index == 1) + screen->removeLastWorkspace(); + else if ((screen->getCurrentWorkspace()->getWorkspaceID() != + (index - 2)) && ((index - 2) < screen->getCount())) + screen->changeWorkspaceID(index - 2); + + if (! (screen->getWorkspacemenu()->isTorn() || isTorn())) + hide(); +} diff --git a/src/Workspacemenu.h b/src/Workspacemenu.h new file mode 100644 index 00000000..6902315d --- /dev/null +++ b/src/Workspacemenu.h @@ -0,0 +1,45 @@ +// WorkspaceMenu.h for Openbox - 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 __Workspacemenu_hh +#define __Workspacemenu_hh + +#include "Basemenu.h" + +// forward declaration +class Workspacemenu; +class Toolbar; + +class Workspacemenu : public Basemenu { +private: + BScreen *screen; + +protected: + virtual void itemSelected(int, int); + +public: + Workspacemenu(BScreen *); +}; + + +#endif // __Workspacemenu_hh + diff --git a/src/bsd-snprintf.c b/src/bsd-snprintf.c new file mode 100644 index 00000000..4716ee29 --- /dev/null +++ b/src/bsd-snprintf.c @@ -0,0 +1,788 @@ +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + **************************************************************/ + +#include "config.h" + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) + +#include +# include +#include + +/* Define this as a fall through, HAVE_STDARG_H is probably already set */ + +#define HAVE_VARARGS_H + +/* varargs declarations: */ + +#if defined(HAVE_STDARG_H) +# include +# define HAVE_STDARGS /* let's hope that works everywhere (mj) */ +# define VA_LOCAL_DECL va_list ap +# define VA_START(f) va_start(ap, f) +# define VA_SHIFT(v,t) ; /* no-op for ANSI */ +# define VA_END va_end(ap) +#else +# if defined(HAVE_VARARGS_H) +# include +# undef HAVE_STDARGS +# define VA_LOCAL_DECL va_list ap +# define VA_START(f) va_start(ap) /* f is ignored! */ +# define VA_SHIFT(v,t) v = va_arg(ap,t) +# define VA_END va_end(ap) +# else +/*XX ** NO VARARGS ** XX*/ +# endif +#endif + +/*int snprintf (char *str, size_t count, const char *fmt, ...);*/ +/*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/ + +static void dopr (char *buffer, size_t maxlen, const char *format, + va_list args); +static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint (char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags); +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + long double fvalue, int min, int max, int flags); +static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 + +#define char_to_int(p) (p - '0') +#define MAX(p,q) ((p >= q) ? p : q) + +static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) +{ + char ch; + long value; + long double fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) + { + if ((ch == '\0') || (currlen >= maxlen)) + state = DP_S_DONE; + + switch(state) + { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch (buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) + { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) + { + min = 10*min + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } + else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') + { + state = DP_S_MAX; + ch = *format++; + } + else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) + { + if (max < 0) + max = 0; + max = 10*max + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } + else + state = DP_S_MOD; + break; + case DP_S_MOD: + /* Currently, we don't support Long Long, bummer */ + switch (ch) + { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) + { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg (args, short int); + else if (cflags == DP_C_LONG) + value = va_arg (args, long int); + else + value = va_arg (args, int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned short int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned short int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned short int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + break; + case 'c': + dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + if (max < 0) + max = maxlen; /* ie, no max */ + fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg (args, void *); + fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) + { + short int *num; + num = va_arg (args, short int *); + *num = currlen; + } + else if (cflags == DP_C_LONG) + { + long int *num; + num = va_arg (args, long int *); + *num = currlen; + } + else + { + int *num; + num = va_arg (args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch (buffer, &currlen, maxlen, ch); + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else + buffer[maxlen - 1] = '\0'; +} + +static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + + if (value == 0) + { + value = ""; + } + + for (strln = 0; value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint (char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) + { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; + } + + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ + + do { + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < 20)); + if (place == 20) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) + { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place)); +#endif + + /* Spaces */ + while (spadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) + { + while (zpadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static long double abs_val (long double value) +{ + long double result = value; + + if (value < 0) + result = -value; + + return result; +} + +static long double pow10 (int exp) +{ + long double result = 1; + + while (exp) + { + result *= 10; + exp--; + } + + return result; +} + +static long round (long double value) +{ + long intpart; + + intpart = value; + value = value - intpart; + if (value >= 0.5) + intpart++; + + return intpart; +} + +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + long double fvalue, int min, int max, int flags) +{ + int signvalue = 0; + long double ufvalue; + char iconvert[20]; + char fconvert[20]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + long intpart; + long fracpart; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) + signvalue = '-'; + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + + intpart = ufvalue; + + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + fracpart = round ((pow10 (max)) * (ufvalue - intpart)); + + if (fracpart >= pow10 (max)) + { + intpart++; + fracpart -= pow10 (max); + } + +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart)); +#endif + + /* Convert integer part */ + do { + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; + intpart = (intpart / 10); + } while(intpart && (iplace < 20)); + if (iplace == 20) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + do { + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; + fracpart = (fracpart / 10); + } while(fracpart && (fplace < 20)); + if (fplace == 20) fplace--; + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) + { + if (signvalue) + { + dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + dopr_outch (buffer, currlen, maxlen, '.'); + + while (fplace > 0) + dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + + while (zpadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (padlen < 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) + buffer[(*currlen)++] = c; +} +#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ + +#ifndef HAVE_VSNPRINTF +int vsnprintf (char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + dopr(str, count, fmt, args); + return(strlen(str)); +} +#endif /* !HAVE_VSNPRINTF */ + +#ifndef HAVE_SNPRINTF +/* VARARGS3 */ +#ifdef HAVE_STDARGS +int snprintf (char *str,size_t count,const char *fmt,...) +#else +int snprintf (va_alist) va_dcl +#endif +{ +#ifndef HAVE_STDARGS + char *str; + size_t count; + char *fmt; +#endif + VA_LOCAL_DECL; + + VA_START (fmt); + VA_SHIFT (str, char *); + VA_SHIFT (count, size_t ); + VA_SHIFT (fmt, char *); + (void) vsnprintf(str, count, fmt, ap); + VA_END; + return(strlen(str)); +} + +#ifdef TEST_SNPRINTF +#ifndef LONG_STRING +#define LONG_STRING 1024 +#endif +int main (void) +{ + char buf1[LONG_STRING]; + char buf2[LONG_STRING]; + char *fp_fmt[] = { + "%-1.5f", + "%1.5f", + "%123.9f", + "%10.5f", + "% 10.5f", + "%+22.9f", + "%+4.9f", + "%01.3f", + "%4f", + "%3.1f", + "%3.2f", + NULL + }; + double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 0}; + char *int_fmt[] = { + "%-1.5d", + "%1.5d", + "%123.9d", + "%5.5d", + "%10.5d", + "% 10.5d", + "%+22.33d", + "%01.3d", + "%4d", + NULL + }; + long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + int x, y; + int fail = 0; + int num = 0; + + printf ("Testing snprintf format codes against system sprintf...\n"); + + for (x = 0; fp_fmt[x] != NULL ; x++) + for (y = 0; fp_nums[y] != 0 ; y++) + { + snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]); + sprintf (buf2, fp_fmt[x], fp_nums[y]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", + fp_fmt[x], buf1, buf2); + fail++; + } + num++; + } + + for (x = 0; int_fmt[x] != NULL ; x++) + for (y = 0; int_nums[y] != 0 ; y++) + { + snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]); + sprintf (buf2, int_fmt[x], int_nums[y]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", + int_fmt[x], buf1, buf2); + fail++; + } + num++; + } + printf ("%d tests failed out of %d.\n", fail, num); +} +#endif /* SNPRINTF_TEST */ + +#endif /* !HAVE_SNPRINTF */ diff --git a/src/bsd-snprintf.h b/src/bsd-snprintf.h new file mode 100644 index 00000000..ed7a21c9 --- /dev/null +++ b/src/bsd-snprintf.h @@ -0,0 +1,17 @@ +#ifndef _BSD_SNPRINTF_H +#define _BSD_SNPRINTF_H + +#include "config.h" + +#include /* For size_t */ + +#ifndef HAVE_SNPRINTF +int snprintf(char *str, size_t count, const char *fmt, ...); +#endif /* !HAVE_SNPRINTF */ + +#ifndef HAVE_VSNPRINTF +int vsnprintf(char *str, size_t count, const char *fmt, va_list args); +#endif /* !HAVE_SNPRINTF */ + + +#endif /* _BSD_SNPRINTF_H */ diff --git a/src/i18n.cc b/src/i18n.cc new file mode 100644 index 00000000..18b77209 --- /dev/null +++ b/src/i18n.cc @@ -0,0 +1,134 @@ +// i18n.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" + +#include + +#ifdef STDC_HEADERS +# include +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_LOCALE_H +# include +#endif // HAVE_LOCALE_H + +// the rest of bb source uses True and False from X, so we continue that +#define True true +#define False false + +static I18n static_i18n; +I18n *i18n; + +void NLSInit(const char *catalog) { + i18n = &static_i18n; + + i18n->openCatalog(catalog); +} + + +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 + + catalog_filename = (char *) 0; +} + + +I18n::~I18n(void) { + delete [] catalog_filename; + +#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) + int lp = strlen(LOCALEPATH), lc = strlen(locale), + ct = strlen(catalog), len = lp + lc + ct + 3; + catalog_filename = new char[len]; + + strncpy(catalog_filename, LOCALEPATH, lp); + *(catalog_filename + lp) = '/'; + strncpy(catalog_filename + lp + 1, locale, lc); + *(catalog_filename + lp + lc + 1) = '/'; + strncpy(catalog_filename + lp + lc + 2, catalog, ct + 1); + +# ifdef MCLoadBySet + catalog_fd = catopen(catalog_filename, MCLoadBySet); +# else // !MCLoadBySet + catalog_fd = catopen(catalog_filename, NL_CAT_LOCALE); +# endif // MCLoadBySet + + if (catalog_fd == (nl_catd) -1) + fprintf(stderr, "failed to open catalog, using default messages\n"); +#else // !HAVE_CATOPEN + + catalog_filename = (char *) 0; +#endif // HAVE_CATOPEN +} + + +const char *I18n::getMessage(int set, int msg, const char *msgString) const { +#if defined(NLS) && defined(HAVE_CATGETS) + if (catalog_fd != (nl_catd) -1) + return (const char *) catgets(catalog_fd, set, msg, msgString); + else +#endif + return msgString; +} diff --git a/src/i18n.h b/src/i18n.h new file mode 100644 index 00000000..b074b2ff --- /dev/null +++ b/src/i18n.h @@ -0,0 +1,66 @@ +// i18n.h for Openbox +// 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 __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/openbox-nls.h" + +#ifdef HAVE_LOCALE_H +# include +#endif // HAVE_LOCALE_H + +#ifdef HAVE_NL_TYPES_H +extern "C" { +# include +} +#endif // HAVE_NL_TYPES_H + + +class I18n { +private: + char *locale, *catalog_filename; + 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 *getMessage(int set, int msg, const char *msgString) const; + void openCatalog(const char *catalog); +}; + + +extern I18n *i18n; +extern void NLSInit(const char *); + + + +#endif // __i18n_h diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 00000000..0a0ad5ba --- /dev/null +++ b/src/main.cc @@ -0,0 +1,186 @@ +// main.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include "../version.h" + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include "i18n.h" +#include "openbox.h" + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_UNISTD_H +#include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_SYS_PARAM_H +# include +#endif // HAVE_SYS_PARAM_H + +#ifndef MAXPATHLEN +#define MAXPATHLEN 255 +#endif // MAXPATHLEN + + +static void showHelp(int exitval) { + // print program usage and command line options + printf(i18n->getMessage(mainSet, mainUsage, + "Openbox %s : (c) 2002 - 2002 Ben Jansens\n" + "\t\t\t 2001 - 2002 Sean 'Shaleh' Perry\n\n" + "\t\t\t 1997 - 2000 Brad Hughes\n\n" + " -display \t\tuse display connection.\n" + " -rc \t\t\tuse alternate resource file.\n" + " -version\t\t\tdisplay version and exit.\n" + " -help\t\t\t\tdisplay this help text and exit.\n\n"), + __openbox_version); + + // some people have requested that we print out compile options + // as well + fprintf(stdout,i18n->getMessage(mainSet, mainCompileOptions, + "Compile time options:\n" + " Debugging:\t\t\t%s\n" + " Interlacing:\t\t\t%s\n" + " Shape:\t\t\t%s\n" + " Slit:\t\t\t\t%s\n" + " 8bpp Ordered Dithering:\t%s\n" + " Event Clobbering:\t\t%s\n\n"), +#ifdef DEBUG + i18n->getMessage(CommonSet, CommonYes, "yes"), +#else // !DEBUG + i18n->getMessage(CommonSet, CommonNo, "no"), +#endif // DEBUG + +#ifdef INTERLACE + i18n->getMessage(CommonSet, CommonYes, "yes"), +#else // !INTERLACE + i18n->getMessage(CommonSet, CommonNo, "no"), +#endif // INTERLACE + +#ifdef SHAPE + i18n->getMessage(CommonSet, CommonYes, "yes"), +#else // !SHAPE + i18n->getMessage(CommonSet, CommonNo, "no"), +#endif // SHAPE + +#ifdef SLIT + i18n->getMessage(CommonSet, CommonYes, "yes"), +#else // !SLIT + i18n->getMessage(CommonSet, CommonNo, "no"), +#endif // SLIT + +#ifdef ORDEREDPSEUDO + i18n->getMessage(CommonSet, CommonYes, "yes"), +#else // !ORDEREDPSEUDO + i18n->getMessage(CommonSet, CommonNo, "no"), +#endif // ORDEREDPSEUDO + +#ifndef NOCLOBBER + i18n->getMessage(CommonSet, CommonYes, "yes") +#else // !NOCLOBBER + i18n->getMessage(CommonSet, CommonNo, "no") +#endif // NOCLOBBER + ); + + ::exit(exitval); +} + +int main(int argc, char **argv) { + char *session_display = (char *) 0; + char *rc_file = (char *) 0; + + NLSInit("openbox.cat"); + + for (int i = 1; i < argc; ++i) { + if (! strcmp(argv[i], "-rc")) { + // look for alternative rc file to use + + if ((++i) >= argc) { + fprintf(stderr, + i18n->getMessage(mainSet, mainRCRequiresArg, + "error: '-rc' requires and argument\n")); + + ::exit(1); + } + + rc_file = argv[i]; + } else if (! strcmp(argv[i], "-display")) { + // check for -display option... to run on a display other than the one + // set by the environment variable DISPLAY + + if ((++i) >= argc) { + fprintf(stderr, + i18n->getMessage(mainSet, mainDISPLAYRequiresArg, + "error: '-display' requires an argument\n")); + + ::exit(1); + } + + session_display = argv[i]; + char dtmp[MAXPATHLEN]; + sprintf(dtmp, "DISPLAY=%s", session_display); + + if (putenv(dtmp)) { + fprintf(stderr, + i18n-> + getMessage(mainSet, mainWarnDisplaySet, + "warning: couldn't set environment variable 'DISPLAY'\n")); + perror("putenv()"); + } + } else if (! strcmp(argv[i], "-version")) { + // print current version string + printf("Openbox %s : (c) 1997 - 2000 Brad Hughes\n" + "\t\t\t 2001 - 2002 Sean 'Shaleh' Perry\n", + __openbox_version); + + ::exit(0); + } else if (! strcmp(argv[i], "-help")) { + showHelp(0); + } else { // invalid command line option + showHelp(-1); + } + } + +#ifdef __EMX__ + _chdir2(getenv("X11ROOT")); +#endif // __EMX__ + + Openbox openbox(argc, argv, session_display, rc_file); + openbox.eventLoop(); + + return(0); +} diff --git a/src/openbox.cc b/src/openbox.cc new file mode 100644 index 00000000..ad3ecc01 --- /dev/null +++ b/src/openbox.cc @@ -0,0 +1,1797 @@ +// openbox.cc for Openbox +// 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. + +// stupid macros needed to access some functions in version 2 of the GNU C +// library +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "../config.h" +#endif // HAVE_CONFIG_H + +#include +#include +#include +#include +#include + +#ifdef SHAPE +#include +#endif // SHAPE + +#include "i18n.h" +#include "openbox.h" +#include "Basemenu.h" +#include "Clientmenu.h" +#include "Rootmenu.h" +#include "Screen.h" + +#ifdef SLIT +#include "Slit.h" +#endif // SLIT + +#include "Toolbar.h" +#include "Window.h" +#include "Workspace.h" +#include "Workspacemenu.h" + +#ifdef HAVE_STDIO_H +# include +#endif // HAVE_STDIO_H + +#ifdef STDC_HEADERS +# include +# include +#endif // STDC_HEADERS + +#ifdef HAVE_UNISTD_H +# include +# include +#endif // HAVE_UNISTD_H + +#ifdef HAVE_SYS_PARAM_H +# include +#endif // HAVE_SYS_PARAM_H + +#ifndef MAXPATHLEN +#define MAXPATHLEN 255 +#endif // MAXPATHLEN + +#ifdef HAVE_SYS_SELECT_H +# include +#endif // HAVE_SYS_SELECT_H + +#ifdef HAVE_SIGNAL_H +# include +#endif // HAVE_SIGNAL_H + +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif // HAVE_SYS_SIGNAL_H + +#ifdef HAVE_SYS_STAT_H +# include +# include +#endif // HAVE_SYS_STAT_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 + +#ifdef HAVE_LIBGEN_H +# include +#endif // HAVE_LIBGEN_H + +#ifndef HAVE_BASENAME +static inline char *basename (char *s) { + char *save = s; + + while (*s) if (*s++ == '/') save = s; + + return save; +} +#endif // HAVE_BASENAME + + +// X event scanner for enter/leave notifies - adapted from twm +typedef struct scanargs { + Window w; + Bool leave, inferior, enter; +} scanargs; + +static Bool queueScanner(Display *, XEvent *e, char *args) { + if ((e->type == LeaveNotify) && + (e->xcrossing.window == ((scanargs *) args)->w) && + (e->xcrossing.mode == NotifyNormal)) { + ((scanargs *) args)->leave = True; + ((scanargs *) args)->inferior = (e->xcrossing.detail == NotifyInferior); + } else if ((e->type == EnterNotify) && + (e->xcrossing.mode == NotifyUngrab)) { + ((scanargs *) args)->enter = True; + } + + return False; +} + +Openbox *openbox; + + +Openbox::Openbox(int m_argc, char **m_argv, char *dpy_name, char *rc) + : BaseDisplay(m_argv[0], dpy_name) { + grab(); + + if (! XSupportsLocale()) + fprintf(stderr, "X server does not support locale\n"); + + if (XSetLocaleModifiers("") == NULL) + fprintf(stderr, "cannot set locale modifiers\n"); + + ::openbox = this; + argc = m_argc; + argv = m_argv; + if (rc == NULL) { + char *homedir = getenv("HOME"); + + rc_file = new char[strlen(homedir) + strlen("/.openbox/rc") + 1]; + sprintf(rc_file, "%s/.openbox", homedir); + + // try to make sure the ~/.openbox directory exists + mkdir(rc_file, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IWOTH | S_IXOTH); + + sprintf(rc_file, "%s/.openbox/rc", homedir); + } else { + rc_file = bstrdup(rc); + } + + no_focus = False; + + resource.menu_file = resource.style_file = (char *) 0; + resource.titlebar_layout = (char *) NULL; + resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0; + + focused_window = masked_window = (OpenboxWindow *) 0; + masked = None; + + windowSearchList = new LinkedList; + menuSearchList = new LinkedList; + +#ifdef SLIT + slitSearchList = new LinkedList; +#endif // SLIT + + toolbarSearchList = new LinkedList; + groupSearchList = new LinkedList; + + menuTimestamps = new LinkedList; + + XrmInitialize(); + load_rc(); + +#ifdef HAVE_GETPID + openbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False); +#endif // HAVE_GETPID + + screenList = new LinkedList; + for (int i = 0; i < getNumberOfScreens(); i++) { + BScreen *screen = new BScreen(this, i); + + if (! screen->isScreenManaged()) { + delete screen; + continue; + } + + screenList->insert(screen); + } + + if (! screenList->count()) { + fprintf(stderr, + i18n->getMessage(openboxSet, openboxNoManagableScreens, + "Openbox::Openbox: no managable screens found, aborting.\n")); + ::exit(3); + } + + XSynchronize(getXDisplay(), False); + XSync(getXDisplay(), False); + + reconfigure_wait = reread_menu_wait = False; + + timer = new BTimer(this, this); + timer->setTimeout(0); + timer->fireOnce(True); + + ungrab(); +} + + +Openbox::~Openbox(void) { + while (screenList->count()) + delete screenList->remove(0); + + while (menuTimestamps->count()) { + MenuTimestamp *ts = menuTimestamps->remove(0); + + if (ts->filename) + delete [] ts->filename; + + delete ts; + } + + if (resource.menu_file) + delete [] resource.menu_file; + + if (resource.style_file) + delete [] resource.style_file; + + delete timer; + + delete screenList; + delete menuTimestamps; + + delete windowSearchList; + delete menuSearchList; + delete toolbarSearchList; + delete groupSearchList; + + delete [] rc_file; + +#ifdef SLIT + delete slitSearchList; +#endif // SLIT +} + + +void Openbox::process_event(XEvent *e) { + if ((masked == e->xany.window) && masked_window && + (e->type == MotionNotify)) { + last_time = e->xmotion.time; + masked_window->motionNotifyEvent(&e->xmotion); + + return; + } + + switch (e->type) { + case ButtonPress: { + // strip the lock key modifiers + e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask); + + last_time = e->xbutton.time; + + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + Toolbar *tbar = (Toolbar *) 0; + + if ((win = searchWindow(e->xbutton.window))) { + win->buttonPressEvent(&e->xbutton); + + if (e->xbutton.button == 1) + win->installColormap(True); + } else if ((menu = searchMenu(e->xbutton.window))) { + menu->buttonPressEvent(&e->xbutton); + +#ifdef SLIT + } else if ((slit = searchSlit(e->xbutton.window))) { + slit->buttonPressEvent(&e->xbutton); +#endif // SLIT + + } else if ((tbar = searchToolbar(e->xbutton.window))) { + tbar->buttonPressEvent(&e->xbutton); + } else { + LinkedListIterator it(screenList); + BScreen *screen = it.current(); + for (; screen; it++, screen = it.current()) { + if (e->xbutton.window == screen->getRootWindow()) { + if (e->xbutton.button == 1) { + if (! screen->isRootColormapInstalled()) + screen->getImageControl()->installRootColormap(); + + if (screen->getWorkspacemenu()->isVisible()) + screen->getWorkspacemenu()->hide(); + + if (screen->getRootmenu()->isVisible()) + screen->getRootmenu()->hide(); + } else if (e->xbutton.button == 2) { + int mx = e->xbutton.x_root - + (screen->getWorkspacemenu()->getWidth() / 2); + int my = e->xbutton.y_root - + (screen->getWorkspacemenu()->getTitleHeight() / 2); + + if (mx < 0) mx = 0; + if (my < 0) my = 0; + + if (mx + screen->getWorkspacemenu()->getWidth() > + screen->getWidth()) + mx = screen->getWidth() - + screen->getWorkspacemenu()->getWidth() - + screen->getBorderWidth(); + + if (my + screen->getWorkspacemenu()->getHeight() > + screen->getHeight()) + my = screen->getHeight() - + screen->getWorkspacemenu()->getHeight() - + screen->getBorderWidth(); + + screen->getWorkspacemenu()->move(mx, my); + + if (! screen->getWorkspacemenu()->isVisible()) { + screen->getWorkspacemenu()->removeParent(); + screen->getWorkspacemenu()->show(); + } + } else if (e->xbutton.button == 3) { + int mx = e->xbutton.x_root - + (screen->getRootmenu()->getWidth() / 2); + int my = e->xbutton.y_root - + (screen->getRootmenu()->getTitleHeight() / 2); + + if (mx < 0) mx = 0; + if (my < 0) my = 0; + + if (mx + screen->getRootmenu()->getWidth() > screen->getWidth()) + mx = screen->getWidth() - + screen->getRootmenu()->getWidth() - + screen->getBorderWidth(); + + if (my + screen->getRootmenu()->getHeight() > screen->getHeight()) + my = screen->getHeight() - + screen->getRootmenu()->getHeight() - + screen->getBorderWidth(); + + screen->getRootmenu()->move(mx, my); + + if (! screen->getRootmenu()->isVisible()) { + checkMenu(); + screen->getRootmenu()->show(); + } + } else if (e->xbutton.button == 4) { + if ((screen->getCurrentWorkspaceID()-1)<0) + screen->changeWorkspaceID(screen->getCount()-1); + else + screen->changeWorkspaceID(screen->getCurrentWorkspaceID()-1); + } else if (e->xbutton.button == 5) { + if ((screen->getCurrentWorkspaceID()+1)>screen->getCount()-1) + screen->changeWorkspaceID(0); + else + screen->changeWorkspaceID(screen->getCurrentWorkspaceID()+1); + } + } + } + } + + break; + } + + case ButtonRelease: { + // strip the lock key modifiers + e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask); + + last_time = e->xbutton.time; + + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + Toolbar *tbar = (Toolbar *) 0; + + if ((win = searchWindow(e->xbutton.window))) + win->buttonReleaseEvent(&e->xbutton); + else if ((menu = searchMenu(e->xbutton.window))) + menu->buttonReleaseEvent(&e->xbutton); + else if ((tbar = searchToolbar(e->xbutton.window))) + tbar->buttonReleaseEvent(&e->xbutton); + + break; + } + + case ConfigureRequest: { + OpenboxWindow *win = (OpenboxWindow *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + if ((win = searchWindow(e->xconfigurerequest.window))) { + win->configureRequestEvent(&e->xconfigurerequest); + +#ifdef SLIT + } else if ((slit = searchSlit(e->xconfigurerequest.window))) { + slit->configureRequestEvent(&e->xconfigurerequest); +#endif // SLIT + + } else { + grab(); + + if (validateWindow(e->xconfigurerequest.window)) { + XWindowChanges xwc; + + xwc.x = e->xconfigurerequest.x; + xwc.y = e->xconfigurerequest.y; + xwc.width = e->xconfigurerequest.width; + xwc.height = e->xconfigurerequest.height; + xwc.border_width = e->xconfigurerequest.border_width; + xwc.sibling = e->xconfigurerequest.above; + xwc.stack_mode = e->xconfigurerequest.detail; + + XConfigureWindow(getXDisplay(), e->xconfigurerequest.window, + e->xconfigurerequest.value_mask, &xwc); + } + + ungrab(); + } + + break; + } + + case MapRequest: { +#ifdef DEBUG + fprintf(stderr, + i18n->getMessage(openboxSet, openboxMapRequest, + "Openbox::process_event(): MapRequest for 0x%lx\n"), + e->xmaprequest.window); +#endif // DEBUG + + OpenboxWindow *win = searchWindow(e->xmaprequest.window); + + if (! win) + win = new OpenboxWindow(this, e->xmaprequest.window); + + if ((win = searchWindow(e->xmaprequest.window))) + win->mapRequestEvent(&e->xmaprequest); + + break; + } + + case MapNotify: { + OpenboxWindow *win = searchWindow(e->xmap.window); + + if (win) + win->mapNotifyEvent(&e->xmap); + + break; + } + + case UnmapNotify: { + OpenboxWindow *win = (OpenboxWindow *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + if ((win = searchWindow(e->xunmap.window))) { + win->unmapNotifyEvent(&e->xunmap); + if (focused_window == win) + focused_window = (OpenboxWindow *) 0; +#ifdef SLIT + } else if ((slit = searchSlit(e->xunmap.window))) { + slit->removeClient(e->xunmap.window); +#endif // SLIT + + } + + break; + } + + case DestroyNotify: { + OpenboxWindow *win = (OpenboxWindow *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + if ((win = searchWindow(e->xdestroywindow.window))) { + win->destroyNotifyEvent(&e->xdestroywindow); + if (focused_window == win) + focused_window = (OpenboxWindow *) 0; +#ifdef SLIT + } else if ((slit = searchSlit(e->xdestroywindow.window))) { + slit->removeClient(e->xdestroywindow.window, False); +#endif // SLIT + } + + break; + } + + case MotionNotify: { + // strip the lock key modifiers + e->xbutton.state &= ~(NumLockMask | ScrollLockMask | LockMask); + + last_time = e->xmotion.time; + + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + + if ((win = searchWindow(e->xmotion.window))) + win->motionNotifyEvent(&e->xmotion); + else if ((menu = searchMenu(e->xmotion.window))) + menu->motionNotifyEvent(&e->xmotion); + + break; + } + + case PropertyNotify: { + last_time = e->xproperty.time; + + if (e->xproperty.state != PropertyDelete) { + OpenboxWindow *win = searchWindow(e->xproperty.window); + + if (win) + win->propertyNotifyEvent(e->xproperty.atom); + } + + break; + } + + case EnterNotify: { + last_time = e->xcrossing.time; + + BScreen *screen = (BScreen *) 0; + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + Toolbar *tbar = (Toolbar *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + if (e->xcrossing.mode == NotifyGrab) break; + + XEvent dummy; + scanargs sa; + sa.w = e->xcrossing.window; + sa.enter = sa.leave = False; + XCheckIfEvent(getXDisplay(), &dummy, queueScanner, (char *) &sa); + + if ((e->xcrossing.window == e->xcrossing.root) && + (screen = searchScreen(e->xcrossing.window))) { + screen->getImageControl()->installRootColormap(); + } else if ((win = searchWindow(e->xcrossing.window))) { + if (win->getScreen()->isSloppyFocus() && + (! win->isFocused()) && (! no_focus)) { + grab(); + + if (((! sa.leave) || sa.inferior) && win->isVisible() && + win->setInputFocus()) + win->installColormap(True); + + ungrab(); + } + } else if ((menu = searchMenu(e->xcrossing.window))) { + menu->enterNotifyEvent(&e->xcrossing); + } else if ((tbar = searchToolbar(e->xcrossing.window))) { + tbar->enterNotifyEvent(&e->xcrossing); +#ifdef SLIT + } else if ((slit = searchSlit(e->xcrossing.window))) { + slit->enterNotifyEvent(&e->xcrossing); +#endif // SLIT + } + break; + } + + case LeaveNotify: { + last_time = e->xcrossing.time; + + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + Toolbar *tbar = (Toolbar *) 0; + +#ifdef SLIT + Slit *slit = (Slit *) 0; +#endif // SLIT + + if ((menu = searchMenu(e->xcrossing.window))) + menu->leaveNotifyEvent(&e->xcrossing); + else if ((win = searchWindow(e->xcrossing.window))) + win->installColormap(False); + else if ((tbar = searchToolbar(e->xcrossing.window))) + tbar->leaveNotifyEvent(&e->xcrossing); +#ifdef SLIT + else if ((slit = searchSlit(e->xcrossing.window))) + slit->leaveNotifyEvent(&e->xcrossing); +#endif // SLIT + + break; + } + + case Expose: { + OpenboxWindow *win = (OpenboxWindow *) 0; + Basemenu *menu = (Basemenu *) 0; + Toolbar *tbar = (Toolbar *) 0; + + if ((win = searchWindow(e->xexpose.window))) + win->exposeEvent(&e->xexpose); + else if ((menu = searchMenu(e->xexpose.window))) + menu->exposeEvent(&e->xexpose); + else if ((tbar = searchToolbar(e->xexpose.window))) + tbar->exposeEvent(&e->xexpose); + + break; + } + + case KeyPress: { + Toolbar *tbar = searchToolbar(e->xkey.window); + + if (tbar && tbar->isEditing()) + tbar->keyPressEvent(&e->xkey); + + break; + } + + case ColormapNotify: { + BScreen *screen = searchScreen(e->xcolormap.window); + + if (screen) + screen->setRootColormapInstalled((e->xcolormap.state == + ColormapInstalled) ? True : False); + + break; + } + + case FocusIn: { + if (e->xfocus.mode == NotifyUngrab || e->xfocus.detail == NotifyPointer) + break; + + OpenboxWindow *win = searchWindow(e->xfocus.window); + if (win && ! win->isFocused()) + setFocusedWindow(win); + + break; + } + + case FocusOut: + break; + + case ClientMessage: { + if (e->xclient.format == 32) { + if (e->xclient.message_type == getWMChangeStateAtom()) { + OpenboxWindow *win = searchWindow(e->xclient.window); + if (! win || ! win->validateClient()) return; + + if (e->xclient.data.l[0] == IconicState) + win->iconify(); + if (e->xclient.data.l[0] == NormalState) + win->deiconify(); + } else if (e->xclient.message_type == getOpenboxChangeWorkspaceAtom()) { + BScreen *screen = searchScreen(e->xclient.window); + + if (screen && e->xclient.data.l[0] >= 0 && + e->xclient.data.l[0] < screen->getCount()) + screen->changeWorkspaceID(e->xclient.data.l[0]); + } else if (e->xclient.message_type == getOpenboxChangeWindowFocusAtom()) { + OpenboxWindow *win = searchWindow(e->xclient.window); + + if (win && win->isVisible() && win->setInputFocus()) + win->installColormap(True); + } else if (e->xclient.message_type == getOpenboxCycleWindowFocusAtom()) { + BScreen *screen = searchScreen(e->xclient.window); + + if (screen) { + if (! e->xclient.data.l[0]) + screen->prevFocus(); + else + screen->nextFocus(); + } + } else if (e->xclient.message_type == getOpenboxChangeAttributesAtom()) { + OpenboxWindow *win = searchWindow(e->xclient.window); + + if (win && win->validateClient()) { + OpenboxHints net; + net.flags = e->xclient.data.l[0]; + net.attrib = e->xclient.data.l[1]; + net.workspace = e->xclient.data.l[2]; + net.stack = e->xclient.data.l[3]; + net.decoration = e->xclient.data.l[4]; + + win->changeOpenboxHints(&net); + } + } + } + + break; + } + + + default: { +#ifdef SHAPE + if (e->type == getShapeEventBase()) { + XShapeEvent *shape_event = (XShapeEvent *) e; + OpenboxWindow *win = (OpenboxWindow *) 0; + + if ((win = searchWindow(e->xany.window)) || + (shape_event->kind != ShapeBounding)) + win->shapeEvent(shape_event); + } +#endif // SHAPE + + } + } // switch +} + + +Bool Openbox::handleSignal(int sig) { + switch (sig) { + case SIGHUP: + reconfigure(); + break; + + case SIGUSR1: + reload_rc(); + break; + + case SIGUSR2: + rereadMenu(); + break; + + case SIGPIPE: + case SIGSEGV: + case SIGFPE: + case SIGINT: + case SIGTERM: + shutdown(); + + default: + return False; + } + + return True; +} + + +BScreen *Openbox::searchScreen(Window window) { + LinkedListIterator it(screenList); + + for (BScreen *curr = it.current(); curr; it++, curr = it.current()) { + if (curr->getRootWindow() == window) { + return curr; + } + } + + return (BScreen *) 0; +} + + +OpenboxWindow *Openbox::searchWindow(Window window) { + LinkedListIterator it(windowSearchList); + + for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + return tmp->getData(); + } + } + + return (OpenboxWindow *) 0; +} + + +OpenboxWindow *Openbox::searchGroup(Window window, OpenboxWindow *win) { + OpenboxWindow *w = (OpenboxWindow *) 0; + LinkedListIterator it(groupSearchList); + + for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + w = tmp->getData(); + if (w->getClientWindow() != win->getClientWindow()) + return win; + } + } + + return (OpenboxWindow *) 0; +} + + +Basemenu *Openbox::searchMenu(Window window) { + LinkedListIterator it(menuSearchList); + + for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) + return tmp->getData(); + } + + return (Basemenu *) 0; +} + + +Toolbar *Openbox::searchToolbar(Window window) { + LinkedListIterator it(toolbarSearchList); + + for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) + return tmp->getData(); + } + + return (Toolbar *) 0; +} + + +#ifdef SLIT +Slit *Openbox::searchSlit(Window window) { + LinkedListIterator it(slitSearchList); + + for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) + return tmp->getData(); + } + + return (Slit *) 0; +} +#endif // SLIT + + +void Openbox::saveWindowSearch(Window window, OpenboxWindow *data) { + windowSearchList->insert(new WindowSearch(window, data)); +} + + +void Openbox::saveGroupSearch(Window window, OpenboxWindow *data) { + groupSearchList->insert(new WindowSearch(window, data)); +} + + +void Openbox::saveMenuSearch(Window window, Basemenu *data) { + menuSearchList->insert(new MenuSearch(window, data)); +} + + +void Openbox::saveToolbarSearch(Window window, Toolbar *data) { + toolbarSearchList->insert(new ToolbarSearch(window, data)); +} + + +#ifdef SLIT +void Openbox::saveSlitSearch(Window window, Slit *data) { + slitSearchList->insert(new SlitSearch(window, data)); +} +#endif // SLIT + + +void Openbox::removeWindowSearch(Window window) { + LinkedListIterator it(windowSearchList); + for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + windowSearchList->remove(tmp); + delete tmp; + break; + } + } +} + + +void Openbox::removeGroupSearch(Window window) { + LinkedListIterator it(groupSearchList); + for (WindowSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + groupSearchList->remove(tmp); + delete tmp; + break; + } + } +} + + +void Openbox::removeMenuSearch(Window window) { + LinkedListIterator it(menuSearchList); + for (MenuSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + menuSearchList->remove(tmp); + delete tmp; + break; + } + } +} + + +void Openbox::removeToolbarSearch(Window window) { + LinkedListIterator it(toolbarSearchList); + for (ToolbarSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + toolbarSearchList->remove(tmp); + delete tmp; + break; + } + } +} + + +#ifdef SLIT +void Openbox::removeSlitSearch(Window window) { + LinkedListIterator it(slitSearchList); + for (SlitSearch *tmp = it.current(); tmp; it++, tmp = it.current()) { + if (tmp->getWindow() == window) { + slitSearchList->remove(tmp); + delete tmp; + break; + } + } +} +#endif // SLIT + + +void Openbox::restart(const char *prog) { + shutdown(); + + if (prog) { + execlp(prog, prog, NULL); + perror(prog); + } + + // fall back in case the above execlp doesn't work + execvp(argv[0], argv); + execvp(basename(argv[0]), argv); +} + + +void Openbox::shutdown(void) { + BaseDisplay::shutdown(); + + XSetInputFocus(getXDisplay(), PointerRoot, None, CurrentTime); + + LinkedListIterator it(screenList); + for (BScreen *s = it.current(); s; it++, s = it.current()) + s->shutdown(); + + XSync(getXDisplay(), False); + + save_rc(); +} + + +void Openbox::save_rc(void) { + XrmDatabase new_openboxrc = (XrmDatabase) 0; + char rc_string[1024]; + + load_rc(); + + sprintf(rc_string, "session.menuFile: %s", resource.menu_file); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.colorsPerChannel: %d", + resource.colors_per_channel); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.titlebarLayout: %s", + resource.titlebar_layout); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.doubleClickInterval: %lu", + resource.double_click_interval); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.autoRaiseDelay: %lu", + ((resource.auto_raise_delay.tv_sec * 1000) + + (resource.auto_raise_delay.tv_usec / 1000))); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.cacheLife: %lu", resource.cache_life / 60000); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.cacheMax: %lu", resource.cache_max); + XrmPutLineResource(&new_openboxrc, rc_string); + + LinkedListIterator it(screenList); + for (BScreen *screen = it.current(); screen; it++, screen = it.current()) { + int screen_number = screen->getScreenNumber(); + +#ifdef SLIT + char *slit_placement = (char *) 0; + + switch (screen->getSlitPlacement()) { + case Slit::TopLeft: slit_placement = "TopLeft"; break; + case Slit::CenterLeft: slit_placement = "CenterLeft"; break; + case Slit::BottomLeft: slit_placement = "BottomLeft"; break; + case Slit::TopCenter: slit_placement = "TopCenter"; break; + case Slit::BottomCenter: slit_placement = "BottomCenter"; break; + case Slit::TopRight: slit_placement = "TopRight"; break; + case Slit::BottomRight: slit_placement = "BottomRight"; break; + case Slit::CenterRight: default: slit_placement = "CenterRight"; break; + } + + sprintf(rc_string, "session.screen%d.slit.placement: %s", screen_number, + slit_placement); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.slit.direction: %s", screen_number, + ((screen->getSlitDirection() == Slit::Horizontal) ? "Horizontal" : + "Vertical")); + XrmPutLineResource(&new_openboxrc, rc_string); + + const char *rootcmd; + if ((rootcmd = screen->getRootCommand()) != NULL) { + sprintf(rc_string, "session.screen%d.rootCommand: %s", screen_number, + rootcmd); + XrmPutLineResource(&new_openboxrc, rc_string); + } + + sprintf(rc_string, "session.screen%d.slit.onTop: %s", screen_number, + ((screen->getSlit()->isOnTop()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.slit.autoHide: %s", screen_number, + ((screen->getSlit()->doAutoHide()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); +#endif // SLIT + + sprintf(rc_string, "session.opaqueMove: %s", + ((screen->doOpaqueMove()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.imageDither: %s", + ((screen->getImageControl()->doDither()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.fullMaximization: %s", screen_number, + ((screen->doFullMax()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.focusNewWindows: %s", screen_number, + ((screen->doFocusNew()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.focusLastWindow: %s", screen_number, + ((screen->doFocusLast()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.rowPlacementDirection: %s", + screen_number, + ((screen->getRowPlacementDirection() == BScreen::LeftRight) ? + "LeftToRight" : "RightToLeft")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.colPlacementDirection: %s", + screen_number, + ((screen->getColPlacementDirection() == BScreen::TopBottom) ? + "TopToBottom" : "BottomToTop")); + XrmPutLineResource(&new_openboxrc, rc_string); + + char *placement = (char *) 0; + switch (screen->getPlacementPolicy()) { + case BScreen::CascadePlacement: + placement = "CascadePlacement"; + break; + + case BScreen::ColSmartPlacement: + placement = "ColSmartPlacement"; + break; + + case BScreen::RowSmartPlacement: + default: + placement = "RowSmartPlacement"; + break; + } + sprintf(rc_string, "session.screen%d.windowPlacement: %s", screen_number, + placement); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.windowZones: %i", screen_number, + screen->getWindowZones()); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.focusModel: %s", screen_number, + ((screen->isSloppyFocus()) ? + ((screen->doAutoRaise()) ? "AutoRaiseSloppyFocus" : + "SloppyFocus") : + "ClickToFocus")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.workspaces: %d", screen_number, + screen->getCount()); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.toolbar.onTop: %s", screen_number, + ((screen->getToolbar()->isOnTop()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.toolbar.autoHide: %s", screen_number, + ((screen->getToolbar()->doAutoHide()) ? "True" : "False")); + XrmPutLineResource(&new_openboxrc, rc_string); + + char *toolbar_placement = (char *) 0; + + switch (screen->getToolbarPlacement()) { + case Toolbar::TopLeft: toolbar_placement = "TopLeft"; break; + case Toolbar::BottomLeft: toolbar_placement = "BottomLeft"; break; + case Toolbar::TopCenter: toolbar_placement = "TopCenter"; break; + case Toolbar::TopRight: toolbar_placement = "TopRight"; break; + case Toolbar::BottomRight: toolbar_placement = "BottomRight"; break; + case Toolbar::BottomCenter: default: + toolbar_placement = "BottomCenter"; break; + } + + sprintf(rc_string, "session.screen%d.toolbar.placement: %s", screen_number, + toolbar_placement); + XrmPutLineResource(&new_openboxrc, rc_string); + + load_rc(screen); + + // these are static, but may not be saved in the users .openbox/rc, + // writing these resources will allow the user to edit them at a later + // time... but loading the defaults before saving allows us to rewrite the + // users changes... + +#ifdef HAVE_STRFTIME + sprintf(rc_string, "session.screen%d.strftimeFormat: %s", screen_number, + screen->getStrftimeFormat()); + XrmPutLineResource(&new_openboxrc, rc_string); +#else // !HAVE_STRFTIME + sprintf(rc_string, "session.screen%d.dateFormat: %s", screen_number, + ((screen->getDateFormat() == B_EuropeanDate) ? + "European" : "American")); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.clockFormat: %d", screen_number, + ((screen->isClock24Hour()) ? 24 : 12)); + XrmPutLineResource(&new_openboxrc, rc_string); +#endif // HAVE_STRFTIME + + sprintf(rc_string, "session.screen%d.edgeSnapThreshold: %d", screen_number, + screen->getEdgeSnapThreshold()); + XrmPutLineResource(&new_openboxrc, rc_string); + + sprintf(rc_string, "session.screen%d.toolbar.widthPercent: %d", + screen_number, screen->getToolbarWidthPercent()); + XrmPutLineResource(&new_openboxrc, rc_string); + + // write out the users workspace names + int i, len = 0; + for (i = 0; i < screen->getCount(); i++) + len += strlen((screen->getWorkspace(i)->getName()) ? + screen->getWorkspace(i)->getName() : "Null") + 1; + + char *resource_string = new char[len + 1024], + *save_string = new char[len], *save_string_pos = save_string, + *name_string_pos; + if (save_string) { + for (i = 0; i < screen->getCount(); i++) { + len = strlen((screen->getWorkspace(i)->getName()) ? + screen->getWorkspace(i)->getName() : "Null") + 1; + name_string_pos = + (char *) ((screen->getWorkspace(i)->getName()) ? + screen->getWorkspace(i)->getName() : "Null"); + + while (--len) *(save_string_pos++) = *(name_string_pos++); + *(save_string_pos++) = ','; + } + } + + *(--save_string_pos) = '\0'; + + sprintf(resource_string, "session.screen%d.workspaceNames: %s", + screen_number, save_string); + XrmPutLineResource(&new_openboxrc, resource_string); + + delete [] resource_string; + delete [] save_string; + } + + XrmDatabase old_openboxrc = XrmGetFileDatabase(rc_file); + + XrmMergeDatabases(new_openboxrc, &old_openboxrc); + XrmPutFileDatabase(old_openboxrc, rc_file); + XrmDestroyDatabase(old_openboxrc); +} + + +void Openbox::load_rc(void) { + XrmDatabase database = (XrmDatabase) 0; + + database = XrmGetFileDatabase(rc_file); + + XrmValue value; + char *value_type; + + if (resource.menu_file) + delete [] resource.menu_file; + + if (XrmGetResource(database, "session.menuFile", "Session.MenuFile", + &value_type, &value)) + resource.menu_file = bstrdup(value.addr); + else + resource.menu_file = bstrdup(DEFAULTMENU); + + if (XrmGetResource(database, "session.colorsPerChannel", + "Session.ColorsPerChannel", &value_type, &value)) { + if (sscanf(value.addr, "%d", &resource.colors_per_channel) != 1) { + resource.colors_per_channel = 4; + } else { + if (resource.colors_per_channel < 2) resource.colors_per_channel = 2; + if (resource.colors_per_channel > 6) resource.colors_per_channel = 6; + } + } else { + resource.colors_per_channel = 4; + } + + if (resource.style_file) + delete [] resource.style_file; + + if (XrmGetResource(database, "session.styleFile", "Session.StyleFile", + &value_type, &value)) + resource.style_file = bstrdup(value.addr); + else + resource.style_file = bstrdup(DEFAULTSTYLE); + + if (XrmGetResource(database, "session.titlebarLayout", + "Session.TitlebarLayout", &value_type, &value)) { + resource.titlebar_layout = bstrdup(value.addr == NULL ? "ILMC" : + value.addr); + } else { + resource.titlebar_layout = bstrdup("ILMC"); + } + + if (XrmGetResource(database, "session.doubleClickInterval", + "Session.DoubleClickInterval", &value_type, &value)) { + if (sscanf(value.addr, "%lu", &resource.double_click_interval) != 1) + resource.double_click_interval = 250; + } else { + resource.double_click_interval = 250; + } + + if (XrmGetResource(database, "session.autoRaiseDelay", + "Session.AutoRaiseDelay", &value_type, &value)) { + if (sscanf(value.addr, "%ld", &resource.auto_raise_delay.tv_usec) != 1) + resource.auto_raise_delay.tv_usec = 400; + } else { + resource.auto_raise_delay.tv_usec = 400; + } + + resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec / 1000; + resource.auto_raise_delay.tv_usec -= + (resource.auto_raise_delay.tv_sec * 1000); + resource.auto_raise_delay.tv_usec *= 1000; + + if (XrmGetResource(database, "session.cacheLife", "Session.CacheLife", + &value_type, &value)) { + if (sscanf(value.addr, "%lu", &resource.cache_life) != 1) + resource.cache_life = 5l; + } else { + resource.cache_life = 5l; + } + + resource.cache_life *= 60000; + + if (XrmGetResource(database, "session.cacheMax", "Session.CacheMax", + &value_type, &value)) { + if (sscanf(value.addr, "%lu", &resource.cache_max) != 1) + resource.cache_max = 200; + } else { + resource.cache_max = 200; + } +} + + +void Openbox::load_rc(BScreen *screen) { + XrmDatabase database = (XrmDatabase) 0; + + database = XrmGetFileDatabase(rc_file); + + XrmValue value; + char *value_type, name_lookup[1024], class_lookup[1024]; + int screen_number = screen->getScreenNumber(); + + sprintf(name_lookup, "session.screen%d.fullMaximization", screen_number); + sprintf(class_lookup, "Session.Screen%d.FullMaximization", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "true", value.size)) + screen->saveFullMax(True); + else + screen->saveFullMax(False); + } else { + screen->saveFullMax(False); + } + sprintf(name_lookup, "session.screen%d.focusNewWindows", screen_number); + sprintf(class_lookup, "Session.Screen%d.FocusNewWindows", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "true", value.size)) + screen->saveFocusNew(True); + else + screen->saveFocusNew(False); + } else { + screen->saveFocusNew(False); + } + sprintf(name_lookup, "session.screen%d.focusLastWindow", screen_number); + sprintf(class_lookup, "Session.Screen%d.focusLastWindow", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "true", value.size)) + screen->saveFocusLast(True); + else + screen->saveFocusLast(False); + } else { + screen->saveFocusLast(False); + } + sprintf(name_lookup, "session.screen%d.rowPlacementDirection", + screen_number); + sprintf(class_lookup, "Session.Screen%d.RowPlacementDirection", + screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "righttoleft", value.size)) + screen->saveRowPlacementDirection(BScreen::RightLeft); + else + screen->saveRowPlacementDirection(BScreen::LeftRight); + } else { + screen->saveRowPlacementDirection(BScreen::LeftRight); + } + sprintf(name_lookup, "session.screen%d.colPlacementDirection", + screen_number); + sprintf(class_lookup, "Session.Screen%d.ColPlacementDirection", + screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "bottomtotop", value.size)) + screen->saveColPlacementDirection(BScreen::BottomTop); + else + screen->saveColPlacementDirection(BScreen::TopBottom); + } else { + screen->saveColPlacementDirection(BScreen::TopBottom); + } + sprintf(name_lookup, "session.screen%d.workspaces", screen_number); + sprintf(class_lookup, "Session.Screen%d.Workspaces", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + int i; + if (sscanf(value.addr, "%d", &i) != 1) i = 1; + screen->saveWorkspaces(i); + } else { + screen->saveWorkspaces(1); + } + sprintf(name_lookup, "session.screen%d.toolbar.widthPercent", + screen_number); + sprintf(class_lookup, "Session.Screen%d.Toolbar.WidthPercent", + screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + int i; + if (sscanf(value.addr, "%d", &i) != 1) i = 66; + + if (i <= 0 || i > 100) + i = 66; + + screen->saveToolbarWidthPercent(i); + } else { + screen->saveToolbarWidthPercent(66); + } + sprintf(name_lookup, "session.screen%d.toolbar.placement", screen_number); + sprintf(class_lookup, "Session.Screen%d.Toolbar.Placement", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "TopLeft", value.size)) + screen->saveToolbarPlacement(Toolbar::TopLeft); + else if (! strncasecmp(value.addr, "BottomLeft", value.size)) + screen->saveToolbarPlacement(Toolbar::BottomLeft); + else if (! strncasecmp(value.addr, "TopCenter", value.size)) + screen->saveToolbarPlacement(Toolbar::TopCenter); + else if (! strncasecmp(value.addr, "TopRight", value.size)) + screen->saveToolbarPlacement(Toolbar::TopRight); + else if (! strncasecmp(value.addr, "BottomRight", value.size)) + screen->saveToolbarPlacement(Toolbar::BottomRight); + else + screen->saveToolbarPlacement(Toolbar::BottomCenter); + } else { + screen->saveToolbarPlacement(Toolbar::BottomCenter); + } + screen->removeWorkspaceNames(); + + sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number); + sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + char *search = bstrdup(value.addr); + + for (int i = 0; i < screen->getNumberOfWorkspaces(); i++) { + char *nn; + + if (! i) nn = strtok(search, ","); + else nn = strtok(NULL, ","); + + if (nn) screen->addWorkspaceName(nn); + else break; + } + + delete [] search; + } + + sprintf(name_lookup, "session.screen%d.toolbar.onTop", screen_number); + sprintf(class_lookup, "Session.Screen%d.Toolbar.OnTop", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "true", value.size)) + screen->saveToolbarOnTop(True); + else + screen->saveToolbarOnTop(False); + } else { + screen->saveToolbarOnTop(False); + } + sprintf(name_lookup, "session.screen%d.toolbar.autoHide", screen_number); + sprintf(class_lookup, "Session.Screen%d.Toolbar.autoHide", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "true", value.size)) + screen->saveToolbarAutoHide(True); + else + screen->saveToolbarAutoHide(False); + } else { + screen->saveToolbarAutoHide(False); + } + sprintf(name_lookup, "session.screen%d.focusModel", screen_number); + sprintf(class_lookup, "Session.Screen%d.FocusModel", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "clicktofocus", value.size)) { + screen->saveAutoRaise(False); + screen->saveSloppyFocus(False); + } else if (! strncasecmp(value.addr, "autoraisesloppyfocus", value.size)) { + screen->saveSloppyFocus(True); + screen->saveAutoRaise(True); + } else { + screen->saveSloppyFocus(True); + screen->saveAutoRaise(False); + } + } else { + screen->saveSloppyFocus(True); + screen->saveAutoRaise(False); + } + + sprintf(name_lookup, "session.screen%d.windowZones", screen_number); + sprintf(class_lookup, "Session.Screen%d.WindowZones", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + int i = atoi(value.addr); + screen->saveWindowZones((i == 1 || i == 2 || i == 4) ? i : 1); + } else { + screen->saveWindowZones(1); + } + + sprintf(name_lookup, "session.screen%d.windowPlacement", screen_number); + sprintf(class_lookup, "Session.Screen%d.WindowPlacement", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "RowSmartPlacement", value.size)) + screen->savePlacementPolicy(BScreen::RowSmartPlacement); + else if (! strncasecmp(value.addr, "ColSmartPlacement", value.size)) + screen->savePlacementPolicy(BScreen::ColSmartPlacement); + else + screen->savePlacementPolicy(BScreen::CascadePlacement); + } else { + screen->savePlacementPolicy(BScreen::RowSmartPlacement); + } +#ifdef SLIT + sprintf(name_lookup, "session.screen%d.slit.placement", screen_number); + sprintf(class_lookup, "Session.Screen%d.Slit.Placement", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "TopLeft", value.size)) + screen->saveSlitPlacement(Slit::TopLeft); + else if (! strncasecmp(value.addr, "CenterLeft", value.size)) + screen->saveSlitPlacement(Slit::CenterLeft); + else if (! strncasecmp(value.addr, "BottomLeft", value.size)) + screen->saveSlitPlacement(Slit::BottomLeft); + else if (! strncasecmp(value.addr, "TopCenter", value.size)) + screen->saveSlitPlacement(Slit::TopCenter); + else if (! strncasecmp(value.addr, "BottomCenter", value.size)) + screen->saveSlitPlacement(Slit::BottomCenter); + else if (! strncasecmp(value.addr, "TopRight", value.size)) + screen->saveSlitPlacement(Slit::TopRight); + else if (! strncasecmp(value.addr, "BottomRight", value.size)) + screen->saveSlitPlacement(Slit::BottomRight); + else + screen->saveSlitPlacement(Slit::CenterRight); + } else { + screen->saveSlitPlacement(Slit::CenterRight); + } + sprintf(name_lookup, "session.screen%d.slit.direction", screen_number); + sprintf(class_lookup, "Session.Screen%d.Slit.Direction", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "Horizontal", value.size)) + screen->saveSlitDirection(Slit::Horizontal); + else + screen->saveSlitDirection(Slit::Vertical); + } else { + screen->saveSlitDirection(Slit::Vertical); + } + sprintf(name_lookup, "session.screen%d.slit.onTop", screen_number); + sprintf(class_lookup, "Session.Screen%d.Slit.OnTop", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "True", value.size)) + screen->saveSlitOnTop(True); + else + screen->saveSlitOnTop(False); + } else { + screen->saveSlitOnTop(False); + } + sprintf(name_lookup, "session.screen%d.slit.autoHide", screen_number); + sprintf(class_lookup, "Session.Screen%d.Slit.AutoHide", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (! strncasecmp(value.addr, "True", value.size)) + screen->saveSlitAutoHide(True); + else + screen->saveSlitAutoHide(False); + } else { + screen->saveSlitAutoHide(False); + } +#endif // SLIT + +#ifdef HAVE_STRFTIME + sprintf(name_lookup, "session.screen%d.strftimeFormat", screen_number); + sprintf(class_lookup, "Session.Screen%d.StrftimeFormat", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + screen->saveStrftimeFormat(value.addr); + } else { + screen->saveStrftimeFormat("%I:%M %p"); + } +#else // HAVE_STRFTIME + sprintf(name_lookup, "session.screen%d.dateFormat", screen_number); + sprintf(class_lookup, "Session.Screen%d.DateFormat", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + if (strncasecmp(value.addr, "european", value.size)) + screen->saveDateFormat(B_AmericanDate); + else + screen->saveDateFormat(B_EuropeanDate); + } else { + screen->saveDateFormat(B_AmericanDate); + } + sprintf(name_lookup, "session.screen%d.clockFormat", screen_number); + sprintf(class_lookup, "Session.Screen%d.ClockFormat", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + int clock; + if (sscanf(value.addr, "%d", &clock) != 1) screen->saveClock24Hour(False); + else if (clock == 24) screen->saveClock24Hour(True); + else screen->saveClock24Hour(False); + } else { + screen->saveClock24Hour(False); + } +#endif // HAVE_STRFTIME + + sprintf(name_lookup, "session.screen%d.edgeSnapThreshold", screen_number); + sprintf(class_lookup, "Session.Screen%d.EdgeSnapThreshold", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + int threshold; + if (sscanf(value.addr, "%d", &threshold) != 1) + screen->saveEdgeSnapThreshold(0); + else + screen->saveEdgeSnapThreshold(threshold); + } else { + screen->saveEdgeSnapThreshold(0); + } + sprintf(name_lookup, "session.screen%d.imageDither", screen_number); + sprintf(class_lookup, "Session.Screen%d.ImageDither", screen_number); + if (XrmGetResource(database, "session.imageDither", "Session.ImageDither", + &value_type, &value)) { + if (! strncasecmp("true", value.addr, value.size)) + screen->saveImageDither(True); + else + screen->saveImageDither(False); + } else { + screen->saveImageDither(True); + } + + sprintf(name_lookup, "session.screen%d.rootCommand", screen_number); + sprintf(class_lookup, "Session.Screen%d.RootCommand", screen_number); + if (XrmGetResource(database, name_lookup, class_lookup, &value_type, + &value)) { + screen->saveRootCommand(value.addr); + } else + screen->saveRootCommand(NULL); + + if (XrmGetResource(database, "session.opaqueMove", "Session.OpaqueMove", + &value_type, &value)) { + if (! strncasecmp("true", value.addr, value.size)) + screen->saveOpaqueMove(True); + else + screen->saveOpaqueMove(False); + } else { + screen->saveOpaqueMove(False); + } + XrmDestroyDatabase(database); +} + + +void Openbox::reload_rc(void) { + load_rc(); + reconfigure(); +} + + +void Openbox::reconfigure(void) { + reconfigure_wait = True; + + if (! timer->isTiming()) timer->start(); +} + + +void Openbox::real_reconfigure(void) { + grab(); + + XrmDatabase new_openboxrc = (XrmDatabase) 0; + char style[MAXPATHLEN + 64]; + + sprintf(style, "session.styleFile: %s", resource.style_file); + XrmPutLineResource(&new_openboxrc, style); + + XrmDatabase old_openboxrc = XrmGetFileDatabase(rc_file); + + XrmMergeDatabases(new_openboxrc, &old_openboxrc); + XrmPutFileDatabase(old_openboxrc, rc_file); + if (old_openboxrc) XrmDestroyDatabase(old_openboxrc); + + for (int i = 0, n = menuTimestamps->count(); i < n; i++) { + MenuTimestamp *ts = menuTimestamps->remove(0); + + if (ts) { + if (ts->filename) + delete [] ts->filename; + + delete ts; + } + } + + LinkedListIterator it(screenList); + for (BScreen *screen = it.current(); screen; it++, screen = it.current()) { + screen->reconfigure(); + } + + ungrab(); +} + + +void Openbox::checkMenu(void) { + Bool reread = False; + LinkedListIterator it(menuTimestamps); + for (MenuTimestamp *tmp = it.current(); tmp && (! reread); + it++, tmp = it.current()) { + struct stat buf; + + if (! stat(tmp->filename, &buf)) { + if (tmp->timestamp != buf.st_ctime) + reread = True; + } else { + reread = True; + } + } + + if (reread) rereadMenu(); +} + + +void Openbox::rereadMenu(void) { + reread_menu_wait = True; + + if (! timer->isTiming()) timer->start(); +} + + +void Openbox::real_rereadMenu(void) { + for (int i = 0, n = menuTimestamps->count(); i < n; i++) { + MenuTimestamp *ts = menuTimestamps->remove(0); + + if (ts) { + if (ts->filename) + delete [] ts->filename; + + delete ts; + } + } + + LinkedListIterator it(screenList); + for (BScreen *screen = it.current(); screen; it++, screen = it.current()) + screen->rereadMenu(); +} + + +void Openbox::saveStyleFilename(const char *filename) { + if (resource.style_file) + delete [] resource.style_file; + + resource.style_file = bstrdup(filename); +} + + +void Openbox::saveMenuFilename(const char *filename) { + Bool found = False; + + LinkedListIterator it(menuTimestamps); + for (MenuTimestamp *tmp = it.current(); tmp && (! found); + it++, tmp = it.current()) { + if (! strcmp(tmp->filename, filename)) found = True; + } + if (! found) { + struct stat buf; + + if (! stat(filename, &buf)) { + MenuTimestamp *ts = new MenuTimestamp; + + ts->filename = bstrdup(filename); + ts->timestamp = buf.st_ctime; + + menuTimestamps->insert(ts); + } + } +} + + +void Openbox::timeout(void) { + if (reconfigure_wait) + real_reconfigure(); + + if (reread_menu_wait) + real_rereadMenu(); + + reconfigure_wait = reread_menu_wait = False; +} + + +void Openbox::setFocusedWindow(OpenboxWindow *win) { + BScreen *old_screen = (BScreen *) 0, *screen = (BScreen *) 0; + OpenboxWindow *old_win = (OpenboxWindow *) 0; + Toolbar *old_tbar = (Toolbar *) 0, *tbar = (Toolbar *) 0; + Workspace *old_wkspc = (Workspace *) 0, *wkspc = (Workspace *) 0; + + if (focused_window) { + old_win = focused_window; + old_screen = old_win->getScreen(); + old_tbar = old_screen->getToolbar(); + old_wkspc = old_screen->getWorkspace(old_win->getWorkspaceNumber()); + + old_win->setFocusFlag(False); + old_wkspc->getMenu()->setItemSelected(old_win->getWindowNumber(), False); + } + + if (win && ! win->isIconic()) { + screen = win->getScreen(); + tbar = screen->getToolbar(); + wkspc = screen->getWorkspace(win->getWorkspaceNumber()); + + focused_window = win; + + win->setFocusFlag(True); + wkspc->getMenu()->setItemSelected(win->getWindowNumber(), True); + } else { + focused_window = (OpenboxWindow *) 0; + } + + if (tbar) + tbar->redrawWindowLabel(True); + if (screen) + screen->updateNetizenWindowFocus(); + + if (old_tbar && old_tbar != tbar) + old_tbar->redrawWindowLabel(True); + if (old_screen && old_screen != screen) + old_screen->updateNetizenWindowFocus(); +} diff --git a/src/openbox.h b/src/openbox.h new file mode 100644 index 00000000..6f23e035 --- /dev/null +++ b/src/openbox.h @@ -0,0 +1,212 @@ +// openbox.h for Openbox +// 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 __openbox_hh +#define __openbox_hh + +#include +#include + +#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 "LinkedList.h" +#include "BaseDisplay.h" +#include "Timer.h" + +//forward declaration +class BScreen; +class Openbox; +class BImageControl; +class OpenboxWindow; +class Basemenu; +class Toolbar; +#ifdef SLIT +class Slit; +#endif // SLIT + +template +class DataSearch { +private: + Window window; + Z *data; + +public: + DataSearch(Window w, Z *d): window(w), data(d) {} + + inline const Window &getWindow(void) const { return window; } + inline Z *getData(void) { return data; } +}; + + +class Openbox : public BaseDisplay, public TimeoutHandler { +private: + typedef struct MenuTimestamp { + char *filename; + time_t timestamp; + } MenuTimestamp; + + struct resource { + Time double_click_interval; + + char *menu_file, *style_file; + char *titlebar_layout; + int colors_per_channel; + timeval auto_raise_delay; + unsigned long cache_life, cache_max; + } resource; + + typedef DataSearch WindowSearch; + LinkedList *windowSearchList, *groupSearchList; + typedef DataSearch MenuSearch; + LinkedList *menuSearchList; + typedef DataSearch ToolbarSearch; + LinkedList *toolbarSearchList; + +#ifdef SLIT + typedef DataSearch SlitSearch; + LinkedList *slitSearchList; +#endif // SLIT + + LinkedList *menuTimestamps; + LinkedList *screenList; + + OpenboxWindow *focused_window, *masked_window; + BTimer *timer; + +#ifdef HAVE_GETPID + Atom openbox_pid; +#endif // HAVE_GETPID + + Bool no_focus, reconfigure_wait, reread_menu_wait; + Time last_time; + Window masked; + char *rc_file, **argv; + int argc; + + +protected: + void load_rc(void); + void save_rc(void); + void reload_rc(void); + void real_rereadMenu(void); + void real_reconfigure(void); + + virtual void process_event(XEvent *); + + +public: + Openbox(int, char **, char * = 0, char * = 0); + virtual ~Openbox(void); + +#ifdef HAVE_GETPID + inline const Atom &getOpenboxPidAtom(void) const { return openbox_pid; } +#endif // HAVE_GETPID + + Basemenu *searchMenu(Window); + + OpenboxWindow *searchGroup(Window, OpenboxWindow *); + OpenboxWindow *searchWindow(Window); + inline OpenboxWindow *getFocusedWindow(void) { return focused_window; } + + BScreen *getScreen(int); + BScreen *searchScreen(Window); + + inline const Time &getDoubleClickInterval(void) const + { return resource.double_click_interval; } + inline const Time &getLastTime(void) const { return last_time; } + + Toolbar *searchToolbar(Window); + + inline const char *getStyleFilename(void) const + { return resource.style_file; } + inline const char *getMenuFilename(void) const + { return resource.menu_file; } + + inline const int &getColorsPerChannel(void) const + { return resource.colors_per_channel; } + + inline const timeval &getAutoRaiseDelay(void) const + { return resource.auto_raise_delay; } + + inline const char *getTitleBarLayout(void) const + { return resource.titlebar_layout; } + + inline const unsigned long &getCacheLife(void) const + { return resource.cache_life; } + inline const unsigned long &getCacheMax(void) const + { return resource.cache_max; } + + inline void maskWindowEvents(Window w, OpenboxWindow *bw) + { masked = w; masked_window = bw; } + inline void setNoFocus(Bool f) { no_focus = f; } + + void setFocusedWindow(OpenboxWindow *w); + void shutdown(void); + void load_rc(BScreen *); + void saveStyleFilename(const char *); + void saveMenuFilename(const char *); + void saveMenuSearch(Window, Basemenu *); + void saveWindowSearch(Window, OpenboxWindow *); + void saveToolbarSearch(Window, Toolbar *); + void saveGroupSearch(Window, OpenboxWindow *); + void removeMenuSearch(Window); + void removeWindowSearch(Window); + void removeToolbarSearch(Window); + void removeGroupSearch(Window); + void restart(const char * = 0); + void reconfigure(void); + void rereadMenu(void); + void checkMenu(void); + + virtual Bool handleSignal(int); + + virtual void timeout(void); + +#ifdef SLIT + Slit *searchSlit(Window); + + void saveSlitSearch(Window, Slit *); + void removeSlitSearch(Window); +#endif // SLIT + +#ifndef HAVE_STRFTIME + + enum { B_AmericanDate = 1, B_EuropeanDate }; +#endif // HAVE_STRFTIME +}; + + +#endif // __openbox_hh -- cgit v1.2.3