summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/BaseDisplay.cc617
-rw-r--r--src/BaseDisplay.h357
-rw-r--r--src/Basemenu.cc1036
-rw-r--r--src/Basemenu.h170
-rw-r--r--src/Clientmenu.cc64
-rw-r--r--src/Clientmenu.h44
-rw-r--r--src/Configmenu.cc323
-rw-r--r--src/Configmenu.h78
-rw-r--r--src/Iconmenu.cc64
-rw-r--r--src/Iconmenu.h44
-rw-r--r--src/Image.cc2444
-rw-r--r--src/Image.h241
-rw-r--r--src/LinkedList.cc356
-rw-r--r--src/LinkedList.h130
-rw-r--r--src/Makefile.am108
-rw-r--r--src/Makefile.in462
-rw-r--r--src/Netizen.cc116
-rw-r--r--src/Netizen.h60
-rw-r--r--src/Rootmenu.cc113
-rw-r--r--src/Rootmenu.h51
-rw-r--r--src/Screen.cc2281
-rw-r--r--src/Screen.h349
-rw-r--r--src/Slit.cc773
-rw-r--r--src/Slit.h159
-rw-r--r--src/Timer.cc76
-rw-r--r--src/Timer.h78
-rw-r--r--src/Toolbar.cc1260
-rw-r--r--src/Toolbar.h156
-rw-r--r--src/Window.cc3244
-rw-r--r--src/Window.h330
-rw-r--r--src/Windowmenu.cc204
-rw-r--r--src/Windowmenu.h78
-rw-r--r--src/Workspace.cc502
-rw-r--r--src/Workspace.h90
-rw-r--r--src/Workspacemenu.cc69
-rw-r--r--src/Workspacemenu.h45
-rw-r--r--src/bsd-snprintf.c788
-rw-r--r--src/bsd-snprintf.h17
-rw-r--r--src/i18n.cc134
-rw-r--r--src/i18n.h66
-rw-r--r--src/main.cc186
-rw-r--r--src/openbox.cc1797
-rw-r--r--src/openbox.h212
43 files changed, 19772 insertions, 0 deletions
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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+
+#ifdef SHAPE
+# include <X11/extensions/shape.h>
+#endif // SHAPE
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif // HAVE_FCNTL_H
+
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif // HAVE_UNISTD_H
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif // HAVE_SYS_SELECT_H
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#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 <sys/types.h>
+# include <sys/wait.h>
+#endif // HAVE_SYS_WAIT_H
+
+#if defined(HAVE_PROCESS_H) && defined(__EMX__)
+# include <process.h>
+#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<BTimer>;
+
+ screenInfoList = new LinkedList<ScreenInfo>;
+ 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<XModifierKeymap*>(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<BTimer> 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<BTimer> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+// 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<ScreenInfo> *screenInfoList;
+ LinkedList<BTimer> *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 <shaleh@debian.org>
+// 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 <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#include <algorithm>
+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<BasemenuItem>;
+
+ // 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<BasemenuItem> 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<BasemenuItem> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+
+class Openbox;
+class BImageControl;
+class BScreen;
+class Basemenu;
+class BasemenuItem;
+#include "LinkedList.h"
+
+
+class Basemenu {
+private:
+ LinkedList<BasemenuItem> *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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <sys/types.h>
+#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 <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef HAVE_CTYPE_H
+# include <ctype.h>
+#endif // HAVE_CTYPE_H
+
+#include <algorithm>
+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 <mike@mydot.com>
+ // 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<Cache>;
+}
+
+
+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<Cache> 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<Cache> 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<Cache> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#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> *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 <stdio.h>
+#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 Z>
+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 Z>
+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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+
+// 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 <shaleh@debian.org>
+// 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 <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <assert.h>
+
+#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 <stdlib.h>
+# include <string.h>
+# include <sys/types.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_CTYPE_H
+# include <ctype.h>
+#endif // HAVE_CTYPE_H
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif // HAVE_DIRENT_H
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif // HAVE_LOCALE_H
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif // HAVE_UNISTD_H
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif // HAVE_SYS_STAT_H
+
+#ifdef HAVE_STDARG_H
+# include <stdarg.h>
+#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 <algorithm>
+
+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<char>;
+ workspacesList = new LinkedList<Workspace>;
+ rootmenuList = new LinkedList<Rootmenu>;
+ netizenList = new LinkedList<Netizen>;
+ iconList = new LinkedList<OpenboxWindow>;
+
+ 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<Workspace> wit(workspacesList);
+ for (Workspace *w = wit.current(); w; wit++, w = wit.current())
+ w->reconfigure();
+
+ LinkedListIterator<OpenboxWindow> 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<OpenboxWindow> 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<Workspace> 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<Netizen> 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<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendCurrentWorkspace();
+}
+
+
+void BScreen::updateNetizenWorkspaceCount(void) {
+ LinkedListIterator<Netizen> 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<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendWindowFocus(f);
+}
+
+
+void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
+ LinkedListIterator<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendWindowAdd(w, p);
+}
+
+
+void BScreen::updateNetizenWindowDel(Window w) {
+ LinkedListIterator<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendWindowDel(w);
+}
+
+
+void BScreen::updateNetizenWindowRaise(Window w) {
+ LinkedListIterator<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendWindowRaise(w);
+}
+
+
+void BScreen::updateNetizenWindowLower(Window w) {
+ LinkedListIterator<Netizen> it(netizenList);
+ for (Netizen *n = it.current(); n; it++, n = it.current())
+ n->sendWindowLower(w);
+}
+
+
+void BScreen::updateNetizenConfigNotify(XEvent *e) {
+ LinkedListIterator<Netizen> 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<Workspace> 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<Rootmenu> 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<Workspace> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xresource.h>
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else // !TIME_WITH_SYS_TIME
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else // !HAVE_SYS_TIME_H
+# include <time.h>
+# 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<Rootmenu> *rootmenuList;
+ LinkedList<Netizen> *netizenList;
+ LinkedList<OpenboxWindow> *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<char> *workspaceNames;
+ LinkedList<Workspace> *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 <shaleh@debian.org>
+// 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 <X11/keysym.h>
+
+#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<SlitClient>;
+
+ 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<SlitClient> 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<SlitClient> 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<SlitClient> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#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<SlitClient> *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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <sys/time.h>
+# include <time.h>
+#else // !TIME_WITH_SYS_TIME
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else // !HAVE_SYS_TIME_H
+# include <time.h>
+# 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 <shaleh@debian.org>
+// 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 <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else // !TIME_WITH_SYS_TIME
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else // !HAVE_SYS_TIME_H
+# include <time.h>
+# 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+
+#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 <shaleh@debian.org>
+// 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 <X11/Xatom.h>
+#include <X11/keysym.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef DEBUG
+# ifdef HAVE_STDIO_H
+# include <stdio.h>
+# 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#ifdef SHAPE
+# include <X11/extensions/shape.h>
+#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 <shaleh@debian.org>
+// 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 <string.h>
+#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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#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 <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif // STDC_HEADERS
+
+
+Workspace::Workspace(BScreen *scrn, int i) {
+ screen = scrn;
+
+ cascade_x = cascade_y = 32;
+
+ id = i;
+
+ stackingList = new LinkedList<OpenboxWindow>;
+ windowList = new LinkedList<OpenboxWindow>;
+ 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<OpenboxWindow> 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<OpenboxWindow> it(stackingList);
+ for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current())
+ bw->deiconify(False, False);
+}
+
+
+void Workspace::hideAll(void) {
+ LinkedList<OpenboxWindow> lst;
+
+ LinkedListIterator<OpenboxWindow> it(stackingList);
+ for (OpenboxWindow *bw = it.current(); bw; it++, bw = it.current())
+ lst.insert(bw, 0);
+
+ LinkedListIterator<OpenboxWindow> it2(&lst);
+ for (OpenboxWindow *bw = it2.current(); bw; it2++, bw = it2.current())
+ if (! bw->isStuck())
+ bw->withdraw();
+}
+
+
+void Workspace::removeAll(void) {
+ LinkedListIterator<OpenboxWindow> 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<OpenboxWindow> 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<OpenboxWindow> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+
+#include "LinkedList.h"
+
+class BScreen;
+class Clientmenu;
+class Workspace;
+class OpenboxWindow;
+
+class Workspace {
+private:
+ BScreen *screen;
+ OpenboxWindow *lastfocus;
+ Clientmenu *clientmenu;
+
+ LinkedList<OpenboxWindow> *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 <shaleh@debian.org>
+// 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 <shaleh@debian.org>
+// 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 <blong@fiction.net> 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 <blong@fiction.net> 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 <roessler@guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me@cs.hmc.edu> 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 <string.h>
+# include <ctype.h>
+#include <sys/types.h>
+
+/* 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 <stdarg.h>
+# 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 <varargs.h>
+# 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 = "<NULL>";
+ }
+
+ 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 <sys/types.h> /* 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 <shaleh@debian.org>
+// 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 <X11/Xlocale.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+# include <stdio.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#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 <shaleh@debian.org>
+// 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 <locale.h>
+#endif // HAVE_LOCALE_H
+
+#ifdef HAVE_NL_TYPES_H
+extern "C" {
+# include <nl_types.h>
+}
+#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 <shaleh@debian.org>
+// 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 <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_UNISTD_H
+#include <sys/types.h>
+#endif // HAVE_UNISTD_H
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#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 <string>\t\tuse display connection.\n"
+ " -rc <string>\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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+
+#ifdef SHAPE
+#include <X11/extensions/shape.h>
+#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 <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif // STDC_HEADERS
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif // HAVE_UNISTD_H
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif // HAVE_SYS_PARAM_H
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 255
+#endif // MAXPATHLEN
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif // HAVE_SYS_SELECT_H
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif // HAVE_SIGNAL_H
+
+#ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+#endif // HAVE_SYS_SIGNAL_H
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif // HAVE_SYS_STAT_H
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else // !TIME_WITH_SYS_TIME
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else // !HAVE_SYS_TIME_H
+# include <time.h>
+# endif // HAVE_SYS_TIME_H
+#endif // TIME_WITH_SYS_TIME
+
+#ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+#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<WindowSearch>;
+ menuSearchList = new LinkedList<MenuSearch>;
+
+#ifdef SLIT
+ slitSearchList = new LinkedList<SlitSearch>;
+#endif // SLIT
+
+ toolbarSearchList = new LinkedList<ToolbarSearch>;
+ groupSearchList = new LinkedList<WindowSearch>;
+
+ menuTimestamps = new LinkedList<MenuTimestamp>;
+
+ XrmInitialize();
+ load_rc();
+
+#ifdef HAVE_GETPID
+ openbox_pid = XInternAtom(getXDisplay(), "_BLACKBOX_PID", False);
+#endif // HAVE_GETPID
+
+ screenList = new LinkedList<BScreen>;
+ 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<BScreen> 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<BScreen> 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<WindowSearch> 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<WindowSearch> 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<MenuSearch> 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<ToolbarSearch> 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<SlitSearch> 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<WindowSearch> 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<WindowSearch> 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<MenuSearch> 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<ToolbarSearch> 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<SlitSearch> 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<BScreen> 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<BScreen> 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<BScreen> it(screenList);
+ for (BScreen *screen = it.current(); screen; it++, screen = it.current()) {
+ screen->reconfigure();
+ }
+
+ ungrab();
+}
+
+
+void Openbox::checkMenu(void) {
+ Bool reread = False;
+ LinkedListIterator<MenuTimestamp> 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<BScreen> 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<MenuTimestamp> 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 <shaleh@debian.org>
+// 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 <X11/Xlib.h>
+#include <X11/Xresource.h>
+
+#ifdef HAVE_STDIO_H
+# include <stdio.h>
+#endif // HAVE_STDIO_H
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else // !TIME_WITH_SYS_TIME
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else // !HAVE_SYS_TIME_H
+# include <time.h>
+# 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 Z>
+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<OpenboxWindow> WindowSearch;
+ LinkedList<WindowSearch> *windowSearchList, *groupSearchList;
+ typedef DataSearch<Basemenu> MenuSearch;
+ LinkedList<MenuSearch> *menuSearchList;
+ typedef DataSearch<Toolbar> ToolbarSearch;
+ LinkedList<ToolbarSearch> *toolbarSearchList;
+
+#ifdef SLIT
+ typedef DataSearch<Slit> SlitSearch;
+ LinkedList<SlitSearch> *slitSearchList;
+#endif // SLIT
+
+ LinkedList<MenuTimestamp> *menuTimestamps;
+ LinkedList<BScreen> *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