WINDOWS GET FRAMES FRAME SHOW UP THEY WORK HUZZAH SOON THEYLL BE LIKE OLD TIMES!
This commit is contained in:
parent
f2ae1c3b17
commit
b9cac2146e
6 changed files with 313 additions and 43 deletions
|
@ -15,7 +15,7 @@ bin_PROGRAMS= openbox3
|
|||
|
||||
openbox3_LDADD=../otk/libotk.a @LIBINTL@
|
||||
|
||||
openbox3_SOURCES= client.cc screen.cc openbox.cc \
|
||||
openbox3_SOURCES= client.cc frame.cc screen.cc openbox.cc \
|
||||
bbwindow.cc workspace.cc blackbox.cc \
|
||||
main.cc xeventhandler.cc
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "client.hh"
|
||||
#include "screen.hh"
|
||||
#include "openbox.hh"
|
||||
|
@ -18,8 +22,8 @@ extern "C" {
|
|||
|
||||
namespace ob {
|
||||
|
||||
OBClient::OBClient(Window window)
|
||||
: _window(window)
|
||||
OBClient::OBClient(int screen, Window window)
|
||||
: _screen(screen), _window(window)
|
||||
{
|
||||
assert(window);
|
||||
|
||||
|
@ -78,6 +82,7 @@ OBClient::OBClient(Window window)
|
|||
updateIconTitle();
|
||||
updateClass();
|
||||
|
||||
/*
|
||||
#ifdef DEBUG
|
||||
printf("Mapped window: 0x%lx\n"
|
||||
" title: \t%s\t icon title: \t%s\n"
|
||||
|
@ -123,6 +128,7 @@ OBClient::OBClient(Window window)
|
|||
_floating ? "yes" : "no",
|
||||
_positioned ? "yes" : "no");
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ extern "C" {
|
|||
|
||||
namespace ob {
|
||||
|
||||
class OBFrame;
|
||||
|
||||
//! Maintains the state of a client window.
|
||||
/*!
|
||||
OBClient maintains the state of a client window. The state consists of the
|
||||
|
@ -32,6 +34,10 @@ namespace ob {
|
|||
*/
|
||||
class OBClient {
|
||||
public:
|
||||
|
||||
//! The frame window which decorates around the client window
|
||||
OBFrame *frame;
|
||||
|
||||
//! Possible window types
|
||||
enum WindowType { Type_Desktop, //!< A desktop (bottom-most window)
|
||||
Type_Dock, //!< A dock bar/panel window
|
||||
|
@ -107,7 +113,14 @@ public:
|
|||
State_Toggle //!< _NET_WM_STATE_TOGGLE
|
||||
};
|
||||
|
||||
//! The event mask to grab on client windows
|
||||
static const long event_mask = PropertyChangeMask | FocusChangeMask |
|
||||
StructureNotifyMask;
|
||||
|
||||
private:
|
||||
//! The screen number on which the client resides
|
||||
int _screen;
|
||||
|
||||
//! The actual window that this class is wrapping up
|
||||
Window _window;
|
||||
|
||||
|
@ -272,11 +285,15 @@ public:
|
|||
//! Constructs a new OBClient object around a specified window id
|
||||
/*!
|
||||
@param window The window id that the OBClient class should handle
|
||||
@param screen The screen on which the window resides
|
||||
*/
|
||||
OBClient(Window window);
|
||||
OBClient(int screen, Window window);
|
||||
//! Destroys the OBClient object
|
||||
virtual ~OBClient();
|
||||
|
||||
//! Returns the screen on which the clien resides
|
||||
inline int screen() const { return _screen; }
|
||||
|
||||
//! Returns the window id that the OBClient object is handling
|
||||
inline Window window() const { return _window; }
|
||||
|
||||
|
|
149
src/frame.cc
Normal file
149
src/frame.cc
Normal file
|
@ -0,0 +1,149 @@
|
|||
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "frame.hh"
|
||||
#include "client.hh"
|
||||
#include "otk/display.hh"
|
||||
|
||||
namespace ob {
|
||||
|
||||
OBFrame::OBFrame(const OBClient *client, const otk::Style *style)
|
||||
: _client(client),
|
||||
_screen(otk::OBDisplay::screenInfo(client->screen()))
|
||||
{
|
||||
assert(client);
|
||||
assert(style);
|
||||
|
||||
_style = 0;
|
||||
loadStyle(style);
|
||||
|
||||
_window = createFrame();
|
||||
assert(_window);
|
||||
|
||||
grabClient();
|
||||
}
|
||||
|
||||
|
||||
OBFrame::~OBFrame()
|
||||
{
|
||||
releaseClient(false);
|
||||
}
|
||||
|
||||
|
||||
void OBFrame::loadStyle(const otk::Style *style)
|
||||
{
|
||||
assert(style);
|
||||
|
||||
// if a style was previously set, then 'replace' is true, cause we're
|
||||
// replacing a style
|
||||
// NOTE: if this is false, then DO NOT DO SHIT WITH _window, it doesnt exist
|
||||
bool replace = (_style);
|
||||
|
||||
if (replace) {
|
||||
// XXX: do shit here whatever
|
||||
}
|
||||
|
||||
_style = style;
|
||||
|
||||
// XXX: load shit like this from the style!
|
||||
_size.left = _size.top = _size.bottom = _size.right = 2;
|
||||
|
||||
if (replace) {
|
||||
XSetWindowBorderWidth(otk::OBDisplay::display, _window,
|
||||
_style->getBorderWidth());
|
||||
|
||||
// XXX: make everything redraw
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OBFrame::resize()
|
||||
{
|
||||
XResizeWindow(otk::OBDisplay::display, _window,
|
||||
_size.left + _size.right + _client->area().width(),
|
||||
_size.top + _size.bottom + _client->area().height());
|
||||
// XXX: more is gunna have to happen here
|
||||
}
|
||||
|
||||
|
||||
void OBFrame::shape()
|
||||
{
|
||||
// XXX: if shaped, shape the frame to the client..
|
||||
}
|
||||
|
||||
|
||||
void OBFrame::grabClient()
|
||||
{
|
||||
|
||||
XGrabServer(otk::OBDisplay::display);
|
||||
|
||||
// select the event mask on the frame
|
||||
XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask);
|
||||
|
||||
// reparent the client to the frame
|
||||
XSelectInput(otk::OBDisplay::display, _client->window(),
|
||||
OBClient::event_mask & ~StructureNotifyMask);
|
||||
XReparentWindow(otk::OBDisplay::display, _client->window(), _window, 0, 0);
|
||||
XSelectInput(otk::OBDisplay::display, _client->window(),
|
||||
OBClient::event_mask);
|
||||
|
||||
// raise the client above the frame
|
||||
XRaiseWindow(otk::OBDisplay::display, _client->window());
|
||||
// map the client so it maps when the frame does
|
||||
XMapWindow(otk::OBDisplay::display, _client->window());
|
||||
|
||||
XUngrabServer(otk::OBDisplay::display);
|
||||
|
||||
resize();
|
||||
shape();
|
||||
}
|
||||
|
||||
|
||||
void OBFrame::releaseClient(bool remap)
|
||||
{
|
||||
// check if the app has already reparented its window to the root window
|
||||
XEvent ev;
|
||||
if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(),
|
||||
ReparentNotify, &ev)) {
|
||||
remap = true; // XXX: why do we remap the window if they already
|
||||
// reparented to root?
|
||||
} else {
|
||||
// according to the ICCCM - if the client doesn't reparent to
|
||||
// root, then we have to do it for them
|
||||
XReparentWindow(otk::OBDisplay::display, _client->window(),
|
||||
_screen->getRootWindow(),
|
||||
_client->area().x(), _client->area().y());
|
||||
}
|
||||
|
||||
// if we want to remap the window, do so now
|
||||
if (remap)
|
||||
XMapWindow(otk::OBDisplay::display, _client->window());
|
||||
}
|
||||
|
||||
|
||||
Window OBFrame::createFrame()
|
||||
{
|
||||
XSetWindowAttributes attrib_create;
|
||||
unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
|
||||
CWOverrideRedirect | CWEventMask;
|
||||
|
||||
attrib_create.background_pixmap = None;
|
||||
attrib_create.colormap = _screen->getColormap();
|
||||
attrib_create.override_redirect = True;
|
||||
attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress;
|
||||
/*
|
||||
We catch button presses because other wise they get passed down to the
|
||||
root window, which will then cause root menus to show when you click the
|
||||
window's frame.
|
||||
*/
|
||||
|
||||
return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(),
|
||||
0, 0, 1, 1, _style->getBorderWidth(),
|
||||
_screen->getDepth(), InputOutput, _screen->getVisual(),
|
||||
create_mask, &attrib_create);
|
||||
}
|
||||
|
||||
}
|
75
src/frame.hh
Normal file
75
src/frame.hh
Normal file
|
@ -0,0 +1,75 @@
|
|||
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
|
||||
#ifndef __frame_hh
|
||||
#define __frame_hh
|
||||
|
||||
/*! @file frame.hh
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <X11/Xlib.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "otk/strut.hh"
|
||||
#include "otk/rect.hh"
|
||||
#include "otk/screeninfo.hh"
|
||||
#include "otk/style.hh"
|
||||
|
||||
namespace ob {
|
||||
|
||||
class OBClient;
|
||||
|
||||
//! Holds and decorates a frame around an OBClient (client window)
|
||||
/*!
|
||||
*/
|
||||
class OBFrame {
|
||||
private:
|
||||
const OBClient *_client;
|
||||
const otk::ScreenInfo *_screen;
|
||||
|
||||
//! The style to use for size and display the decorations
|
||||
const otk::Style *_style;
|
||||
|
||||
//! The window id of the base frame window
|
||||
Window _window;
|
||||
//! The size of the frame on each side of the client window
|
||||
otk::Strut _size;
|
||||
|
||||
//! Creates the base frame window
|
||||
Window createFrame();
|
||||
|
||||
//! Reparents the client window from the root window onto the frame
|
||||
void grabClient();
|
||||
//! Reparents the client window back to the root window
|
||||
/*!
|
||||
@param remap Re-map the client window when we're done reparenting?
|
||||
*/
|
||||
void releaseClient(bool remap);
|
||||
|
||||
public:
|
||||
//! Constructs an OBFrame object, and reparents the client to itself
|
||||
/*!
|
||||
@param client The client window which will be decorated by the new OBFrame
|
||||
@param style The style to use to decorate the frame
|
||||
*/
|
||||
OBFrame(const OBClient *client, const otk::Style *style);
|
||||
//! Destroys the OBFrame object
|
||||
virtual ~OBFrame();
|
||||
|
||||
//! Load a style to decorate the frame with
|
||||
void loadStyle(const otk::Style *style);
|
||||
|
||||
//! Size the frame to the client
|
||||
void resize();
|
||||
//! Shape the frame window to the client window
|
||||
void shape();
|
||||
|
||||
//! Returns the frame's most-parent window, which is a child of the root
|
||||
//! window
|
||||
inline Window window() const { return _window; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __frame_hh
|
|
@ -2,10 +2,15 @@
|
|||
|
||||
#include "xeventhandler.hh"
|
||||
#include "client.hh"
|
||||
#include "frame.hh"
|
||||
#include "openbox.hh"
|
||||
#include "otk/display.hh"
|
||||
#include "otk/rect.hh"
|
||||
|
||||
// XXX: REMOVE THIS SOON!!#!
|
||||
#include "blackbox.hh"
|
||||
#include "screen.hh"
|
||||
|
||||
extern "C" {
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
@ -119,7 +124,7 @@ void OBXEventHandler::configureRequest(const XConfigureRequestEvent &e)
|
|||
|
||||
|
||||
// XXX: put this into the OBScreen or OBClient class!
|
||||
static void manageWindow(Window window)
|
||||
static void manageWindow(int screen, Window window)
|
||||
{
|
||||
OBClient *client = 0;
|
||||
XWMHints *wmhint;
|
||||
|
@ -139,15 +144,14 @@ static void manageWindow(Window window)
|
|||
}
|
||||
|
||||
// choose the events we want to receive on the CLIENT window
|
||||
attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
|
||||
StructureNotifyMask;
|
||||
attrib_set.event_mask = OBClient::event_mask;
|
||||
attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
|
||||
ButtonMotionMask;
|
||||
XChangeWindowAttributes(otk::OBDisplay::display, window,
|
||||
CWEventMask|CWDontPropagate, &attrib_set);
|
||||
|
||||
// create the OBClient class, which gets all of the hints on the window
|
||||
Openbox::instance->addClient(window, client = new OBClient(window));
|
||||
Openbox::instance->addClient(window, client = new OBClient(screen, window));
|
||||
|
||||
// we dont want a border on the client
|
||||
XSetWindowBorderWidth(otk::OBDisplay::display, window, 0);
|
||||
|
@ -159,14 +163,15 @@ static void manageWindow(Window window)
|
|||
if (!client->positionRequested()) {
|
||||
// XXX: position the window intelligenty
|
||||
}
|
||||
|
||||
// XXX: store a style somewheres cooler!!
|
||||
otk::Style *style = ((Blackbox*)Openbox::instance)->
|
||||
searchScreen(RootWindow(otk::OBDisplay::display, screen))->
|
||||
getWindowStyle();
|
||||
client->frame = new OBFrame(client, style);
|
||||
|
||||
// XXX: grab server, reparent client to the frame, ungrab server
|
||||
|
||||
// XXX: if shaped, shape the frame..
|
||||
|
||||
// XXX: if on the current desktop..
|
||||
/// XMapSubwindows(otk::OBDisplay::display, FRAMEWINDOW);
|
||||
XMapWindow(otk::OBDisplay::display, window);
|
||||
XMapWindow(otk::OBDisplay::display, client->frame->window());
|
||||
|
||||
// XXX: handle any requested states such as shaded/maximized
|
||||
}
|
||||
|
@ -174,46 +179,27 @@ static void manageWindow(Window window)
|
|||
// XXX: move this to the OBScreen or OBClient class!
|
||||
static void unmanageWindow(OBClient *client)
|
||||
{
|
||||
bool remap = false; // remap the window when we're done?
|
||||
|
||||
Window window = client->window();
|
||||
OBFrame *frame = client->frame;
|
||||
|
||||
// XXX: pass around focus if this window was focused
|
||||
|
||||
// remove the window from our save set
|
||||
XChangeSaveSet(otk::OBDisplay::display, window, SetModeDelete);
|
||||
XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
|
||||
|
||||
// we dont want events no more
|
||||
XSelectInput(otk::OBDisplay::display, window, NoEventMask);
|
||||
XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
|
||||
|
||||
// XXX: XUnmapWindow(otk::OBDisplay::display, FRAME);
|
||||
XUnmapWindow(otk::OBDisplay::display, window);
|
||||
XUnmapWindow(otk::OBDisplay::display, frame->window());
|
||||
|
||||
// we dont want a border on the client
|
||||
XSetWindowBorderWidth(otk::OBDisplay::display, window,client->borderWidth());
|
||||
XSetWindowBorderWidth(otk::OBDisplay::display, client->window(),
|
||||
client->borderWidth());
|
||||
|
||||
// remove the client class from the search list
|
||||
Openbox::instance->removeClient(window);
|
||||
Openbox::instance->removeClient(client->window());
|
||||
|
||||
// check if the app has already reparented its window to the root window
|
||||
XEvent ev;
|
||||
if (XCheckTypedWindowEvent(otk::OBDisplay::display, window, ReparentNotify,
|
||||
&ev)) {
|
||||
remap = true; // XXX: why do we remap the window if they already
|
||||
// reparented to root?
|
||||
} else {
|
||||
// according to the ICCCM - if the client doesn't reparent to
|
||||
// root, then we have to do it for them
|
||||
XReparentWindow(otk::OBDisplay::display, window,
|
||||
RootWindow(otk::OBDisplay::display,
|
||||
DefaultScreen(otk::OBDisplay::display)),
|
||||
// XXX: screen->getRootWindow(),
|
||||
client->area().x(), client->area().y());
|
||||
}
|
||||
|
||||
// if we want to remap the window, do so now
|
||||
if (remap)
|
||||
XMapWindow(otk::OBDisplay::display, window);
|
||||
delete client->frame;
|
||||
client->frame = 0;
|
||||
|
||||
delete client;
|
||||
}
|
||||
|
@ -229,7 +215,44 @@ void OBXEventHandler::mapRequest(const XMapRequestEvent &e)
|
|||
if (client) {
|
||||
// XXX: uniconify and/or unshade the window
|
||||
} else {
|
||||
manageWindow(e.window);
|
||||
int screen = INT_MAX;
|
||||
|
||||
for (int i = 0; i < ScreenCount(otk::OBDisplay::display); ++i)
|
||||
if (otk::OBDisplay::screenInfo(i)->getRootWindow() == e.parent) {
|
||||
screen = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (screen >= ScreenCount(otk::OBDisplay::display)) {
|
||||
/*
|
||||
we got a map request for a window who's parent isn't root. this
|
||||
can happen in only one circumstance:
|
||||
|
||||
a client window unmapped a managed window, and then remapped it
|
||||
somewhere between unmapping the client window and reparenting it
|
||||
to root.
|
||||
|
||||
regardless of how it happens, we need to find the screen that
|
||||
the window is on
|
||||
*/
|
||||
XWindowAttributes wattrib;
|
||||
if (! XGetWindowAttributes(otk::OBDisplay::display, e.window,
|
||||
&wattrib)) {
|
||||
// failed to get the window attributes, perhaps the window has
|
||||
// now been destroyed?
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ScreenCount(otk::OBDisplay::display); ++i)
|
||||
if (otk::OBDisplay::screenInfo(i)->getRootWindow() == wattrib.root) {
|
||||
screen = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(screen < ScreenCount(otk::OBDisplay::display));
|
||||
|
||||
manageWindow(screen, e.window);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue