mouse and key bindings plugins work. segfault somewhere still on shutdown
This commit is contained in:
parent
51b93d9c4c
commit
4bcd03b2d0
15 changed files with 782 additions and 208 deletions
190
openbox/action.c
190
openbox/action.c
|
@ -1,172 +1,205 @@
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "stacking.h"
|
#include "stacking.h"
|
||||||
|
#include "frame.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "action.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
void action_execute(char *path)
|
Action *action_new(void (*func)(union ActionData *data))
|
||||||
|
{
|
||||||
|
Action *a = g_new(Action, 1);
|
||||||
|
a->func = func;
|
||||||
|
|
||||||
|
/* deal with pointers */
|
||||||
|
if (func == action_execute)
|
||||||
|
a->data.execute.path = NULL;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_free(Action *a)
|
||||||
|
{
|
||||||
|
/* deal with pointers */
|
||||||
|
if (a->func == action_execute)
|
||||||
|
g_free(a->data.execute.path);
|
||||||
|
|
||||||
|
g_free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_execute(union ActionData *data)
|
||||||
{
|
{
|
||||||
GError *e;
|
GError *e;
|
||||||
if (!g_spawn_command_line_async(path, &e)) {
|
if (!g_spawn_command_line_async(data->execute.path, &e)) {
|
||||||
g_warning("failed to execute '%s': %s", path, e->message);
|
g_warning("failed to execute '%s': %s",
|
||||||
|
data->execute.path, e->message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_iconify(Client *c)
|
void action_iconify(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_iconify(c, TRUE, TRUE);
|
client_iconify(data->client.c, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_raise(Client *c)
|
void action_raise(union ActionData *data)
|
||||||
{
|
{
|
||||||
stacking_raise(c);
|
stacking_raise(data->client.c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_lower(Client *c)
|
void action_lower(union ActionData *data)
|
||||||
{
|
{
|
||||||
stacking_lower(c);
|
stacking_lower(data->client.c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_close(Client *c)
|
void action_close(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_close(c);
|
client_close(data->client.c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_shade(Client *c)
|
void action_shade(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_shade(c, TRUE);
|
client_shade(data->client.c, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_unshade(Client *c)
|
void action_unshade(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_shade(c, FALSE);
|
client_shade(data->client.c, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_shade(Client *c)
|
void action_toggle_shade(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_shade(c, !c->shaded);
|
client_shade(data->client.c, !data->client.c->shaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_omnipresent(Client *c)
|
void action_toggle_omnipresent(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_set_desktop(c, c->desktop == DESKTOP_ALL ?
|
client_set_desktop(data->client.c, data->client.c->desktop == DESKTOP_ALL ?
|
||||||
screen_desktop : DESKTOP_ALL);
|
screen_desktop : DESKTOP_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_move_relative(Client *c, int dx, int dy)
|
void action_move_relative(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_configure(c, Corner_TopLeft, c->area.x + dx, c->area.y + dy,
|
Client *c = data->relative.c;
|
||||||
|
client_configure(c, Corner_TopLeft,
|
||||||
|
c->area.x + data->relative.dx,
|
||||||
|
c->area.y + data->relative.dy,
|
||||||
c->area.width, c->area.height, TRUE, TRUE);
|
c->area.width, c->area.height, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_resize_relative(Client *c, int dx, int dy)
|
void action_resize_relative(union ActionData *data)
|
||||||
{
|
{
|
||||||
|
Client *c = data->relative.c;
|
||||||
client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
|
client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
|
||||||
c->area.width + dx, c->area.height + dy, TRUE, TRUE);
|
c->area.width + data->relative.dx,
|
||||||
|
c->area.height + data->relative.dy, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_maximize_full(Client *c)
|
void action_maximize_full(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, TRUE, 0, TRUE);
|
client_maximize(data->client.c, TRUE, 0, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_unmaximize_full(Client *c)
|
void action_unmaximize_full(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, FALSE, 0, TRUE);
|
client_maximize(data->client.c, FALSE, 0, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_maximize_full(Client *c)
|
void action_toggle_maximize_full(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, !(c->max_horz || c->max_vert), 0, TRUE);
|
client_maximize(data->client.c,
|
||||||
|
!(data->client.c->max_horz || data->client.c->max_vert),
|
||||||
|
0, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_maximize_horz(Client *c)
|
void action_maximize_horz(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, TRUE, 1, TRUE);
|
client_maximize(data->client.c, TRUE, 1, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_unmaximize_horz(Client *c)
|
void action_unmaximize_horz(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, FALSE, 1, TRUE);
|
client_maximize(data->client.c, FALSE, 1, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_maximize_horz(Client *c)
|
void action_toggle_maximize_horz(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, !c->max_horz, 1, TRUE);
|
client_maximize(data->client.c, !data->client.c->max_horz, 1, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_maximize_vert(Client *c)
|
void action_maximize_vert(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, TRUE, 2, TRUE);
|
client_maximize(data->client.c, TRUE, 2, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_unmaximize_vert(Client *c)
|
void action_unmaximize_vert(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, FALSE, 2, TRUE);
|
client_maximize(data->client.c, FALSE, 2, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_maximize_vert(Client *c)
|
void action_toggle_maximize_vert(union ActionData *data)
|
||||||
{
|
{
|
||||||
client_maximize(c, !c->max_vert, 2, TRUE);
|
client_maximize(data->client.c, !data->client.c->max_vert, 2, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_send_to_desktop(Client *c, guint desktop)
|
void action_send_to_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
|
if (data->sendto.desktop < screen_num_desktops ||
|
||||||
client_set_desktop(c, desktop);
|
data->sendto.desktop == DESKTOP_ALL)
|
||||||
|
client_set_desktop(data->sendto.c, data->sendto.desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow)
|
void action_send_to_next_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint d;
|
guint d;
|
||||||
|
|
||||||
d = screen_desktop + 1;
|
d = screen_desktop + 1;
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->sendtonextprev.wrap) return;
|
||||||
d = 0;
|
d = 0;
|
||||||
}
|
}
|
||||||
client_set_desktop(c, d);
|
client_set_desktop(data->sendtonextprev.c, d);
|
||||||
if (follow) screen_set_desktop(d);
|
if (data->sendtonextprev.follow) screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_send_to_previous_desktop(Client *c, gboolean wrap, gboolean follow)
|
void action_send_to_previous_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint d;
|
guint d;
|
||||||
|
|
||||||
d = screen_desktop - 1;
|
d = screen_desktop - 1;
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->sendtonextprev.wrap) return;
|
||||||
d = screen_num_desktops - 1;
|
d = screen_num_desktops - 1;
|
||||||
}
|
}
|
||||||
client_set_desktop(c, d);
|
client_set_desktop(data->sendtonextprev.c, d);
|
||||||
if (follow) screen_set_desktop(d);
|
if (data->sendtonextprev.follow) screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_desktop(guint desktop)
|
void action_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
|
if (data->desktop.desk < screen_num_desktops ||
|
||||||
screen_set_desktop(desktop);
|
data->desktop.desk == DESKTOP_ALL)
|
||||||
|
screen_set_desktop(data->desktop.desk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_next_desktop(gboolean wrap)
|
void action_next_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint d;
|
guint d;
|
||||||
|
|
||||||
d = screen_desktop + 1;
|
d = screen_desktop + 1;
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
d = 0;
|
d = 0;
|
||||||
}
|
}
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_previous_desktop(gboolean wrap)
|
void action_previous_desktop(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint d;
|
guint d;
|
||||||
|
|
||||||
d = screen_desktop - 1;
|
d = screen_desktop - 1;
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
d = screen_num_desktops - 1;
|
d = screen_num_desktops - 1;
|
||||||
}
|
}
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
|
@ -267,7 +300,7 @@ static guint translate_row_col(guint r, guint c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_next_desktop_column(gboolean wrap)
|
void action_next_desktop_column(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint r, c, d;
|
guint r, c, d;
|
||||||
|
|
||||||
|
@ -275,7 +308,7 @@ void action_next_desktop_column(gboolean wrap)
|
||||||
++c;
|
++c;
|
||||||
d = translate_row_col(r, c);
|
d = translate_row_col(r, c);
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
c = 0;
|
c = 0;
|
||||||
}
|
}
|
||||||
if (d >= screen_num_desktops)
|
if (d >= screen_num_desktops)
|
||||||
|
@ -285,7 +318,7 @@ void action_next_desktop_column(gboolean wrap)
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_previous_desktop_column(gboolean wrap)
|
void action_previous_desktop_column(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint r, c, d;
|
guint r, c, d;
|
||||||
|
|
||||||
|
@ -293,7 +326,7 @@ void action_previous_desktop_column(gboolean wrap)
|
||||||
--c;
|
--c;
|
||||||
d = translate_row_col(r, c);
|
d = translate_row_col(r, c);
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
c = screen_desktop_layout.columns - 1;
|
c = screen_desktop_layout.columns - 1;
|
||||||
}
|
}
|
||||||
if (d >= screen_num_desktops)
|
if (d >= screen_num_desktops)
|
||||||
|
@ -303,7 +336,7 @@ void action_previous_desktop_column(gboolean wrap)
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_next_desktop_row(gboolean wrap)
|
void action_next_desktop_row(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint r, c, d;
|
guint r, c, d;
|
||||||
|
|
||||||
|
@ -311,7 +344,7 @@ void action_next_desktop_row(gboolean wrap)
|
||||||
++r;
|
++r;
|
||||||
d = translate_row_col(r, c);
|
d = translate_row_col(r, c);
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
if (d >= screen_num_desktops)
|
if (d >= screen_num_desktops)
|
||||||
|
@ -321,7 +354,7 @@ void action_next_desktop_row(gboolean wrap)
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_previous_desktop_row(gboolean wrap)
|
void action_previous_desktop_row(union ActionData *data)
|
||||||
{
|
{
|
||||||
guint r, c, d;
|
guint r, c, d;
|
||||||
|
|
||||||
|
@ -329,7 +362,7 @@ void action_previous_desktop_row(gboolean wrap)
|
||||||
--r;
|
--r;
|
||||||
d = translate_row_col(r, c);
|
d = translate_row_col(r, c);
|
||||||
if (d >= screen_num_desktops) {
|
if (d >= screen_num_desktops) {
|
||||||
if (!wrap) return;
|
if (!data->nextprevdesktop.wrap) return;
|
||||||
c = screen_desktop_layout.rows - 1;
|
c = screen_desktop_layout.rows - 1;
|
||||||
}
|
}
|
||||||
if (d >= screen_num_desktops)
|
if (d >= screen_num_desktops)
|
||||||
|
@ -339,8 +372,29 @@ void action_previous_desktop_row(gboolean wrap)
|
||||||
screen_set_desktop(d);
|
screen_set_desktop(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void action_toggle_decorations(Client *c)
|
void action_toggle_decorations(union ActionData *data)
|
||||||
{
|
{
|
||||||
|
Client *c = data->client.c;
|
||||||
c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
|
c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
|
||||||
client_setup_decor_and_functions(c);
|
client_setup_decor_and_functions(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void action_move(union ActionData *data)
|
||||||
|
{
|
||||||
|
Client *c = data->move.c;
|
||||||
|
int x = data->move.x;
|
||||||
|
int y = data->move.y;
|
||||||
|
|
||||||
|
client_configure(c, Corner_TopLeft, x, y, c->area.width, c->area.height,
|
||||||
|
TRUE, data->move.final);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_resize(union ActionData *data)
|
||||||
|
{
|
||||||
|
Client *c = data->resize.c;
|
||||||
|
int w = data->resize.x - c->frame->size.left - c->frame->size.right;
|
||||||
|
int h = data->resize.y - c->frame->size.top - c->frame->size.bottom;
|
||||||
|
|
||||||
|
client_configure(c, data->resize.corner, c->area.x, c->area.y, w, h,
|
||||||
|
TRUE, data->resize.final);
|
||||||
|
}
|
||||||
|
|
211
openbox/action.h
211
openbox/action.h
|
@ -3,70 +3,155 @@
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|
||||||
typedef enum {
|
/* These have to all have a Client* at the top even if they don't use it, so
|
||||||
Action_Execute,
|
that I can set it blindly later on. So every function will have a Client*
|
||||||
Action_Iconify,
|
available (possibly NULL though) if it wants it.
|
||||||
Action_Raise,
|
*/
|
||||||
Action_Lower,
|
|
||||||
Action_Close,
|
struct AnyAction {
|
||||||
Action_Shade,
|
Client *c;
|
||||||
Action_Unshade,
|
};
|
||||||
Action_ToggleShade,
|
|
||||||
Action_ToggleOmnipresent,
|
struct Execute {
|
||||||
Action_MoveRelative,
|
Client *c;
|
||||||
Action_ResizeRelative,
|
char *path;
|
||||||
Action_MaximizeFull,
|
};
|
||||||
Action_UnmaximizeFull,
|
|
||||||
Action_ToggleMaximizeFull,
|
struct ClientAction {
|
||||||
Action_MaximizeHorz,
|
Client *c;
|
||||||
Action_UnmaximizeHorz,
|
};
|
||||||
Action_ToggleMaximizeHorz,
|
|
||||||
Action_MaximizeVert,
|
struct MoveResizeRelative {
|
||||||
Action_UnmaximizeVert,
|
Client *c;
|
||||||
Action_ToggleMaximizeVert,
|
int dx;
|
||||||
Action_SendToDesktop,
|
int dy;
|
||||||
Action_SendToNextDesktop,
|
};
|
||||||
Action_SendToPreviousDesktop,
|
|
||||||
Action_Desktop,
|
struct SendToDesktop {
|
||||||
Action_NextDesktop,
|
Client *c;
|
||||||
Action_PreviousDesktop,
|
guint desktop;
|
||||||
Action_NextDesktopColumn,
|
};
|
||||||
Action_PreviousDesktopColumn,
|
|
||||||
Action_NextDesktopRow,
|
struct SendToNextPreviousDesktop {
|
||||||
Action_PreviousDesktopRow,
|
Client *c;
|
||||||
Action_ToggleDecorations
|
gboolean wrap;
|
||||||
|
gboolean follow;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Desktop {
|
||||||
|
Client *c;
|
||||||
|
guint desk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NextPreviousDesktop {
|
||||||
|
Client *c;
|
||||||
|
gboolean wrap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Move {
|
||||||
|
Client *c;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
gboolean final;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Resize {
|
||||||
|
Client *c;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
gboolean final;
|
||||||
|
Corner corner;
|
||||||
|
};
|
||||||
|
|
||||||
|
union ActionData {
|
||||||
|
struct AnyAction any;
|
||||||
|
struct Execute execute;
|
||||||
|
struct ClientAction client;
|
||||||
|
struct MoveResizeRelative relative;
|
||||||
|
struct SendToDesktop sendto;
|
||||||
|
struct SendToNextPreviousDesktop sendtonextprev;
|
||||||
|
struct Desktop desktop;
|
||||||
|
struct NextPreviousDesktop nextprevdesktop;
|
||||||
|
struct Move move;
|
||||||
|
struct Resize resize;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* The func member acts like an enum to tell which one of the structs in
|
||||||
|
the data union are valid.
|
||||||
|
*/
|
||||||
|
void (*func)(union ActionData *data);
|
||||||
|
union ActionData data;
|
||||||
} Action;
|
} Action;
|
||||||
|
|
||||||
void action_execute(char *path);
|
Action *action_new(void (*func)(union ActionData *data));
|
||||||
void action_iconify(Client *c);
|
void action_free(Action *a);
|
||||||
void action_raise(Client *c);
|
|
||||||
void action_lower(Client *c);
|
/* Execute */
|
||||||
void action_close(Client *c);
|
void action_execute(union ActionData *data);
|
||||||
void action_shade(Client *c);
|
/* ClientAction */
|
||||||
void action_unshade(Client *c);
|
void action_iconify(union ActionData *data);
|
||||||
void action_toggle_shade(Client *c);
|
/* ClientAction */
|
||||||
void action_toggle_omnipresent(Client *c);
|
void action_raise(union ActionData *data);
|
||||||
void action_move_relative(Client *c, int dx, int dy);
|
/* ClientAction */
|
||||||
void action_resize_relative(Client *c, int dx, int dy);
|
void action_lower(union ActionData *data);
|
||||||
void action_maximize_full(Client *c);
|
/* ClientAction */
|
||||||
void action_unmaximize_full(Client *c);
|
void action_close(union ActionData *data);
|
||||||
void action_toggle_maximize_full(Client *c);
|
/* ClientAction */
|
||||||
void action_maximize_horz(Client *c);
|
void action_shade(union ActionData *data);
|
||||||
void action_unmaximize_horz(Client *c);
|
/* ClientAction */
|
||||||
void action_toggle_maximize_horz(Client *c);
|
void action_unshade(union ActionData *data);
|
||||||
void action_maximize_vert(Client *c);
|
/* ClientAction */
|
||||||
void action_unmaximize_vert(Client *c);
|
void action_toggle_shade(union ActionData *data);
|
||||||
void action_toggle_maximize_vert(Client *c);
|
/* ClientAction */
|
||||||
void action_send_to_desktop(Client *c, guint desktop);
|
void action_toggle_omnipresent(union ActionData *data);
|
||||||
void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow);
|
/* MoveResizeRelative */
|
||||||
void action_send_to_previous_desktop(Client *c, gboolean wrap,gboolean follow);
|
void action_move_relative(union ActionData *data);
|
||||||
void action_desktop(guint desktop);
|
/* MoveResizeRelative */
|
||||||
void action_next_desktop(gboolean wrap);
|
void action_resize_relative(union ActionData *data);
|
||||||
void action_previous_desktop(gboolean wrap);
|
/* ClientAction */
|
||||||
void action_next_desktop_column(gboolean wrap);
|
void action_maximize_full(union ActionData *data);
|
||||||
void action_previous_desktop_column(gboolean wrap);
|
/* ClientAction */
|
||||||
void action_next_desktop_row(gboolean wrap);
|
void action_unmaximize_full(union ActionData *data);
|
||||||
void action_previous_desktop_row(gboolean wrap);
|
/* ClientAction */
|
||||||
void action_toggle_decorations(Client *c);
|
void action_toggle_maximize_full(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_maximize_horz(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_unmaximize_horz(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_toggle_maximize_horz(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_maximize_vert(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_unmaximize_vert(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_toggle_maximize_vert(union ActionData *data);
|
||||||
|
/* SendToDesktop */
|
||||||
|
void action_send_to_desktop(union ActionData *data);
|
||||||
|
/* SendToNextPreviousDesktop */
|
||||||
|
void action_send_to_next_desktop(union ActionData *data);
|
||||||
|
/* SendToNextPreviousDesktop */
|
||||||
|
void action_send_to_previous_desktop(union ActionData *data);
|
||||||
|
/* Desktop */
|
||||||
|
void action_desktop(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_next_desktop(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_previous_desktop(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_next_desktop_column(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_previous_desktop_column(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_next_desktop_row(union ActionData *data);
|
||||||
|
/* NextPreviousDesktop */
|
||||||
|
void action_previous_desktop_row(union ActionData *data);
|
||||||
|
/* ClientAction */
|
||||||
|
void action_toggle_decorations(union ActionData *data);
|
||||||
|
/* Move */
|
||||||
|
void action_move(union ActionData *data);
|
||||||
|
/* Resize */
|
||||||
|
void action_resize(union ActionData *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,7 +21,7 @@ void grab_pointer(gboolean grab, Cursor cur)
|
||||||
if (grab) {
|
if (grab) {
|
||||||
if (pgrabs++ == 0)
|
if (pgrabs++ == 0)
|
||||||
XGrabPointer(ob_display, ob_root, False, 0, GrabModeAsync,
|
XGrabPointer(ob_display, ob_root, False, 0, GrabModeAsync,
|
||||||
GrabModeSync, FALSE, cur, CurrentTime);
|
GrabModeAsync, FALSE, cur, CurrentTime);
|
||||||
} else if (pgrabs > 0) {
|
} else if (pgrabs > 0) {
|
||||||
if (--pgrabs == 0)
|
if (--pgrabs == 0)
|
||||||
XUngrabPointer(ob_display, CurrentTime);
|
XUngrabPointer(ob_display, CurrentTime);
|
||||||
|
|
|
@ -7,9 +7,9 @@ CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
|
||||||
plugin_LTLIBRARIES=keyboard.la
|
plugin_LTLIBRARIES=keyboard.la
|
||||||
|
|
||||||
keyboard_la_LDFLAGS=-module -avoid-version
|
keyboard_la_LDFLAGS=-module -avoid-version
|
||||||
keyboard_la_SOURCES=keyboard.c tree.c translate.c keyaction.c
|
keyboard_la_SOURCES=keyboard.c tree.c translate.c
|
||||||
|
|
||||||
noinst_HEADERS=keyboard.h tree.h translate.h keyaction.h
|
noinst_HEADERS=keyboard.h tree.h translate.h
|
||||||
|
|
||||||
MAINTAINERCLEANFILES= Makefile.in
|
MAINTAINERCLEANFILES= Makefile.in
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "../../kernel/action.h"
|
#include "../../kernel/action.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "keyaction.h"
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
KeyBindingTree *firstnode;
|
KeyBindingTree *firstnode;
|
||||||
|
@ -21,6 +20,7 @@ static void grab_keys(gboolean grab)
|
||||||
} else {
|
} else {
|
||||||
KeyBindingTree *p = firstnode;
|
KeyBindingTree *p = firstnode;
|
||||||
while (p) {
|
while (p) {
|
||||||
|
/* XXX grab all lock keys too */
|
||||||
XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
|
XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
|
||||||
GrabModeAsync, GrabModeSync);
|
GrabModeAsync, GrabModeSync);
|
||||||
p = p->next_sibling;
|
p = p->next_sibling;
|
||||||
|
@ -38,56 +38,43 @@ static void reset_chains()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearall()
|
static gboolean kbind(GList *keylist, Action *action)
|
||||||
{
|
|
||||||
grab_keys(FALSE);
|
|
||||||
tree_destroy(firstnode);
|
|
||||||
firstnode = NULL;
|
|
||||||
grab_keys(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean bind(GList *keylist, KeyAction *action)
|
|
||||||
{
|
{
|
||||||
KeyBindingTree *tree, *t;
|
KeyBindingTree *tree, *t;
|
||||||
gboolean conflict;
|
gboolean conflict;
|
||||||
|
|
||||||
|
g_assert(keylist != NULL);
|
||||||
|
g_assert(action != NULL);
|
||||||
|
|
||||||
if (!(tree = tree_build(keylist))) {
|
if (!(tree = tree_build(keylist))) {
|
||||||
g_warning("invalid binding");
|
g_warning("invalid binding");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if ((t = tree_find(tree, &conflict)) != NULL) {
|
||||||
t = tree_find(tree, &conflict);
|
|
||||||
if (conflict) {
|
|
||||||
g_warning("conflict with binding");
|
|
||||||
tree_destroy(tree);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (t != NULL) {
|
|
||||||
/* already bound to something */
|
/* already bound to something */
|
||||||
g_warning("keychain is already bound");
|
g_warning("keychain is already bound");
|
||||||
tree_destroy(tree);
|
tree_destroy(tree);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (conflict) {
|
||||||
|
g_warning("conflict with binding");
|
||||||
|
tree_destroy(tree);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* grab the server here to make sure no key pressed go missed */
|
/* grab the server here to make sure no key presses go missed */
|
||||||
grab_server(TRUE);
|
grab_server(TRUE);
|
||||||
|
|
||||||
grab_keys(FALSE);
|
grab_keys(FALSE);
|
||||||
|
|
||||||
/* set the function */
|
/* set the action */
|
||||||
t = tree;
|
t = tree;
|
||||||
while (t->first_child) t = t->first_child;
|
while (t->first_child) t = t->first_child;
|
||||||
t->action.action = action->action;
|
t->action = action;
|
||||||
t->action.type[0] = action->type[0];
|
/* assimilate this built tree into the main tree. assimilation
|
||||||
t->action.type[1] = action->type[1];
|
destroys/uses the tree */
|
||||||
t->action.data[0] = action->data[0];
|
tree_assimilate(tree);
|
||||||
t->action.data[1] = action->data[1];
|
|
||||||
|
|
||||||
/* assimilate this built tree into the main tree */
|
|
||||||
tree_assimilate(tree); /* assimilation destroys/uses the tree */
|
|
||||||
|
|
||||||
grab_keys(TRUE);
|
grab_keys(TRUE);
|
||||||
|
|
||||||
grab_server(FALSE);
|
grab_server(FALSE);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -117,7 +104,14 @@ static void press(ObEvent *e, void *foo)
|
||||||
}
|
}
|
||||||
curpos = p;
|
curpos = p;
|
||||||
} else {
|
} else {
|
||||||
keyaction_do(&p->action, focus_client);
|
if (p->action->func != NULL) {
|
||||||
|
p->action->data.any.c = focus_client;
|
||||||
|
|
||||||
|
g_assert(!(p->action->func == action_move ||
|
||||||
|
p->action->func == action_resize));
|
||||||
|
|
||||||
|
p->action->func(&p->action->data);
|
||||||
|
}
|
||||||
|
|
||||||
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
|
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
|
||||||
reset_chains();
|
reset_chains();
|
||||||
|
@ -132,49 +126,47 @@ static void press(ObEvent *e, void *foo)
|
||||||
static void binddef()
|
static void binddef()
|
||||||
{
|
{
|
||||||
GList *list = g_list_append(NULL, NULL);
|
GList *list = g_list_append(NULL, NULL);
|
||||||
KeyAction a;
|
Action *a;
|
||||||
|
|
||||||
|
/* When creating an Action struct, all of the data elements in the
|
||||||
|
appropriate struct need to be set, except the Client*, which will be set
|
||||||
|
at call-time when then action function is used.
|
||||||
|
*/
|
||||||
|
|
||||||
list->data = "C-Right";
|
list->data = "C-Right";
|
||||||
a.action = Action_NextDesktop;
|
a = action_new(action_next_desktop);
|
||||||
keyaction_set_bool(&a, 0, TRUE);
|
a->data.nextprevdesktop.wrap = TRUE;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-Left";
|
list->data = "C-Left";
|
||||||
a.action = Action_PreviousDesktop;
|
a = action_new(action_previous_desktop);
|
||||||
keyaction_set_bool(&a, 0, TRUE);
|
a->data.nextprevdesktop.wrap = TRUE;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-1";
|
list->data = "C-1";
|
||||||
a.action = Action_Desktop;
|
a = action_new(action_desktop);
|
||||||
keyaction_set_uint(&a, 0, 0);
|
a->data.desktop.desk = 0;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-2";
|
list->data = "C-2";
|
||||||
a.action = Action_Desktop;
|
a = action_new(action_desktop);
|
||||||
keyaction_set_uint(&a, 0, 1);
|
a->data.desktop.desk = 1;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-3";
|
list->data = "C-3";
|
||||||
a.action = Action_Desktop;
|
a = action_new(action_desktop);
|
||||||
keyaction_set_uint(&a, 0, 2);
|
a->data.desktop.desk = 2;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-4";
|
list->data = "C-4";
|
||||||
a.action = Action_Desktop;
|
a = action_new(action_desktop);
|
||||||
keyaction_set_uint(&a, 0, 3);
|
a->data.desktop.desk = 3;
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
|
|
||||||
list->data = "C-space";
|
list->data = "C-space";
|
||||||
a.action = Action_Execute;
|
a = action_new(action_execute);
|
||||||
keyaction_set_string(&a, 0, "xterm");
|
a->data.execute.path = g_strdup("xterm");
|
||||||
keyaction_set_none(&a, 1);
|
kbind(list, a);
|
||||||
bind(list, &a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_startup()
|
void plugin_startup()
|
||||||
|
@ -188,6 +180,10 @@ void plugin_startup()
|
||||||
void plugin_shutdown()
|
void plugin_shutdown()
|
||||||
{
|
{
|
||||||
dispatch_register(0, (EventHandler)press, NULL);
|
dispatch_register(0, (EventHandler)press, NULL);
|
||||||
clearall();
|
|
||||||
|
grab_keys(FALSE);
|
||||||
|
tree_destroy(firstnode);
|
||||||
|
firstnode = NULL;
|
||||||
|
grab_keys(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#ifndef __plugin_keyboard_keybaord_h
|
#ifndef __plugin_keyboard_keybaord_h
|
||||||
#define __plugin_keyboard_keybaord_h
|
#define __plugin_keyboard_keybaord_h
|
||||||
|
|
||||||
#include "keyaction.h"
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "../../kernel/action.h"
|
||||||
|
|
||||||
typedef struct KeyBindingTree {
|
typedef struct KeyBindingTree {
|
||||||
guint state;
|
guint state;
|
||||||
guint key;
|
guint key;
|
||||||
GList *keylist;
|
GList *keylist;
|
||||||
KeyAction action;
|
Action *action;
|
||||||
|
|
||||||
/* the next binding in the tree at the same level */
|
/* the next binding in the tree at the same level */
|
||||||
struct KeyBindingTree *next_sibling;
|
struct KeyBindingTree *next_sibling;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../../kernel/openbox.h"
|
#include "../../kernel/openbox.h"
|
||||||
#include "keyboard.h"
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
guint keyboard_translate_modifier(char *str)
|
static guint translate_modifier(char *str)
|
||||||
{
|
{
|
||||||
if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
|
if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
|
||||||
else if (!strcmp("Mod2", str)) return Mod2Mask;
|
else if (!strcmp("Mod2", str)) return Mod2Mask;
|
||||||
|
@ -36,7 +35,7 @@ gboolean translate_key(char *str, guint *state, guint *keycode)
|
||||||
/* figure out the mod mask */
|
/* figure out the mod mask */
|
||||||
*state = 0;
|
*state = 0;
|
||||||
for (i = 0; parsed[i] != l; ++i) {
|
for (i = 0; parsed[i] != l; ++i) {
|
||||||
guint m = keyboard_translate_modifier(parsed[i]);
|
guint m = translate_modifier(parsed[i]);
|
||||||
if (!m) goto translation_fail;
|
if (!m) goto translation_fail;
|
||||||
*state |= m;
|
*state |= m;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
guint translate_modifier(char *str);
|
|
||||||
gboolean translate_key(char *str, guint *state, guint *keycode);
|
gboolean translate_key(char *str, guint *state, guint *keycode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
#include "keyaction.h"
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
void tree_destroy(KeyBindingTree *tree)
|
void tree_destroy(KeyBindingTree *tree)
|
||||||
|
@ -15,7 +14,7 @@ void tree_destroy(KeyBindingTree *tree)
|
||||||
for (it = tree->keylist; it != NULL; it = it->next)
|
for (it = tree->keylist; it != NULL; it = it->next)
|
||||||
g_free(it->data);
|
g_free(it->data);
|
||||||
g_list_free(tree->keylist);
|
g_list_free(tree->keylist);
|
||||||
keyaction_free(&tree->action);
|
action_free(tree->action);
|
||||||
}
|
}
|
||||||
g_free(tree);
|
g_free(tree);
|
||||||
tree = c;
|
tree = c;
|
||||||
|
|
|
@ -4,3 +4,4 @@ Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
.libs
|
.libs
|
||||||
.deps
|
.deps
|
||||||
|
translate.lo
|
||||||
|
|
|
@ -7,9 +7,9 @@ CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
|
||||||
plugin_LTLIBRARIES=mouse.la
|
plugin_LTLIBRARIES=mouse.la
|
||||||
|
|
||||||
mouse_la_LDFLAGS=-module -avoid-version
|
mouse_la_LDFLAGS=-module -avoid-version
|
||||||
mouse_la_SOURCES=mouse.c
|
mouse_la_SOURCES=mouse.c translate.c
|
||||||
|
|
||||||
noinst_HEADERS=
|
noinst_HEADERS=mouse.h translate.h
|
||||||
|
|
||||||
MAINTAINERCLEANFILES= Makefile.in
|
MAINTAINERCLEANFILES= Makefile.in
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,385 @@
|
||||||
|
#include "../../kernel/openbox.h"
|
||||||
#include "../../kernel/dispatch.h"
|
#include "../../kernel/dispatch.h"
|
||||||
|
#include "../../kernel/action.h"
|
||||||
|
#include "../../kernel/client.h"
|
||||||
|
#include "../../kernel/frame.h"
|
||||||
|
#include "../../kernel/engine.h"
|
||||||
|
#include "translate.h"
|
||||||
|
#include "mouse.h"
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
void my_powerful_function() {}
|
/* GData of GSList*s of PointerBinding*s. */
|
||||||
|
static GData *bound_contexts;
|
||||||
|
|
||||||
|
struct foreach_grab_temp {
|
||||||
|
Client *client;
|
||||||
|
gboolean grab;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void grab_button(Client *client, guint state, guint button,
|
||||||
|
GQuark context, gboolean grab)
|
||||||
|
{
|
||||||
|
Window win;
|
||||||
|
int mode = GrabModeAsync;
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
if (context == g_quark_try_string("frame")) {
|
||||||
|
win = client->frame->window;
|
||||||
|
mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
|
||||||
|
} else if (context == g_quark_try_string("client")) {
|
||||||
|
win = client->frame->plate;
|
||||||
|
mode = GrabModeSync; /* this is handled in pointer_event */
|
||||||
|
mask = ButtonPressMask; /* can't catch more than this with Sync mode
|
||||||
|
the release event is manufactured in
|
||||||
|
pointer_fire */
|
||||||
|
} else return;
|
||||||
|
|
||||||
|
if (grab)
|
||||||
|
/* XXX grab all lock keys */
|
||||||
|
XGrabButton(ob_display, button, state, win, FALSE, mask, mode,
|
||||||
|
GrabModeAsync, None, None);
|
||||||
|
else
|
||||||
|
/* XXX ungrab all lock keys */
|
||||||
|
XUngrabButton(ob_display, button, state, win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void foreach_grab(GQuark key, gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
struct foreach_grab_temp *d = user_data;
|
||||||
|
GSList *it;
|
||||||
|
for (it = data; it != NULL; it = it->next) {
|
||||||
|
MouseBinding *b = it->data;
|
||||||
|
grab_button(d->client, b->state, b->button, key, d->grab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void grab_for_client(Client *client, gboolean grab)
|
||||||
|
{
|
||||||
|
struct foreach_grab_temp bt;
|
||||||
|
bt.client = client;
|
||||||
|
bt.grab = grab;
|
||||||
|
g_datalist_foreach(&bound_contexts, foreach_grab, &bt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void grab_all_clients(gboolean grab)
|
||||||
|
{
|
||||||
|
GSList *it;
|
||||||
|
|
||||||
|
for (it = client_list; it != NULL; it = it->next)
|
||||||
|
grab_for_client(it->data, grab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void foreach_clear(GQuark key, gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
GSList *it;
|
||||||
|
user_data = user_data;
|
||||||
|
for (it = data; it != NULL; it = it->next) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
MouseBinding *b = it->data;
|
||||||
|
for (i = 0; i < NUM_MOUSEACTION; ++i)
|
||||||
|
action_free(b->action[i]);
|
||||||
|
g_free(b);
|
||||||
|
}
|
||||||
|
g_slist_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fire_button(MouseAction a, GQuark context, Client *c, guint state,
|
||||||
|
guint button)
|
||||||
|
{
|
||||||
|
GSList *it;
|
||||||
|
MouseBinding *b;
|
||||||
|
|
||||||
|
for (it = g_datalist_id_get_data(&bound_contexts, context);
|
||||||
|
it != NULL; it = it->next) {
|
||||||
|
b = it->data;
|
||||||
|
if (b->state == state && b->button == button)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* if not bound, then nothing to do! */
|
||||||
|
if (it == NULL) return;
|
||||||
|
|
||||||
|
if (b->action[a] != NULL && b->action[a]->func != NULL) {
|
||||||
|
b->action[a]->data.any.c = c;
|
||||||
|
|
||||||
|
g_assert(!(b->action[a]->func == action_move ||
|
||||||
|
b->action[a]->func == action_resize));
|
||||||
|
|
||||||
|
b->action[a]->func(&b->action[a]->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* corner should be the opposite corner of the window in which the pointer
|
||||||
|
clicked, Corner_TopLeft if a good default if there is no client */
|
||||||
|
static void fire_motion(MouseAction a, GQuark context, Client *c, guint state,
|
||||||
|
guint button, int cx, int cy, int cw, int ch,
|
||||||
|
int dx, int dy, gboolean final, Corner corner)
|
||||||
|
{
|
||||||
|
GSList *it;
|
||||||
|
MouseBinding *b;
|
||||||
|
|
||||||
|
for (it = g_datalist_id_get_data(&bound_contexts, context);
|
||||||
|
it != NULL; it = it->next) {
|
||||||
|
b = it->data;
|
||||||
|
if (b->state == state && b->button == button)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* if not bound, then nothing to do! */
|
||||||
|
if (it == NULL) return;
|
||||||
|
|
||||||
|
if (b->action[a] != NULL && b->action[a]->func != NULL) {
|
||||||
|
b->action[a]->data.any.c = c;
|
||||||
|
|
||||||
|
if (b->action[a]->func == action_move) {
|
||||||
|
b->action[a]->data.move.x = cx + dx;
|
||||||
|
b->action[a]->data.move.y = cy + dy;
|
||||||
|
b->action[a]->data.move.final = final;
|
||||||
|
} else if (b->action[a]->func == action_resize) {
|
||||||
|
b->action[a]->data.resize.corner = corner;
|
||||||
|
switch (corner) {
|
||||||
|
case Corner_TopLeft:
|
||||||
|
b->action[a]->data.resize.x = cw + dx;
|
||||||
|
b->action[a]->data.resize.y = ch + dy;
|
||||||
|
break;
|
||||||
|
case Corner_TopRight:
|
||||||
|
b->action[a]->data.resize.x = cw - dx;
|
||||||
|
b->action[a]->data.resize.y = ch + dy;
|
||||||
|
break;
|
||||||
|
case Corner_BottomLeft:
|
||||||
|
b->action[a]->data.resize.x = cw + dx;
|
||||||
|
b->action[a]->data.resize.y = ch - dy;
|
||||||
|
break;
|
||||||
|
case Corner_BottomRight:
|
||||||
|
b->action[a]->data.resize.x = cw - dx;
|
||||||
|
b->action[a]->data.resize.y = ch - dy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b->action[a]->data.resize.final = final;
|
||||||
|
}
|
||||||
|
b->action[a]->func(&b->action[a]->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Corner pick_corner(int x, int y, int cx, int cy, int cw, int ch)
|
||||||
|
{
|
||||||
|
if (x - cx < cw / 2) {
|
||||||
|
if (y - cy < ch / 2)
|
||||||
|
return Corner_BottomRight;
|
||||||
|
else
|
||||||
|
return Corner_TopRight;
|
||||||
|
} else {
|
||||||
|
if (y - cy < ch / 2)
|
||||||
|
return Corner_BottomLeft;
|
||||||
|
else
|
||||||
|
return Corner_TopLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void event(ObEvent *e, void *foo)
|
static void event(ObEvent *e, void *foo)
|
||||||
{
|
{
|
||||||
|
static Time ltime;
|
||||||
|
static int px, py, cx, cy, cw, ch, dx, dy;
|
||||||
|
static guint button = 0, lbutton = 0;
|
||||||
|
static gboolean drag = FALSE;
|
||||||
|
static Corner corner = Corner_TopLeft;
|
||||||
|
gboolean click = FALSE;
|
||||||
|
gboolean dclick = FALSE;
|
||||||
|
|
||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
|
case Event_Client_Mapped:
|
||||||
|
grab_for_client(e->data.c.client, TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Event_Client_Destroy:
|
||||||
|
grab_for_client(e->data.c.client, FALSE);
|
||||||
|
break;
|
||||||
|
|
||||||
case Event_X_ButtonPress:
|
case Event_X_ButtonPress:
|
||||||
|
if (!button) {
|
||||||
|
if (e->data.x.client == NULL)
|
||||||
|
corner = Corner_TopLeft;
|
||||||
|
else {
|
||||||
|
cx = e->data.x.client->frame->area.x;
|
||||||
|
cy = e->data.x.client->frame->area.y;
|
||||||
|
cw = e->data.x.client->frame->area.width;
|
||||||
|
ch = e->data.x.client->frame->area.height;
|
||||||
|
px = e->data.x.e->xbutton.x_root;
|
||||||
|
py = e->data.x.e->xbutton.y_root;
|
||||||
|
corner = pick_corner(px, py, cx, cy, cw, ch);
|
||||||
|
button = e->data.x.e->xbutton.button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fire_button(MouseAction_Press,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xbutton.state,
|
||||||
|
e->data.x.e->xbutton.button);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Event_X_ButtonRelease:
|
case Event_X_ButtonRelease:
|
||||||
|
if (e->data.x.e->xbutton.button == button) {
|
||||||
|
/* end drags */
|
||||||
|
if (drag) {
|
||||||
|
fire_motion(MouseAction_Motion,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xbutton.state,
|
||||||
|
e->data.x.e->xbutton.button,
|
||||||
|
cx, cy, cw, ch, dx, dy, TRUE, corner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clicks are only valid if its released over the window */
|
||||||
|
if (e->data.x.e->xbutton.x >= 0 && e->data.x.e->xbutton.y >= 0) {
|
||||||
|
int junk;
|
||||||
|
Window wjunk;
|
||||||
|
guint ujunk, w, h;
|
||||||
|
XGetGeometry(ob_display, e->data.x.e->xbutton.window,
|
||||||
|
&wjunk, &junk, &junk, &w, &h, &ujunk, &ujunk);
|
||||||
|
if (e->data.x.e->xbutton.x < (signed)w &&
|
||||||
|
e->data.x.e->xbutton.y < (signed)h) {
|
||||||
|
click =TRUE;
|
||||||
|
/* double clicks happen if there were 2 in a row! */
|
||||||
|
if (lbutton == button &&
|
||||||
|
e->data.x.e->xbutton.time - 300 <= ltime)
|
||||||
|
dclick = TRUE;
|
||||||
|
}
|
||||||
|
lbutton = button;
|
||||||
|
} else
|
||||||
|
lbutton = 0;
|
||||||
|
|
||||||
|
button = 0;
|
||||||
|
ltime = e->data.x.e->xbutton.time;
|
||||||
|
}
|
||||||
|
fire_button(MouseAction_Press,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xbutton.state,
|
||||||
|
e->data.x.e->xbutton.button);
|
||||||
|
if (click)
|
||||||
|
fire_button(MouseAction_Click,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xbutton.state,
|
||||||
|
e->data.x.e->xbutton.button);
|
||||||
|
if (dclick)
|
||||||
|
fire_button(MouseAction_DClick,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xbutton.state,
|
||||||
|
e->data.x.e->xbutton.button);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Event_X_MotionNotify:
|
case Event_X_MotionNotify:
|
||||||
|
if (button) {
|
||||||
|
drag = TRUE;
|
||||||
|
dx = e->data.x.e->xmotion.x_root - px;
|
||||||
|
dy = e->data.x.e->xmotion.y_root - py;
|
||||||
|
fire_motion(MouseAction_Motion,
|
||||||
|
engine_get_context(e->data.x.client,
|
||||||
|
e->data.x.e->xbutton.window),
|
||||||
|
e->data.x.client, e->data.x.e->xmotion.state,
|
||||||
|
button, cx, cy, cw, ch, dx, dy, FALSE, corner);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact,
|
||||||
|
Action *action)
|
||||||
|
{
|
||||||
|
guint state, button;
|
||||||
|
GQuark context;
|
||||||
|
MouseBinding *b;
|
||||||
|
GSList *it;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (!translate_button(buttonstr, &state, &button)) {
|
||||||
|
g_warning("invalid button");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = g_quark_try_string(contextstr);
|
||||||
|
if (!context) {
|
||||||
|
g_warning("invalid context");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it = g_datalist_id_get_data(&bound_contexts, context);
|
||||||
|
it != NULL; it = it->next){
|
||||||
|
b = it->data;
|
||||||
|
if (b->state == state && b->button == button) {
|
||||||
|
/* already bound */
|
||||||
|
if (b->action[mact] != NULL) {
|
||||||
|
g_warning("duplicate binding");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
b->action[mact] = action;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grab_all_clients(FALSE);
|
||||||
|
|
||||||
|
/* add the binding */
|
||||||
|
b = g_new(MouseBinding, 1);
|
||||||
|
b->state = state;
|
||||||
|
b->button = button;
|
||||||
|
for (i = 0; i < NUM_MOUSEACTION; ++i)
|
||||||
|
if (i != mact)
|
||||||
|
b->action[i] = NULL;
|
||||||
|
b->action[mact] = action;
|
||||||
|
g_datalist_id_set_data(&bound_contexts, context,
|
||||||
|
g_slist_append(g_datalist_id_get_data(&bound_contexts, context), b));
|
||||||
|
|
||||||
|
grab_all_clients(TRUE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void binddef()
|
||||||
|
{
|
||||||
|
Action *a;
|
||||||
|
|
||||||
|
/* When creating an Action struct, all of the data elements in the
|
||||||
|
appropriate struct need to be set, except the Client*, which will be set
|
||||||
|
at call-time when then action function is used.
|
||||||
|
|
||||||
|
For action_move and action_resize, the 'x', 'y', and 'final' data
|
||||||
|
elements should not be set, as they are set at call-time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a = action_new(action_move);
|
||||||
|
mbind("1", "titlebar", MouseAction_Motion, a);
|
||||||
|
a = action_new(action_move);
|
||||||
|
mbind("1", "handle", MouseAction_Motion, a);
|
||||||
|
a = action_new(action_move);
|
||||||
|
mbind("A-1", "frame", MouseAction_Motion, a);
|
||||||
|
|
||||||
|
a = action_new(action_resize);
|
||||||
|
mbind("1", "blcorner", MouseAction_Motion, a);
|
||||||
|
a = action_new(action_resize);
|
||||||
|
mbind("1", "brcorner", MouseAction_Motion, a);
|
||||||
|
a = action_new(action_resize);
|
||||||
|
mbind("A-3", "frame", MouseAction_Motion, a);
|
||||||
|
}
|
||||||
|
|
||||||
void plugin_startup()
|
void plugin_startup()
|
||||||
{
|
{
|
||||||
dispatch_register(Event_X_ButtonPress | Event_X_ButtonRelease |
|
dispatch_register(Event_Client_Mapped | Event_Client_Destroy |
|
||||||
|
Event_X_ButtonPress | Event_X_ButtonRelease |
|
||||||
Event_X_MotionNotify, (EventHandler)event, NULL);
|
Event_X_MotionNotify, (EventHandler)event, NULL);
|
||||||
|
|
||||||
|
/* XXX parse a config */
|
||||||
|
binddef();
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_shutdown()
|
void plugin_shutdown()
|
||||||
{
|
{
|
||||||
dispatch_register(0, (EventHandler)event, NULL);
|
dispatch_register(0, (EventHandler)event, NULL);
|
||||||
|
|
||||||
|
grab_all_clients(FALSE);
|
||||||
|
g_datalist_foreach(&bound_contexts, foreach_clear, NULL);
|
||||||
}
|
}
|
||||||
|
|
21
plugins/mouse/mouse.h
Normal file
21
plugins/mouse/mouse.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef __plugin_mouse_mouse_h
|
||||||
|
#define __plugin_mouse_mouse_h
|
||||||
|
|
||||||
|
#include "../../kernel/action.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MouseAction_Press,
|
||||||
|
MouseAction_Release,
|
||||||
|
MouseAction_Click,
|
||||||
|
MouseAction_DClick,
|
||||||
|
MouseAction_Motion,
|
||||||
|
NUM_MOUSEACTION
|
||||||
|
} MouseAction;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint state;
|
||||||
|
guint button;
|
||||||
|
Action *action[NUM_MOUSEACTION];
|
||||||
|
} MouseBinding;
|
||||||
|
|
||||||
|
#endif
|
55
plugins/mouse/translate.c
Normal file
55
plugins/mouse/translate.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "../../kernel/openbox.h"
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static guint translate_modifier(char *str)
|
||||||
|
{
|
||||||
|
if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
|
||||||
|
else if (!strcmp("Mod2", str)) return Mod2Mask;
|
||||||
|
else if (!strcmp("Mod3", str)) return Mod3Mask;
|
||||||
|
else if (!strcmp("Mod4", str) || !strcmp("W", str)) return Mod4Mask;
|
||||||
|
else if (!strcmp("Mod5", str)) return Mod5Mask;
|
||||||
|
else if (!strcmp("C", str)) return ControlMask;
|
||||||
|
else if (!strcmp("S", str)) return ShiftMask;
|
||||||
|
g_warning("Invalid modifier '%s' in binding.", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean translate_button(char *str, guint *state, guint *button)
|
||||||
|
{
|
||||||
|
char **parsed;
|
||||||
|
char *l;
|
||||||
|
int i;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
parsed = g_strsplit(str, "-", -1);
|
||||||
|
|
||||||
|
/* first, find the button (last token) */
|
||||||
|
l = NULL;
|
||||||
|
for (i = 0; parsed[i] != NULL; ++i)
|
||||||
|
l = parsed[i];
|
||||||
|
if (l == NULL)
|
||||||
|
goto translation_fail;
|
||||||
|
|
||||||
|
/* figure out the mod mask */
|
||||||
|
*state = 0;
|
||||||
|
for (i = 0; parsed[i] != l; ++i) {
|
||||||
|
guint m = translate_modifier(parsed[i]);
|
||||||
|
if (!m) goto translation_fail;
|
||||||
|
*state |= m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* figure out the button */
|
||||||
|
*button = atoi(l);
|
||||||
|
if (!*button) {
|
||||||
|
g_warning("Invalid button '%s' in pointer binding.", l);
|
||||||
|
goto translation_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
translation_fail:
|
||||||
|
g_strfreev(parsed);
|
||||||
|
return ret;
|
||||||
|
}
|
8
plugins/mouse/translate.h
Normal file
8
plugins/mouse/translate.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef __plugin_mouse_translate_h
|
||||||
|
#define __plugin_mouse_translate_h
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
gboolean translate_button(char *str, guint *state, guint *keycode);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue