diff options
| author | Dana Jansens <danakj@orodu.net> | 2003-05-16 18:10:10 +0000 |
|---|---|---|
| committer | Dana Jansens <danakj@orodu.net> | 2003-05-16 18:10:10 +0000 |
| commit | b77e40e1c7710323aa59a778338d8e18b591f718 (patch) | |
| tree | 48ae520439b10bffa5c63f3cc5a7230ccab06331 /openbox/dock.c | |
| parent | 6e42b65bda1706887f3b2a7f9d79ba20f7611a06 (diff) | |
rename "Slit" to "Dock".
add config options to the rc3 for the dock.
create a window_map, add DockApps to the ObWindow types, use the window_map for translating windows into objects for event handling (only one lookup now) and remove the old maps (client_map, menu_map).
Diffstat (limited to 'openbox/dock.c')
| -rw-r--r-- | openbox/dock.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/openbox/dock.c b/openbox/dock.c new file mode 100644 index 00000000..6e45850e --- /dev/null +++ b/openbox/dock.c @@ -0,0 +1,382 @@ +#include "dock.h" +#include "screen.h" +#include "config.h" +#include "grab.h" +#include "openbox.h" +#include "render/theme.h" + +#define DOCK_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \ + EnterWindowMask | LeaveWindowMask) +#define DOCKAPP_EVENT_MASK (StructureNotifyMask) + +static Dock *dock; + +void dock_startup() +{ + XSetWindowAttributes attrib; + int i; + + dock = g_new0(struct Dock, 1); + dock->obwin.type = Window_Dock; + + dock->hidden = TRUE; + + attrib.event_mask = DOCK_EVENT_MASK; + attrib.override_redirect = True; + dock->frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0, + render_depth, InputOutput, render_visual, + CWOverrideRedirect | CWEventMask, + &attrib); + dock->a_frame = appearance_copy(theme_a_unfocused_title); + XSetWindowBorder(ob_display, dock->frame, theme_b_color->pixel); + XSetWindowBorderWidth(ob_display, dock->frame, theme_bwidth); + + g_hash_table_insert(window_map, &dock->frame, dock); + stacking_add(DOCK_AS_WINDOW(&dock[i])); + stacking_raise(DOCK_AS_WINDOW(&dock[i])); +} + +void dock_shutdown() +{ + XDestroyWindow(ob_display, dock->frame); + appearance_free(dock->a_frame); + g_hash_table_remove(window_map, &dock->frame); + stacking_remove(dock); +} + +void dock_add(Window win, XWMHints *wmhints) +{ + DockApp *app; + XWindowAttributes attrib; + + app = g_new0(DockApp, 1); + app->win = win; + app->icon_win = (wmhints->flags & IconWindowHint) ? + wmhints->icon_window : win; + + if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) { + app->w = attrib.width; + app->h = attrib.height; + } else { + app->w = app->h = 64; + } + + dock->dock_apps = g_list_append(dock->dock_apps, app); + dock_configure(); + + XReparentWindow(ob_display, app->icon_win, dock->frame, app->x, app->y); + /* + This is the same case as in frame.c for client windows. When Openbox is + starting, the window is already mapped so we see unmap events occur for + it. There are 2 unmap events generated that we see, one with the 'event' + member set the root window, and one set to the client, but both get + handled and need to be ignored. + */ + if (ob_state == State_Starting) + app->ignore_unmaps += 2; + + if (app->win != app->icon_win) { + /* have to map it so that it can be re-managed on a restart */ + XMoveWindow(ob_display, app->win, -1000, -1000); + XMapWindow(ob_display, app->win); + } + XMapWindow(ob_display, app->icon_win); + XSync(ob_display, False); + + /* specify that if we exit, the window should not be destroyed and should + be reparented back to root automatically */ + XChangeSaveSet(ob_display, app->icon_win, SetModeInsert); + XSelectInput(ob_display, app->icon_win, DOCKAPP_EVENT_MASK); + + grab_button_full(2, 0, app->icon_win, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, + GrabModeAsync, ob_cursors.move); + + g_hash_table_insert(window_map, &app->icon_win, app); + + g_message("Managed Dock App: 0x%lx", app->icon_win); +} + +void dock_remove_all() +{ + while (dock->dock_apps) + dock_remove(dock->dock_apps->data, TRUE); +} + +void dock_remove(DockApp *app, gboolean reparent) +{ + ungrab_button(2, 0, app->icon_win); + XSelectInput(ob_display, app->icon_win, NoEventMask); + /* remove the window from our save set */ + XChangeSaveSet(ob_display, app->icon_win, SetModeDelete); + XSync(ob_display, False); + + g_hash_table_remove(window_map, &app->icon_win); + + if (reparent) + XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y); + + dock->dock_apps = g_list_remove(dock->dock_apps, app); + dock_configure(); + + g_message("Unmanaged Dock App: 0x%lx", app->icon_win); + + g_free(app); +} + +void dock_configure() +{ + GList *it; + int spot; + int gravity; + + dock->w = dock->h = spot = 0; + + for (it = dock->dock_apps; it; it = it->next) { + struct DockApp *app = it->data; + if (config_dock_horz) { + app->x = spot; + app->y = 0; + dock->w += app->w; + dock->h = MAX(dock->h, app->h); + spot += app->w; + } else { + app->x = 0; + app->y = spot; + dock->w = MAX(dock->w, app->w); + dock->h += app->h; + spot += app->h; + } + + XMoveWindow(ob_display, app->icon_win, app->x, app->y); + } + + /* used for calculating offsets */ + dock->w += theme_bwidth * 2; + dock->h += theme_bwidth * 2; + + /* calculate position */ + switch (config_dock_pos) { + case DockPos_Floating: + dock->x = config_dock_x; + dock->y = config_dock_y; + gravity = NorthWestGravity; + break; + case DockPos_TopLeft: + dock->x = 0; + dock->y = 0; + gravity = NorthWestGravity; + break; + case DockPos_Top: + dock->x = screen_physical_size.width / 2; + dock->y = 0; + gravity = NorthGravity; + break; + case DockPos_TopRight: + dock->x = screen_physical_size.width; + dock->y = 0; + gravity = NorthEastGravity; + break; + case DockPos_Left: + dock->x = 0; + dock->y = screen_physical_size.height / 2; + gravity = WestGravity; + break; + case DockPos_Right: + dock->x = screen_physical_size.width; + dock->y = screen_physical_size.height / 2; + gravity = EastGravity; + break; + case DockPos_BottomLeft: + dock->x = 0; + dock->y = screen_physical_size.height; + gravity = SouthWestGravity; + break; + case DockPos_Bottom: + dock->x = screen_physical_size.width / 2; + dock->y = screen_physical_size.height; + gravity = SouthGravity; + break; + case DockPos_BottomRight: + dock->x = screen_physical_size.width; + dock->y = screen_physical_size.height; + gravity = SouthEastGravity; + break; + } + + switch(gravity) { + case NorthGravity: + case CenterGravity: + case SouthGravity: + dock->x -= dock->w / 2; + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + dock->x -= dock->w; + break; + } + switch(gravity) { + case WestGravity: + case CenterGravity: + case EastGravity: + dock->y -= dock->h / 2; + break; + case SouthWestGravity: + case SouthGravity: + case SouthEastGravity: + dock->y -= dock->h; + break; + } + + if (config_dock_hide && dock->hidden) { + switch (config_dock_pos) { + case DockPos_Floating: + break; + case DockPos_TopLeft: + if (config_dock_horz) + dock->y -= dock->h - theme_bwidth; + else + dock->x -= dock->w - theme_bwidth; + break; + case DockPos_Top: + dock->y -= dock->h - theme_bwidth; + break; + case DockPos_TopRight: + if (config_dock_horz) + dock->y -= dock->h - theme_bwidth; + else + dock->x += dock->w - theme_bwidth; + break; + case DockPos_Left: + dock->x -= dock->w - theme_bwidth; + break; + case DockPos_Right: + dock->x += dock->w - theme_bwidth; + break; + case DockPos_BottomLeft: + if (config_dock_horz) + dock->y += dock->h - theme_bwidth; + else + dock->x -= dock->w - theme_bwidth; + break; + case DockPos_Bottom: + dock->y += dock->h - theme_bwidth; + break; + case DockPos_BottomRight: + if (config_dock_horz) + dock->y += dock->h - theme_bwidth; + else + dock->x += dock->w - theme_bwidth; + break; + } + } + + /* not used for actually sizing shit */ + dock->w -= theme_bwidth * 2; + dock->h -= theme_bwidth * 2; + + if (dock->w > 0 && dock->h > 0) { + RECT_SET(dock->a_frame->area, 0, 0, dock->w, dock->h); + XMoveResizeWindow(ob_display, dock->frame, + dock->x, dock->y, dock->w, dock->h); + + paint(dock->frame, dock->a_frame); + XMapWindow(ob_display, dock->frame); + } else + XUnmapWindow(ob_display, dock->frame); + + /* but they are useful outside of this function! */ + dock->w += theme_bwidth * 2; + dock->h += theme_bwidth * 2; +} + +void dock_app_configure(DockApp *app, int w, int h) +{ + app->w = w; + app->h = h; + dock_configure(); +} + +void dock_app_drag(DockApp *app, XMotionEvent *e) +{ + DockApp *over = NULL; + GList *it; + int x, y; + gboolean after; + + x = e->x_root; + y = e->y_root; + + /* are we on top of the dock? */ + if (!(x >= dock->x && + y >= dock->y && + x < dock->x + dock->w && + y < dock->y + dock->h)) + return; + + x -= dock->x; + y -= dock->y; + + /* which dock app are we on top of? */ + for (it = dock->dock_apps; it; it = it->next) { + over = it->data; + if (config_dock_horz) { + if (x >= over->x && x < over->x + over->w) + break; + } else { + if (y >= over->y && y < over->y + over->h) + break; + } + } + if (!it || app == over) return; + + x -= over->x; + y -= over->y; + + if (config_dock_horz) + after = (x > over->w / 2); + else + after = (y > over->h / 2); + + /* remove before doing the it->next! */ + dock->dock_apps = g_list_remove(dock->dock_apps, app); + + if (after) it = it->next; + + dock->dock_apps = g_list_insert_before(dock->dock_apps, it, app); + dock_configure(); +} + +static void hide_timeout(void *n) +{ + /* dont repeat */ + timer_stop(dock->hide_timer); + dock->hide_timer = NULL; + + /* hide */ + dock->hidden = TRUE; + dock_configure(); +} + +void dock_hide(gboolean hide) +{ + if (dock->hidden == hide || !config_dock_hide) + return; + if (!hide) { + /* show */ + dock->hidden = FALSE; + dock_configure(); + + /* if was hiding, stop it */ + if (dock->hide_timer) { + timer_stop(dock->hide_timer); + dock->hide_timer = NULL; + } + } else { + g_assert(!dock->hide_timer); + dock->hide_timer = timer_start(config_dock_hide_timeout * 1000, + (TimeoutHandler)hide_timeout, + NULL); + } +} |
