Guys,

I really miss a feature from other window managers, at least KWin and
WindowMaker, that is the option to move and resize windows using just
the keyboard. Basically you activate a shortcut to enter the "action
mode", in which you use the keyboard arrows to move or resize the
window and then you hit "Enter" to confirm or "Escape" to rollback, if
you wait some seconds it will also confirm, since it's not a dangerous
option, it is more intuitive (you don't even need to know you need to
confirm)... if you say "Oh, sh*t" then you usually hit Escape and
you'll learn it will rollback.

This is implemented in the attached patch. It's very rough and needs
some review, but it works nicely, except:
  - we'll have 2 items in the bindings for each action: "Move" and
"Move with keyboard", etc.
  - offsets are not configurable, they're fixed in 5px in each
direction for each operation;
  - timeout is not configurable, it's 5s;
  - no geometry window while moving or resizing windows.

The first point is really easy to remove, but then I guess it would
impact the mouse bindings, anyone with more experience in that can
confirm?

The second and third are easy to add, but maybe it's too much. I'll
add if required, but I want to avoid too much useless options going
in.

The last point I haven't looked at it, but I guess i can learn it from
existing code. hints are welcome, of course.

-- 
Gustavo Sverzut Barbieri
http://profusion.mobi embedded systems
--------------------------------------
MSN: [EMAIL PROTECTED]
Skype: gsbarbieri
Mobile: +55 (19) 9225-2202
Index: src/bin/e_border.c
===================================================================
--- src/bin/e_border.c	(revision 35979)
+++ src/bin/e_border.c	(working copy)
@@ -2607,7 +2607,215 @@
    return borders;
 }
 
+static Ecore_X_Window action_input_win = 0;
+static E_Border *action_border = NULL;
+static Ecore_Event_Handler *action_handler = NULL;
+static Ecore_Timer *action_timer = NULL;
+static Ecore_X_Rectangle action_orig;
+
+static int
+_e_border_action_input_win_del(void)
+{
+   if (!action_input_win)
+     return 0;
+
+   e_grabinput_release(action_input_win, action_input_win);
+   ecore_x_window_del(action_input_win);
+   action_input_win = 0;
+   return 1;
+}
+
+static int
+_e_border_action_input_win_new(E_Border *bd)
+{
+   if (!action_input_win)
+     {
+	Ecore_X_Window parent = bd->zone->container->win;
+	action_input_win = ecore_x_window_input_new(parent, 0, 0, 1, 1);
+	if (!action_input_win)
+	  return 0;
+     }
+
+   ecore_x_window_show(action_input_win);
+   if (e_grabinput_get(action_input_win, 0, action_input_win))
+     return 1;
+
+   _e_border_action_input_win_del();
+   return 0;
+}
+
+static int
+_e_border_action_finish(void)
+{
+   _e_border_action_input_win_del();
+
+   if (action_timer)
+     ecore_timer_del(action_timer);
+   action_timer = NULL;
+
+   if (action_handler)
+     ecore_event_handler_del(action_handler);
+   action_handler = NULL;
+
+   action_border = NULL;
+}
+
+static int
+_e_border_action_timeout(void *data)
+{
+   _e_border_action_finish();
+   return 0;
+}
+
+static void
+_e_border_action_timeout_add(void)
+{
+   if (action_timer)
+     ecore_timer_del(action_timer);
+   action_timer = ecore_timer_add(5.0, _e_border_action_timeout, NULL);
+}
+
+static void
+_e_border_action_init(E_Border *bd)
+{
+   action_orig.x = bd->x;
+   action_orig.y = bd->y;
+   action_orig.width = bd->w;
+   action_orig.height = bd->h;
+
+   action_border = bd;
+
+   _e_border_action_timeout_add();
+}
+
+static void
+_e_border_action_restore_orig(E_Border *bd)
+{
+   if (action_border != bd)
+     return;
+
+   e_border_move_resize(bd, action_orig.x, action_orig.y, action_orig.width, action_orig.height);
+}
+
+#define E_BORDER_MOVE_KEY_DX 5
+#define E_BORDER_MOVE_KEY_DY 5
+static int
+_e_border_move_key_down(void *data, int type, void *event)
+{
+   Ecore_X_Event_Key_Down *ev = event;
+   int x, y;
+
+   if (ev->event_win != action_input_win)
+     return 1;
+   if (!action_border)
+     {
+	fprintf(stderr, "ERROR: no action_border!\n");
+	goto stop;
+     }
+
+   x = action_border->x;
+   y = action_border->y;
+
+   if (strcmp(ev->keysymbol, "Up") == 0)
+     y -= E_BORDER_MOVE_KEY_DY;
+   else if (strcmp(ev->keysymbol, "Down") == 0)
+     y += E_BORDER_MOVE_KEY_DY;
+   else if (strcmp(ev->keysymbol, "Left") == 0)
+     x -= E_BORDER_MOVE_KEY_DX;
+   else if (strcmp(ev->keysymbol, "Right") == 0)
+     x += E_BORDER_MOVE_KEY_DX;
+   else if (strcmp(ev->keysymbol, "Return") == 0)
+     goto stop;
+   else if (strcmp(ev->keysymbol, "Escape") == 0)
+     {
+	_e_border_action_restore_orig(action_border);
+	goto stop;
+     }
+
+   e_border_move(action_border, x, y);
+   _e_border_action_timeout_add();
+
+   return 1;
+
+ stop:
+   _e_border_action_finish();
+   return 0;
+}
+
 EAPI void
+e_border_act_move_keyboard(E_Border *bd)
+{
+   if (!_e_border_action_input_win_new(bd))
+     return;
+
+   _e_border_action_init(bd);
+
+   if (action_handler)
+     ecore_event_handler_del(action_handler);
+   action_handler = ecore_event_handler_add(ECORE_X_EVENT_KEY_DOWN, _e_border_move_key_down, NULL);
+}
+
+#define E_BORDER_RESIZE_KEY_DX 5
+#define E_BORDER_RESIZE_KEY_DY 5
+static int
+_e_border_resize_key_down(void *data, int type, void *event)
+{
+   Ecore_X_Event_Key_Down *ev = event;
+   int w, h;
+
+   if (ev->event_win != action_input_win)
+     return 1;
+   if (!action_border)
+     {
+	fprintf(stderr, "ERROR: no action_border!\n");
+	goto stop;
+     }
+
+   w = action_border->w;
+   h = action_border->h;
+
+   if (strcmp(ev->keysymbol, "Up") == 0)
+     h -= E_BORDER_RESIZE_KEY_DY;
+   else if (strcmp(ev->keysymbol, "Down") == 0)
+     h += E_BORDER_RESIZE_KEY_DY;
+   else if (strcmp(ev->keysymbol, "Left") == 0)
+     w -= E_BORDER_RESIZE_KEY_DX;
+   else if (strcmp(ev->keysymbol, "Right") == 0)
+     w += E_BORDER_RESIZE_KEY_DX;
+   else if (strcmp(ev->keysymbol, "Return") == 0)
+     goto stop;
+   else if (strcmp(ev->keysymbol, "Escape") == 0)
+     {
+	_e_border_action_restore_orig(action_border);
+	goto stop;
+     }
+   else
+     goto stop;
+
+   e_border_resize(action_border, w, h);
+   _e_border_action_timeout_add();
+
+   return 1;
+
+ stop:
+   _e_border_action_finish();
+   return 0;
+}
+
+EAPI void
+e_border_act_resize_keyboard(E_Border *bd)
+{
+   if (!_e_border_action_input_win_new(bd))
+     return;
+
+   _e_border_action_init(bd);
+
+   if (action_handler)
+     ecore_event_handler_del(action_handler);
+   action_handler = ecore_event_handler_add(ECORE_X_EVENT_KEY_DOWN, _e_border_resize_key_down, NULL);
+}
+
+EAPI void
 e_border_act_move_begin(E_Border *bd, Ecore_X_Event_Mouse_Button_Down *ev)
 {
    E_OBJECT_CHECK(bd);
Index: src/bin/e_border.h
===================================================================
--- src/bin/e_border.h	(revision 35979)
+++ src/bin/e_border.h	(working copy)
@@ -598,6 +598,9 @@
 
 EAPI Evas_List *e_border_client_list(void);
 
+EAPI void e_border_act_move_keyboard(E_Border *bd);
+EAPI void e_border_act_resize_keyboard(E_Border *bd);
+
 EAPI void e_border_act_move_begin(E_Border *bd, Ecore_X_Event_Mouse_Button_Down *ev);
 EAPI void e_border_act_move_end(E_Border *bd, Ecore_X_Event_Mouse_Button_Up *ev);
 EAPI void e_border_act_resize_begin(E_Border *bd, Ecore_X_Event_Mouse_Button_Down *ev);
Index: src/bin/e_actions.c
===================================================================
--- src/bin/e_actions.c	(revision 35979)
+++ src/bin/e_actions.c	(working copy)
@@ -123,6 +123,19 @@
    e_border_act_move_end((E_Border *)obj, ev);
 }
 
+ACT_FN_GO(window_move_keyboard)
+{
+   if (!obj) obj = E_OBJECT(e_border_focused_get());
+   if (!obj) return;
+   if (obj->type != E_BORDER_TYPE)
+     {
+	obj = E_OBJECT(e_border_focused_get());
+	if (!obj) return;
+     }
+   if (!((E_Border *)obj)->lock_user_stacking)
+     e_border_act_move_keyboard((E_Border *)obj);
+}
+
 /***************************************************************************/
 ACT_FN_GO(window_resize)
 {
@@ -174,6 +187,19 @@
    e_border_act_resize_end((E_Border *)obj, ev);
 }
 
+ACT_FN_GO(window_resize_keyboard)
+{
+   if (!obj) obj = E_OBJECT(e_border_focused_get());
+   if (!obj) return;
+   if (obj->type != E_BORDER_TYPE)
+     {
+	obj = E_OBJECT(e_border_focused_get());
+	if (!obj) return;
+     }
+   if (!((E_Border *)obj)->lock_user_stacking)
+     e_border_act_resize_keyboard((E_Border *)obj);
+}
+
 /***************************************************************************/
 ACT_FN_GO(window_menu)
 {
@@ -2254,6 +2280,11 @@
    ACT_GO_SIGNAL(window_move);
    ACT_END(window_move);
    ACT_END_MOUSE(window_move);
+
+   ACT_GO(window_move_keyboard);
+   e_action_predef_name_set(_("Window : Actions"), _("Move with Keyboard"),
+			    "window_move_keyboard", NULL, NULL, 0);
+
    
    /* window_resize */
    ACT_GO(window_resize);
@@ -2265,6 +2296,10 @@
    ACT_END(window_resize);
    ACT_END_MOUSE(window_resize);
 
+   ACT_GO(window_resize_keyboard);
+   e_action_predef_name_set(_("Window : Actions"), _("Resize with Keyboard"),
+			    "window_resize_keyboard", NULL, NULL, 0);
+
    /* window_menu */
    ACT_GO(window_menu);
    e_action_predef_name_set(_("Menu"), _("Window Menu"), 
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to