From 6ec45bce2a80facb1473e40ece7d20a148b29616 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Wed, 5 Sep 2007 03:54:24 +0200 Subject: [PATCH] WIP version 3 of edges thinger This is lets you bind actions to clicking on screen edges/corners. Eventually it should also let you bind hovering or entering/leaving and whatnot. --- Makefile.am | 2 + openbox/edges.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++ openbox/edges.h | 31 ++++++++++++++ openbox/event.c | 6 +-- openbox/frame.c | 21 ++++++++- openbox/frame.h | 8 ++++ openbox/openbox.c | 3 ++ openbox/window.h | 7 ++- 8 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 openbox/edges.c create mode 100644 openbox/edges.h diff --git a/Makefile.am b/Makefile.am index b4389043..f1dc5d8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -251,6 +251,8 @@ openbox_openbox_SOURCES = \ openbox/debug.h \ openbox/dock.c \ openbox/dock.h \ + openbox/edges.c \ + openbox/edges.h \ openbox/event.c \ openbox/event.h \ openbox/focus.c \ diff --git a/openbox/edges.c b/openbox/edges.c new file mode 100644 index 00000000..744cd977 --- /dev/null +++ b/openbox/edges.c @@ -0,0 +1,106 @@ +#include "openbox.h" +#include "config.h" +#include "screen.h" +#include "edges.h" +#include "frame.h" + +#include +#include + +#warning Do something clever with xinerama +ObEdge *edge[OB_NUM_EDGES]; +#warning put in config.c and parse configs of course +gboolean config_edge_enabled[OB_NUM_EDGES] = {1, 1, 1, 1, 1, 1, 1, 1}; + +#ifdef DEBUG +#define EDGE_WIDTH 10 +#define CORNER_SIZE 20 +#else +#define EDGE_WIDTH 1 +#define CORNER_SIZE 2 +#endif +static void get_position(ObEdgeLocation edge, Rect screen, Rect *rect) +{ + switch (edge) { + case OB_EDGE_TOP: + RECT_SET(*rect, CORNER_SIZE, 0, + screen.width - 2 * CORNER_SIZE, EDGE_WIDTH); + break; + case OB_EDGE_TOPRIGHT: + RECT_SET(*rect, screen.width - CORNER_SIZE, 0, + CORNER_SIZE, CORNER_SIZE); + break; + case OB_EDGE_RIGHT: + RECT_SET(*rect, screen.width - EDGE_WIDTH, CORNER_SIZE, + EDGE_WIDTH, screen.height - 2 * CORNER_SIZE); + break; + case OB_EDGE_BOTTOMRIGHT: + RECT_SET(*rect, screen.width - CORNER_SIZE, + screen.height - CORNER_SIZE, + CORNER_SIZE, CORNER_SIZE); + break; + case OB_EDGE_BOTTOM: + RECT_SET(*rect, CORNER_SIZE, screen.height - EDGE_WIDTH, + screen.width - 2 * CORNER_SIZE, EDGE_WIDTH); + break; + case OB_EDGE_BOTTOMLEFT: + RECT_SET(*rect, 0, screen.height - CORNER_SIZE, + CORNER_SIZE, CORNER_SIZE); + break; + case OB_EDGE_LEFT: + RECT_SET(*rect, 0, CORNER_SIZE, + EDGE_WIDTH, screen.height - 2 * CORNER_SIZE); + break; + case OB_EDGE_TOPLEFT: + RECT_SET(*rect, 0, 0, CORNER_SIZE, CORNER_SIZE); + break; + } +} + +void edges_startup(gboolean reconfigure) +{ + ObEdgeLocation i; + Rect r; + XSetWindowAttributes xswa; + const Rect *screen = screen_physical_area_all_monitors(); + + xswa.override_redirect = True; + + for (i=0; i < OB_NUM_EDGES; i++) { + if (!config_edge_enabled[i]) + continue; + + edge[i] = g_new(ObEdge, 1); + edge[i]->obwin.type = OB_WINDOW_CLASS_EDGE; + edge[i]->location = i; + + get_position(i, *screen, &r); + edge[i]->win = XCreateWindow(obt_display, obt_root(ob_screen), + r.x, r.y, r.width, r.height, 0, 0, InputOnly, + CopyFromParent, CWOverrideRedirect, &xswa); + XSelectInput(obt_display, edge[i]->win, ButtonPressMask | ButtonReleaseMask + | EnterWindowMask | LeaveWindowMask); + XMapWindow(obt_display, edge[i]->win); + + stacking_add(EDGE_AS_WINDOW(edge[i])); + window_add(&edge[i]->win, EDGE_AS_WINDOW(edge[i])); + +#ifdef DEBUG + ob_debug("mapped edge window %i at %03i %03i %02i %02i", i, r.x, r.y, r.width, r.height); +#endif + } + + XFlush(obt_display); +} + +void edges_shutdown(gboolean reconfigure) +{ + gint i; + + for (i=0; i < OB_NUM_EDGES; i++) { + window_remove(edge[i]->win); + stacking_remove(EDGE_AS_WINDOW(edge[i])); + XDestroyWindow(obt_display, edge[i]->win); + g_free(edge[i]); + } +} diff --git a/openbox/edges.h b/openbox/edges.h new file mode 100644 index 00000000..46484044 --- /dev/null +++ b/openbox/edges.h @@ -0,0 +1,31 @@ +#ifndef __edges_h +#define __edges_h + +#include "window.h" + +typedef enum +{ + OB_EDGE_TOP, + OB_EDGE_TOPRIGHT, + OB_EDGE_RIGHT, + OB_EDGE_BOTTOMRIGHT, + OB_EDGE_BOTTOM, + OB_EDGE_BOTTOMLEFT, + OB_EDGE_LEFT, + OB_EDGE_TOPLEFT, + OB_NUM_EDGES +} ObEdgeLocation; + +typedef struct _ObEdge ObEdge; + +struct _ObEdge +{ + ObWindow obwin; + Window win; + ObEdgeLocation location; +}; + +void edges_startup(gboolean reconfigure); +void edges_shutdown(gboolean reconfigure); + +#endif diff --git a/openbox/event.c b/openbox/event.c index 243f2078..59fc21c7 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -30,6 +30,7 @@ #include "grab.h" #include "menu.h" #include "prompt.h" +#include "edges.h" #include "menuframe.h" #include "keyboard.h" #include "mouse.h" @@ -480,9 +481,6 @@ static void event_process(const XEvent *ec, gpointer data) case OB_WINDOW_CLASS_MENUFRAME: menu = WINDOW_AS_MENUFRAME(obwin); break; - case OB_WINDOW_CLASS_INTERNAL: - /* we don't do anything with events directly on these windows */ - break; case OB_WINDOW_CLASS_PROMPT: prompt = WINDOW_AS_PROMPT(obwin); break; @@ -711,7 +709,7 @@ static void event_process(const XEvent *ec, gpointer data) /* ...or it if it was physically on an openbox internal window... */ ((w = window_find(e->xbutton.subwindow)) && - (WINDOW_IS_INTERNAL(w) || WINDOW_IS_DOCK(w)))) + (WINDOW_IS_INTERNAL(w) || WINDOW_IS_DOCK(w) || WINDOW_IS_EDGE(w)))) /* ...then process the event, otherwise ignore it */ { used = event_handle_user_input(client, e); diff --git a/openbox/frame.c b/openbox/frame.c index 3dbcf126..2e36dd62 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -28,6 +28,7 @@ #include "focus_cycle_indicator.h" #include "moveresize.h" #include "screen.h" +#include "edges.h" #include "obrender/theme.h" #include "obt/display.h" #include "obt/xqueue.h" @@ -1386,6 +1387,22 @@ ObFrameContext frame_context_from_string(const gchar *name) return OB_FRAME_CONTEXT_MOVE_RESIZE; else if (!g_ascii_strcasecmp("Dock", name)) return OB_FRAME_CONTEXT_DOCK; + else if (!g_ascii_strcasecmp("ScreenTop", name)) + return OB_FRAME_CONTEXT_EDGE_TOP; + else if (!g_ascii_strcasecmp("ScreenTopRight", name)) + return OB_FRAME_CONTEXT_EDGE_TOPRIGHT; + else if (!g_ascii_strcasecmp("ScreenRight", name)) + return OB_FRAME_CONTEXT_EDGE_RIGHT; + else if (!g_ascii_strcasecmp("ScreenBottomRight", name)) + return OB_FRAME_CONTEXT_EDGE_BOTTOMRIGHT; + else if (!g_ascii_strcasecmp("ScreenBottom", name)) + return OB_FRAME_CONTEXT_EDGE_BOTTOM; + else if (!g_ascii_strcasecmp("ScreenBottomLeft", name)) + return OB_FRAME_CONTEXT_EDGE_BOTTOMLEFT; + else if (!g_ascii_strcasecmp("ScreenLeft", name)) + return OB_FRAME_CONTEXT_EDGE_LEFT; + else if (!g_ascii_strcasecmp("ScreenTopLeft", name)) + return OB_FRAME_CONTEXT_EDGE_TOPLEFT; return OB_FRAME_CONTEXT_NONE; } @@ -1397,12 +1414,14 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) if (moveresize_in_progress) return OB_FRAME_CONTEXT_MOVE_RESIZE; - if (win == obt_root(ob_screen)) return OB_FRAME_CONTEXT_ROOT; if ((obwin = window_find(win))) { if (WINDOW_IS_DOCK(obwin)) { return OB_FRAME_CONTEXT_DOCK; + } else if (WINDOW_IS_EDGE(obwin)) { + ObEdge *edge = (ObEdge *)obwin; + return OB_FRAME_CONTEXT_EDGE_TOP + edge->location; } } if (client == NULL) return OB_FRAME_CONTEXT_NONE; diff --git a/openbox/frame.h b/openbox/frame.h index 915c08db..275faa74 100644 --- a/openbox/frame.h +++ b/openbox/frame.h @@ -54,6 +54,14 @@ typedef enum { a move/resize */ OB_FRAME_CONTEXT_MOVE_RESIZE, OB_FRAME_CONTEXT_DOCK, + OB_FRAME_CONTEXT_EDGE_TOP, + OB_FRAME_CONTEXT_EDGE_TOPRIGHT, + OB_FRAME_CONTEXT_EDGE_RIGHT, + OB_FRAME_CONTEXT_EDGE_BOTTOMRIGHT, + OB_FRAME_CONTEXT_EDGE_BOTTOM, + OB_FRAME_CONTEXT_EDGE_BOTTOMLEFT, + OB_FRAME_CONTEXT_EDGE_LEFT, + OB_FRAME_CONTEXT_EDGE_TOPLEFT, OB_FRAME_NUM_CONTEXTS } ObFrameContext; diff --git a/openbox/openbox.c b/openbox/openbox.c index cba04995..f901435f 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -21,6 +21,7 @@ #include "openbox.h" #include "session.h" #include "dock.h" +#include "edges.h" #include "event.h" #include "menu.h" #include "client.h" @@ -327,6 +328,7 @@ gint main(gint argc, gchar **argv) mouse_startup(reconfigure); menu_frame_startup(reconfigure); menu_startup(reconfigure); + edges_startup(reconfigure); prompt_startup(reconfigure); /* do this after everything is started so no events will get @@ -392,6 +394,7 @@ gint main(gint argc, gchar **argv) window_unmanage_all(); prompt_shutdown(reconfigure); + edges_shutdown(reconfigure); menu_shutdown(reconfigure); menu_frame_shutdown(reconfigure); mouse_shutdown(reconfigure); diff --git a/openbox/window.h b/openbox/window.h index 24a7d07b..c1402bcf 100644 --- a/openbox/window.h +++ b/openbox/window.h @@ -32,7 +32,8 @@ typedef enum { OB_WINDOW_CLASS_DOCK, OB_WINDOW_CLASS_CLIENT, OB_WINDOW_CLASS_INTERNAL, - OB_WINDOW_CLASS_PROMPT + OB_WINDOW_CLASS_PROMPT, + OB_WINDOW_CLASS_EDGE } ObWindowClass; /* In order to be an ObWindow, you need to make this struct the top of your @@ -51,6 +52,8 @@ struct _ObWindow { (((ObWindow*)win)->type == OB_WINDOW_CLASS_INTERNAL) #define WINDOW_IS_PROMPT(win) \ (((ObWindow*)win)->type == OB_WINDOW_CLASS_PROMPT) +#define WINDOW_IS_EDGE(win) \ + (((ObWindow*)win)->type == OB_WINDOW_CLASS_EDGE) struct _ObMenu; struct _ObDock; @@ -63,12 +66,14 @@ struct _ObPrompt; #define WINDOW_AS_CLIENT(win) ((struct _ObClient*)win) #define WINDOW_AS_INTERNAL(win) ((struct _ObInternalWindow*)win) #define WINDOW_AS_PROMPT(win) ((struct _ObPrompt*)win) +#define WINDOW_AS_EDGE(win) ((struct _ObEdge*)win) #define MENUFRAME_AS_WINDOW(menu) ((ObWindow*)menu) #define DOCK_AS_WINDOW(dock) ((ObWindow*)dock) #define CLIENT_AS_WINDOW(client) ((ObWindow*)client) #define INTERNAL_AS_WINDOW(intern) ((ObWindow*)intern) #define PROMPT_AS_WINDOW(prompt) ((ObWindow*)prompt) +#define EDGE_AS_WINDOW(edge) ((ObWindow*)edge) void window_startup (gboolean reconfig); void window_shutdown(gboolean reconfig); -- 2.34.1