ede/edewm/Events.cpp

509 lines
13 KiB
C++

/*
* $Id: Events.cpp 1712 2006-07-25 10:04:41Z karijes $
*
* Edewm, window manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2000-2006 EDE Authors.
*
* This program is licenced under terms of the
* GNU General Public Licence version 2 or newer.
* See COPYING for details.
*/
#include "Events.h"
#include "Frame.h"
#include "Titlebar.h"
#include "Windowmanager.h"
#include "Tracers.h"
#include "Atoms.h"
#include "Hints.h"
#include "Cursor.h"
#include "debug.h"
#include <assert.h>
#define FRAME_NAME(frame) (frame->label ? frame->label : "NULL")
FrameEventHandler::FrameEventHandler(Frame* f) : curr_frame(f)
{
assert(curr_frame != NULL);
}
FrameEventHandler::~FrameEventHandler()
{
}
/* Handle efltk events.
* Some events like FL_FOCUS and FL_UNFOCUS are not handled, since
* efltk does not receive this event when when should (for example:
* one window is focused, but other shoud be automatically unfocused).
* X on ther hand send FocusIn and FocusOut when above events ocurr.
*/
int FrameEventHandler::handle_fltk(int event)
{
long gggg;
static long bbbb;
static CursorType ctype;
if(curr_frame->show_titlebar)
{
Titlebar* tbar = curr_frame->titlebar;
assert(tbar != NULL);
if(!curr_frame->resizing())
{
if(Fl::event_inside(tbar->x(), tbar->y(), tbar->w(), tbar->h()) || curr_frame->moving())
return tbar->handle(event);
}
}
switch(event)
{
case FL_SHOW:
case FL_HIDE:
return 0;
case FL_ENTER:
ELOG("FrameEventHandler: FL_ENTER");
return 1;
case FL_LEAVE:
ELOG("FrameEventHandler: FL_LEAVE");
return 1;
case FL_MOVE:
{
// note, I am using coordinates _inside_ window
gggg = curr_frame->resize_type(Fl::event_x(), Fl::event_y());
switch(gggg)
{
case ResizeTypeUpLeft:
ELOG("FrameEventHandler (resizing): ResizeTypeUpLeft");
curr_frame->set_cursor(CURSOR_NW);
ctype = CURSOR_NW;
bbbb = ResizeTypeUpLeft;
return 1;
case ResizeTypeUpRight:
ELOG("FrameEventHandler (resizing): ResizeTypeUpRight");
curr_frame->set_cursor(CURSOR_NE);
ctype = CURSOR_NE;
bbbb = ResizeTypeUpRight;
return 1;
case ResizeTypeDownLeft:
ELOG("FrameEventHandler (resizing): ResizeTypeDownLeft");
curr_frame->set_cursor(CURSOR_SW);
ctype = CURSOR_SW;
bbbb = ResizeTypeDownLeft;
return 1;
case ResizeTypeDownRight:
ELOG("FrameEventHandler (resizing): ResizeTypeDownRight");
curr_frame->set_cursor(CURSOR_SE);
ctype = CURSOR_SE;
bbbb = ResizeTypeDownRight;
return 1;
case ResizeTypeUp:
ELOG("FrameEventHandler (resizing): ResizeTypeUp");
curr_frame->set_cursor(CURSOR_N);
ctype = CURSOR_N;
bbbb = ResizeTypeUp;
return 1;
case ResizeTypeLeft:
ELOG("FrameEventHandler (resizing): ResizeTypeLeft");
curr_frame->set_cursor(CURSOR_W);
ctype = CURSOR_W;
bbbb = ResizeTypeLeft;
return 1;
case ResizeTypeRight:
ELOG("FrameEventHandler (resizing): ResizeTypeRight");
curr_frame->set_cursor(CURSOR_E);
ctype = CURSOR_E;
bbbb = ResizeTypeRight;
return 1;
case ResizeTypeDown:
ELOG("FrameEventHandler (resizing): ResizeTypeDown");
curr_frame->set_cursor(CURSOR_S);
ctype = CURSOR_S;
bbbb = ResizeTypeDown;
return 1;
default:
//curr_frame->set_cursor(CURSOR_DEFAULT);
bbbb = ResizeTypeNone;
return 1;
}
return 1;
}
case FL_PUSH:
ELOG("FrameEventHandler: FL_PUSH");
if(Fl::event_is_click())
{
curr_frame->borders_color(CLICKED);
curr_frame->raise();
}
return 1;
case FL_DRAG:
ELOG("FrameEventHandler: FL_DRAG");
if(bbbb != ResizeTypeNone)
{
if(!curr_frame->resizing())
{
curr_frame->grab_cursor();
curr_frame->resize_start();
curr_frame->show_coordinates_window();
}
//XGrabServer(fl_display);
curr_frame->set_cursor(ctype);
curr_frame->resize_window(Fl::event_x_root(), Fl::event_y_root(), bbbb);
curr_frame->update_coordinates_window();
}
return 1;
case FL_RELEASE:
ELOG("FrameEventHandler: FL_RELEASE");
if(curr_frame->resizing())
{
//XUngrabServer(fl_display);
curr_frame->resize_end();
curr_frame->ungrab_cursor();
curr_frame->hide_coordinates_window();
curr_frame->set_cursor(CURSOR_DEFAULT);
}
//curr_frame->color(FL_GRAY);
curr_frame->borders_color(FOCUSED);
return 1;
default:
// let other events go to sizers
return curr_frame->handle_parent(event);
}
return 0;
}
int FrameEventHandler::handle_x(XEvent* event)
{
switch(event->type)
{
case MapRequest:
return map_event(event->xmaprequest);
case UnmapNotify:
return unmap_event(event->xunmap);
case ReparentNotify:
return reparent_event(event->xreparent);
case DestroyNotify:
return destroy_event(event->xdestroywindow);
/*case ClientMessage:
return client_message(event->xclient);*/
case LeaveNotify:
case EnterNotify:
return enter_leave_event(event->xcrossing);
/* FocusIn, as FocusOut is not used, but for
* debugging is here. When we map a large number
* of windows, X seems goes into (for me unknown)
* infinite FocusIn/FocusOut loop, which blocks
* everything. So, to keep us far away from pain,
* leave FocusIn for someone else. Here should not
* be used.
*/
case FocusIn:
{
ELOG("FrameEventHandler: FocusIn");
switch(event->xfocus.mode)
{
case NotifyNormal:
ELOG(" - NotifyNormal");
break;
case NotifyGrab:
ELOG(" - NotifyGrab");
break;
case NotifyUngrab:
ELOG(" - NotifyUngrab");
break;
}
if(event->xfocus.send_event)
ELOG(" - got from SendEvent");
/* This will prevent menus, etc.
* to steal focus from parent.
*/
//if(event->xfocus.mode == NotifyNormal)
// curr_frame->focus();
}
return 1;
/* FocusOut really fuck up focusing so
* it is not handled. Either xfocus.mode == NotifyNormal
* does not helps when window emits menu, since menu
* itself will yield FocusOut for parent and FocusIn
* for itself. Unfortunately I don't know any toolkit
* which export some kind MENU flag, where we can check.
* So, let we shut it up, make ourself little bit happy
* and take all burden of FocusOut to ourself (which made
* use very very unhappy).
*/
case FocusOut:
{
ELOG("FrameEventHandler: FocusOut");
switch(event->xfocus.mode)
{
case NotifyNormal:
ELOG(" - NotifyNormal");
break;
case NotifyGrab:
ELOG(" - NotifyGrab");
break;
case NotifyUngrab:
ELOG(" - NotifyUngrab");
break;
}
if(event->xfocus.send_event)
ELOG(" - got from SendEvent");
//curr_frame->unfocus();
}
return 1;
case PropertyNotify:
return property_event(event->xproperty);
case ConfigureRequest:
return configure_event(event->xconfigurerequest);
return 1;
default:
#ifdef _DEBUG
const char* name = WindowManager::instance()->xevent_map[event->type];
if(name)
ELOG("Got unhandled %s in frame", name);
else
ELOG("Got unhandled event in frame (%i)", event->type);
#endif
return 0;
}
return 0;
}
int FrameEventHandler::map_event(const XMapRequestEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::map_event(const XMapRequestEvent& e)");
assert(e.window == curr_frame->window());
curr_frame->map();
return 1;
}
int FrameEventHandler::unmap_event(const XUnmapEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::unmap_event(const XUnmapEvent& e)");
//assert(e.window == curr_frame->window());
if(e.window != curr_frame->window())
return 1;
ELOG("FrameEventHandler: UnmapNotify (%s)", FRAME_NAME(curr_frame->fdata));
if(e.from_configure)
return 1;
if(curr_frame->option(FrameOptIgnoreUnmap))
{
ELOG("Frame have FrameOptIgnoreUnmap, skiping this event");
curr_frame->clear_option(FrameOptIgnoreUnmap);
}
else
curr_frame->unmap();
return 1;
}
int FrameEventHandler::reparent_event(const XReparentEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::reparent_event(const XReparentEvent& e)");
ELOG("FrameEventHandler: ReparentNotify (%s)", FRAME_NAME(curr_frame->fdata));
// echo
if(e.parent == fl_xid(curr_frame))
return 1;
// app is trying to tear-off again ???
if(e.parent == fl_xid(WindowManager::instance()))
return 1;
if(e.override_redirect)
{
ELOG("override_redirect from reparent_event");
}
EWARNING("Destroy in ReparentNotify!");
curr_frame->destroy();
return 1;
}
int FrameEventHandler::destroy_event(const XDestroyWindowEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::destroy_event(const XDestroyWindowEvent& e)");
curr_frame->destroy();
return 1;
}
int FrameEventHandler::client_message(const XClientMessageEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::client_message(const XClientMessageEvent& e)");
if(!ValidateDrawable(e.window))
return 1;
#ifdef _DEBUG
Atom a = e.message_type;
const char* name = WindowManager::instance()->atom_map[a];
if(name)
ELOG("FrameEventHandler: unhandled atom %s", name);
else
ELOG("FrameEventHandler: unhandled atom %x", a);
#endif
return 1;
}
/* Handle property atoms. Here Netwm atoms are handled
* last, giving them precedence and chance to overwrite
* Icccm stuf (list XA_WM_NAME vs. _XA_NET_WM_NAME)
*/
int FrameEventHandler::property_event(const XPropertyEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::property_event(const XPropertyEvent& e)");
if(e.atom == XA_WM_NAME)
ELOG("XA_WM_NAME");
if(e.atom == XA_WM_ICON_NAME)
ELOG("XA_WM_ICON_NAME");
if(e.atom == XA_WM_HINTS)
ELOG("XA_WM_HINTS");
if(e.atom == XA_WM_NORMAL_HINTS)
ELOG("XA_WM_NORMAL_HINTS");
if(e.atom == XA_WM_SIZE_HINTS)
ELOG("XA_WM_SIZE_HINTS");
if(e.atom == XA_WM_TRANSIENT_FOR)
ELOG("XA_WM_TRANSIENT_FOR");
if(e.atom == _XA_WM_COLORMAP_WINDOWS)
ELOG("_XA_WM_COLORMAP_WINDOWS");
if(e.atom == _XA_WM_STATE)
ELOG("_XA_WM_STATE");
if(e.atom == _XA_WM_PROTOCOLS)
ELOG("_XA_WM_PROTOCOLS");
if(e.atom == _XA_NET_WM_WINDOW_TYPE)
ELOG("_XA_NET_WM_WINDOW_TYPE");
if(e.atom == _XA_NET_WM_STRUT)
{
ELOG("_XA_NET_WM_STRUT");
int dummy;
WindowManager::instance()->hints()->netwm_strut(curr_frame->fdata->window,
&dummy, &dummy, &dummy, &dummy);
}
if(e.atom == _XA_NET_WM_NAME)
ELOG("_XA_NET_WM_NAME");
if(e.atom == _XA_NET_WM_ICON)
ELOG("_XA_NET_WM_ICON");
if(e.atom == _XA_KWM_WIN_ICON)
ELOG("_XA_KWM_WIN_ICON");
return 1;
}
/* Handle EnterNotify and LeaveNotify events.
* Here is used only LeaveNotify to change cursor, since it will be
* trigered only on window borders (exact what is needed). On other
* hand, entering frame's child (or plain window) is handled by
* window itself, with ability to change cursor as like.
* Note, this event could not be simulated with FL_LEAVE, since
* it will be trigered only when mouse if off from whole window
* (including childs).
*
* Also, checkings of frame resizings are must, since mouse moving is
* usually faster than window resizing, so we will get flickering in
* cursors changes if not checked.
*
* TODO: better will be cursor is grabbed !
*/
int FrameEventHandler::enter_leave_event(const XCrossingEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::enter_event(const XEnterWindowEvent& e)");
if(curr_frame->state(FrameStateUnmapped))
return 1;
if(e.type == LeaveNotify && !curr_frame->resizing())
curr_frame->set_cursor(CURSOR_DEFAULT);
return 1;
}
/* This message we can get for windows we know about and we don't know
* about (since all root messages are redirected to us). So we first check
* is window is managed by us, and apply changes to it via our functions.
* Otherwise, we configure window directly.
*
* Note: in fltk's fluid(1.1.6), setting x coords will send us pretty
* amount of junk (change x and y in the same time !!!). This is probably
* bug in fluid.
*/
int FrameEventHandler::configure_event(const XConfigureRequestEvent& e)
{
TRACE_FUNCTION("int FrameEventHandler::configure_event(const XConfigureRequestEvent& e)");
if(curr_frame->state(FrameStateUnmapped))
return 1;
if(curr_frame->window() == e.window)
{
ELOG("ConfigureRequest from frame");
if(!ValidateDrawable(curr_frame->window()))
return 1;
int x_pos = curr_frame->fdata->plain.x;
int y_pos = curr_frame->fdata->plain.y;
int w_sz = curr_frame->fdata->plain.w;
int h_sz = curr_frame->fdata->plain.h;
if(e.value_mask & CWX)
x_pos = e.x;
if(e.value_mask & CWY)
y_pos = e.y;
if(e.value_mask & CWWidth)
w_sz = e.width;
if(e.value_mask & CWHeight)
h_sz = e.height;
if(e.value_mask & CWStackMode)
{
if(e.detail == Above)
curr_frame->raise();
if(e.detail == Below)
curr_frame->lower();
}
curr_frame->set_size(x_pos, y_pos, w_sz, h_sz, true);
}
else
{
ELOG("ConfigureRequest from unhandled window");
if(ValidateDrawable(e.window))
{
XWindowChanges wc;
wc.x = e.x;
wc.y = e.y;
wc.width = e.width;
wc.height = e.height;
wc.stack_mode = e.detail;
XConfigureWindow(fl_display, e.window, e.value_mask, &wc);
}
}
return 1;
}