diff --git a/Makefile.am b/Makefile.am index bc0ff88..01bda93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -205,6 +205,7 @@ openbox_openbox_SOURCES = \ openbox/actions/showdesktop.c \ openbox/actions/showmenu.c \ openbox/actions/unfocus.c \ + openbox/actions/tiling.c \ openbox/actions.c \ openbox/actions.h \ openbox/client.c \ diff --git a/data/rc.xml b/data/rc.xml index 04447f3..c7cce57 100644 --- a/data/rc.xml +++ b/data/rc.xml @@ -216,6 +216,12 @@ + + + + + + diff --git a/openbox/actions/all.c b/openbox/actions/all.c index c86c428..dbb1fec 100644 --- a/openbox/actions/all.c +++ b/openbox/actions/all.c @@ -39,4 +39,6 @@ void action_all_startup(void) action_growtoedge_startup(); action_if_startup(); action_focustobottom_startup(); + action_tiling_startup(); + } diff --git a/openbox/actions/all.h b/openbox/actions/all.h index 909836a..827e81c 100644 --- a/openbox/actions/all.h +++ b/openbox/actions/all.h @@ -40,5 +40,6 @@ void action_movetoedge_startup(void); void action_growtoedge_startup(void); void action_if_startup(void); void action_focustobottom_startup(void); +void action_tiling_startup(void); #endif diff --git a/openbox/event.c b/openbox/event.c index 44b6eb7..7fe0aab 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -761,7 +761,6 @@ static void event_handle_root(XEvent *e) ob_debug("Another WM has requested to replace us. Exiting."); ob_exit_replace(); break; - case ClientMessage: if (e->xclient.format != 32) break; diff --git a/openbox/screen.c b/openbox/screen.c index 3b9f66f..0f2b9f8 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -55,9 +55,13 @@ static gboolean screen_validate_layout(ObDesktopLayout *l); static gboolean replace_wm(void); static void screen_tell_ksplash(void); static void screen_fallback_focus(void); +static void refresh_tiling_screens(); guint screen_num_desktops; + guint screen_num_monitors; +guint screen_num_monitors_phys; + guint screen_desktop; guint screen_last_desktop; gboolean screen_showing_desktop; @@ -71,6 +75,14 @@ static guint screen_old_desktop; static gboolean screen_desktop_timeout = TRUE; /*! An array of desktops, holding an array of areas per monitor */ static Rect *monitor_area = NULL; +/* array holding physical screens, previos one virtual */ +static Rect *monitor_area_phys = NULL; +static ObTiledScreen *tiled_screens = NULL; + + +static ObTilingLayout TilingLayout = OB_TL_NONE; + + /*! An array of desktops, holding an array of struts */ static GSList *struts_top = NULL; static GSList *struts_left = NULL; @@ -1349,14 +1361,25 @@ static void get_xinerama_screens(Rect **xin_areas, guint *nxin) void screen_update_areas(void) { - guint i, j; - gulong *dims; - GList *it; - GSList *sit; + ob_debug("screen_update_areas."); g_free(monitor_area); get_xinerama_screens(&monitor_area, &screen_num_monitors); + refresh_tiling_screens(); + + _screen_update_areas(); +} +void _screen_update_areas(void) +{ + guint i, j; + gulong *dims; + GList *it; + GSList *sit; + + ob_debug("_screen_update_areas."); + + /* set up the user-specified margins */ config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]); config_margins.top_end = RECT_RIGHT(monitor_area[screen_num_monitors]); @@ -1731,3 +1754,232 @@ gboolean screen_pointer_pos(gint *x, gint *y) } return ret; } + +void init_phys_screens() +{ + if( monitor_area_phys == NULL ) + { + //not yet initialized + + ob_debug("initialize tiling stuff." ); + + + monitor_area_phys = g_memdup( monitor_area, sizeof(Rect) * (screen_num_monitors + 1) ); + screen_num_monitors_phys = screen_num_monitors; + + //initialize array with tiled screens, tiled screens array has same dimension as phys screens + + tiled_screens = g_new0(ObTiledScreen, screen_num_monitors_phys); + int i; + for( i = 0; i < screen_num_monitors_phys; i++ ) + { + tiled_screens[i].used_screens = 1; + tiled_screens[i].screens[0] = monitor_area_phys[i]; + tiled_screens[i].TilingLayout = OB_TL_NONE; + } + } +} + +gint find_phys_screen( gint _x, gint _y ) +{ + ob_debug("search phys screen for [%d][%d].", _x, _y ); + + init_phys_screens(); + int i; + for( i = 0; i < screen_num_monitors_phys; i++ ) + { + if( + monitor_area_phys[i].x <= _x && + monitor_area_phys[i].y <= _y && + ( monitor_area_phys[i].x + monitor_area_phys[i].width ) >= _x && + ( monitor_area_phys[i].y + monitor_area_phys[i].height ) >= _y ) + { + ob_debug("\tfound [%d].", i ); + return i; + } + } + + ob_debug("\tnot found [%d].", i ); + return 0; +} + +void set_tiling_layout_next( gint _x, gint _y ) +{ + gint phys_screen = find_phys_screen( _x, _y ); + + ObTilingLayout ntl; + + if( tiled_screens[phys_screen].TilingLayout == OB_TL_FOUR ) + { + ob_debug("set NONE tiling." ); + ntl = OB_TL_NONE; + } + else + { + ntl = (ObTilingLayout)(tiled_screens[phys_screen].TilingLayout + 1); + ob_debug("\tset next layout [%d].", ntl ); + } + set_tiling_layout( _x, _y, ntl ); + +} + +void set_tiling_layout( gint _x, gint _y, ObTilingLayout _tl ) +{ + ob_debug("set tiling layout [%d][%d][%d].", _x, _y, _tl ); + + + gint phys_screen = find_phys_screen( _x, _y ); + + tiled_screens[phys_screen].TilingLayout = _tl; + + gint x = monitor_area_phys[phys_screen].x; + gint y = monitor_area_phys[phys_screen].y; + gint width = monitor_area_phys[phys_screen].width; + gint height = monitor_area_phys[phys_screen].height; + + if( tiled_screens[phys_screen].x == 0 || tiled_screens[phys_screen].y == 0 ) + { + tiled_screens[phys_screen].x = width / 2; + tiled_screens[phys_screen].y = height / 2; + } + + set_tiling_center( tiled_screens[phys_screen].x + x, tiled_screens[phys_screen].y + y ); + +} + +void generate_virtual_screens() +{ + g_free( monitor_area ); + + int i,n,k; + screen_num_monitors = 0; + for( i = 0; i < screen_num_monitors_phys; i++ ) + screen_num_monitors += tiled_screens[i].used_screens; + + ob_debug("generate virtual screens [%d].", screen_num_monitors ); + + + monitor_area = g_new( Rect, screen_num_monitors + 1 ); + + n = 0; + + for( i = 0; i < screen_num_monitors_phys; i++ ) + { + for( k = 0; k < tiled_screens[i].used_screens; k++,n++ ) + { + ob_debug("add virtual screen with dims [%d][%d][%d][%d].", + tiled_screens[i].screens[k].x, + tiled_screens[i].screens[k].y, + tiled_screens[i].screens[k].width, + tiled_screens[i].screens[k].height); + monitor_area[n] = tiled_screens[i].screens[k]; + } + } + + monitor_area[screen_num_monitors] = monitor_area_phys[screen_num_monitors_phys]; + + _screen_update_areas(); +} + +//call it every time resolution of screen,display ot what ever has been changed +static void refresh_tiling_screens() +{ + if( monitor_area_phys == NULL ) + { + //seems to is not used untill now + return; + } + + /* to make it easer, we just drop all tiling infos + * but it whould be nice to recalculate all tiling screens + * it is not clear how to handle if one of phisycal screns disapears */ + + g_free( monitor_area_phys ); + monitor_area_phys = NULL; + g_free( tiled_screens ); + tiled_screens = NULL; + screen_num_monitors_phys = 0; + + +} + +#define SETSCREEN(a,b,c,d,e) RECT_SET(tiled_screens[phys_screen].screens[a],x+(b),y+(c),(d),(e)) +#define TSCREEN tiled_screens[phys_screen] + +void set_tiling_center( gint _x, gint _y ) +{ + gint phys_screen = find_phys_screen( _x, _y ); + + gint w = monitor_area_phys[phys_screen].width; + gint h = monitor_area_phys[phys_screen].height; + gint x = monitor_area_phys[phys_screen].x; + gint y = monitor_area_phys[phys_screen].y; + + tiled_screens[phys_screen].x = _x - x; + tiled_screens[phys_screen].y = _y - y; + + switch( tiled_screens[phys_screen].TilingLayout ) + { + case OB_TL_NONE: + SETSCREEN(0, 0, 0, w, h); + TSCREEN.used_screens = 1; + break; + case OB_TL_FOUR: + SETSCREEN(0, 0, 0, TSCREEN.x, TSCREEN.y); + SETSCREEN(1, TSCREEN.x, 0, w-TSCREEN.x, TSCREEN.y); + SETSCREEN(2, 0, TSCREEN.y, TSCREEN.x, h-TSCREEN.y); + SETSCREEN(3, TSCREEN.x, TSCREEN.y, w-TSCREEN.x, h-TSCREEN.y); + TSCREEN.used_screens = 4; + break; + case OB_TL_TWO_HORISONTAL: + SETSCREEN(0, 0, 0, w, TSCREEN.y); + SETSCREEN(1, 0, TSCREEN.y, w, h-TSCREEN.y); + TSCREEN.used_screens = 2; + break; + case OB_TL_TWO_VERTICAL: + SETSCREEN(0, 0, 0, TSCREEN.x, h); + SETSCREEN(1, TSCREEN.x, 0, w-TSCREEN.x, h); + TSCREEN.used_screens = 2; + break; + case OB_TL_THREE_TOP: + SETSCREEN(0, 0, 0, w, TSCREEN.y); + SETSCREEN(1, 0, TSCREEN.y, TSCREEN.x, h-TSCREEN.y); + SETSCREEN(2, TSCREEN.x, TSCREEN.y, w-TSCREEN.x, h-TSCREEN.y); + TSCREEN.used_screens = 3; + break; + case OB_TL_THREE_BOTTOM: + SETSCREEN(0, 0, 0, TSCREEN.x, TSCREEN.y); + SETSCREEN(1, TSCREEN.x, 0, w-TSCREEN.x, TSCREEN.y); + SETSCREEN(2, 0, TSCREEN.y, w, h-TSCREEN.y); + TSCREEN.used_screens = 3; + break; + case OB_TL_THREE_LEFT: + SETSCREEN(0, 0, 0, TSCREEN.x, h); + SETSCREEN(1, TSCREEN.x, 0, w-TSCREEN.x, TSCREEN.y); + SETSCREEN(2, TSCREEN.x, TSCREEN.y, w-TSCREEN.x, h-TSCREEN.y); + TSCREEN.used_screens = 3; + break; + case OB_TL_THREE_RIGHT: + SETSCREEN(0, 0, 0, TSCREEN.x, TSCREEN.y); + SETSCREEN(1, 0, TSCREEN.y, TSCREEN.x, h-TSCREEN.y); + SETSCREEN(2, TSCREEN.x, 0, w-TSCREEN.x, h); + TSCREEN.used_screens = 3; + break; + } + + generate_virtual_screens(); +} + +#undef SETSCREEN + +static void allocate_screens( gint _n ) +{ + if( _n <= 0 ) return; + + g_free( monitor_area ); + + screen_num_monitors = _n; + + monitor_area = g_new(Rect, screen_num_monitors + 1 ); +} + diff --git a/openbox/screen.h b/openbox/screen.h index 11915f1..12b637d 100644 --- a/openbox/screen.h +++ b/openbox/screen.h @@ -133,4 +133,39 @@ void screen_set_root_cursor(void); is on this screen and FALSE if it is on another screen. */ gboolean screen_pointer_pos(gint *x, gint *y); +/* tiling layouts */ + +typedef enum +{ + OB_TL_NONE = 0, + /* three areas, one big on top */ + OB_TL_THREE_TOP, + /* three areas, one big on left */ + OB_TL_THREE_LEFT, + OB_TL_THREE_BOTTOM, + OB_TL_THREE_RIGHT, + /* two areas, splitted vertically */ + OB_TL_TWO_VERTICAL, + /* two areas, splitted horisontally */ + OB_TL_TWO_HORISONTAL, + /* four small areas, do not put anything after this one */ + OB_TL_FOUR +} ObTilingLayout; + +typedef struct +{ + ObTilingLayout TilingLayout; + //dimensions of tiles, max 4 supported + Rect screens[4]; + //tiling center + gint x; + gint y; + + gint used_screens; +} ObTiledScreen; + +void set_tiling_center( gint _x, gint _y ); +void set_tiling_layout( gint _x, gint _y, ObTilingLayout _tl ); +void set_tiling_layout_next( gint _x, gint _y ); + #endif