mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
509 lines
13 KiB
C++
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;
|
||
|
}
|