diff options
Diffstat (limited to 'src/panel_app.c')
-rw-r--r-- | src/panel_app.c | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/src/panel_app.c b/src/panel_app.c new file mode 100644 index 0000000..a3d020b --- /dev/null +++ b/src/panel_app.c @@ -0,0 +1,597 @@ +#include "panel_app.h" + +MBPanelApp* +panel_app_list_get_prev (MBPanel *panel, + MBPanelApp *papp, + MBPanelApp **list_head) +{ + MBPanelApp *tmp = *list_head; + + if (tmp == NULL || papp == tmp) return NULL; + + while (tmp->next != NULL) + { + if (tmp->next == papp) return tmp; + tmp = tmp->next; + } + + return NULL; +} + +MBPanelApp* +panel_app_list_get_last (MBPanel *panel, + MBPanelApp *list_head) +{ + MBPanelApp *tmp = list_head; + + if (tmp == NULL) return NULL; + + while (tmp->next != NULL) tmp = tmp->next; + + return tmp; +} + +MBPanelApp* +panel_app_list_prepend(MBPanel *panel, + MBPanelApp *list_to_append_to, + MBPanelApp *papp_new) +{ + papp_new->next = list_to_append_to; + return papp_new; +} + +void +panel_app_list_append (MBPanel *panel, + MBPanelApp **list_to_append_to, + MBPanelApp *new_client) +{ + MBPanelApp *tmp = NULL; + if (*list_to_append_to == NULL) + { + *list_to_append_to = new_client; + } + else + { + tmp = *list_to_append_to; + while ( tmp->next != NULL ) tmp = tmp->next; + tmp->next = new_client; + } + + new_client->next = NULL; +} + +void /* XXX Can probably go */ +panel_app_list_insert_after(MBPanel *panel, + MBPanelApp *papp, + MBPanelApp *new_papp) +{ + MBPanelApp *tmp; + tmp = papp->next; + papp->next = new_papp; + new_papp->next = tmp; +} + +void +panel_app_list_remove (MBPanel *panel, + MBPanelApp *papp, + MBPanelApp **list_head) +{ + MBPanelApp *prev_papp = panel_app_list_get_prev(panel, papp, list_head); + + if (prev_papp == NULL) + { + *list_head = papp->next; + } + else + { + prev_papp->next = papp->next; + } + return; +} + +void +panel_app_name_get(MBPanel *panel, + MBPanelApp *papp) +{ + Atom type; + int format; + long bytes_after; + long n_items; + int result; + + result = XGetWindowProperty (panel->dpy, papp->win, + panel->atoms[ATOM_NET_WM_NAME], + 0, 1024L, + False, panel->atoms[ATOM_UTF8_STRING], + &type, &format, &n_items, + &bytes_after, (unsigned char **)&papp->name); + + if (result != Success + || papp->name == NULL + || type != panel->atoms[ATOM_UTF8_STRING] + || format != 8 + || n_items == 0) + { + if (papp->name) XFree (papp->name); + + XFetchName(panel->dpy, papp->win, (char **)&papp->name); + if (papp->name == NULL) { + XStoreName(panel->dpy, papp->win, "<unnamed>"); + XFetchName(panel->dpy, papp->win, (char **)&papp->name); + if (papp->name == NULL) + papp->name = strdup("<unnamed>"); + } + } +} + +Window +panel_app_get_client_leader_win(MBPanel *panel, MBPanelApp *papp) +{ + Atom realType; + unsigned long n; + unsigned long extra; + int format; + int status; + Window* value = NULL, win_result = None; + + status = XGetWindowProperty(panel->dpy, papp->win, + panel->atoms[ATOM_WM_CLIENT_LEADER], + 0L, 16L, + 0, XA_WINDOW, &realType, &format, + &n, &extra, (unsigned char **) &value); + if (status == Success && realType == XA_WINDOW + && format == 32 && n == 1 && value != NULL) + { + win_result = (Window) value[0]; + } + + if (value) XFree(value); + + return win_result; +} + +int* +panel_app_icon_prop_data_get(MBPanel *d, MBPanelApp *papp) +{ + Atom type; + int format; + long bytes_after; + unsigned char *data = NULL; + long n_items; + int result; + + result = XGetWindowProperty (d->dpy, papp->win, + d->atoms[ATOM_NET_WM_ICON], + 0, 100000L, + False, XA_CARDINAL, + &type, &format, &n_items, + &bytes_after, (unsigned char **)&data); + + if (result != Success || data == NULL) + { + if (data) XFree (data); + DBG("%s() failed for %s (XID: %li)\n", __func__, papp->name, papp->win); + return NULL; + } + + return (int *)data; +} + +void +panel_app_add_start(MBPanel *panel, MBPanelApp *papp_new) +{ + MBPanelApp *papp_prev; + + papp_prev = panel_app_list_get_last(panel, panel->apps_start_head); + + panel_app_list_append (panel, &panel->apps_start_head, papp_new); + + if (papp_prev != NULL) + { + papp_new->offset = panel_app_get_offset(panel, papp_prev) + + panel_app_get_size(panel, papp_prev); + DBG("%s() got %i = %i + %i\n", __func__, papp_new->offset, + panel_app_get_offset(panel, papp_prev) , + panel_app_get_size(panel, papp_prev) ); + } + else + papp_new->offset = 0; + + papp_new->gravity = PAPP_GRAVITY_START; +} + +void +panel_app_add_end(MBPanel *panel, MBPanelApp *papp_new) +{ + MBPanelApp *papp_prev; + + papp_prev = panel_app_list_get_last(panel, panel->apps_end_head); + + panel_app_list_append (panel, &panel->apps_end_head, papp_new); + + if (papp_prev != NULL) + papp_new->offset = panel_app_get_offset(panel, papp_prev) + - panel_app_get_size(panel, papp_new); + else + papp_new->offset = ( PANEL_IS_VERTICAL(panel) ? panel->h : panel->w ) + - panel_app_get_size(panel, papp_new); + + papp_new->gravity = PAPP_GRAVITY_END; +} + +Bool +panel_app_check_for_space (MBPanel *panel, MBPanelApp *papp) +{ + MBPanelApp *papp_end = NULL, *papp_start = NULL; + + papp_end = panel_app_list_get_last(panel, panel->apps_end_head); + papp_start = panel_app_list_get_last(panel, panel->apps_start_head); + + if (papp_end && papp_start && + panel_app_get_offset(panel, papp_start) + + panel_app_get_size(panel, papp_start) + > panel_app_get_offset(panel, papp_end)) + { + panel_handle_full_panel(panel, papp); + return False; + } + return True; +} + +MBPanelApp * +panel_app_new(MBPanel *panel, Window win, char *cmd_str) +{ + MBPanelApp *papp; + XWindowAttributes attr; + int padding = 0; + Bool add_at_start = False; + + papp = NEW(MBPanelApp); + + papp->next = NULL; + papp->win = win; + papp->panel = panel; + papp->ignore = False; + papp->ignore_unmap = 0; + papp->icon = NULL; + + /* XXX should check we actually get this */ + XGetWindowAttributes(panel->dpy, win, &attr); + + papp->w = attr.width; + papp->h = attr.height; + + if (session_preexisting_restarting(panel) && !panel->session_run_first_time) + { + if (panel->session_cur_gravity == PAPP_GRAVITY_START) + add_at_start = True; + } + else if ( ((attr.x < 0) && !PANEL_IS_VERTICAL(panel)) + || ((attr.y < 0) && PANEL_IS_VERTICAL(panel))) + { + add_at_start = True; + } + + if (add_at_start) + { + if (panel->apps_start_head == NULL) + padding = panel->margin_start; + else + padding = panel->padding; + + panel_app_add_start(panel, papp); + } + else + { + if (panel->apps_end_head == NULL) + padding = -1 * panel->margin_end; + else + padding = -1 * panel->padding; + + panel_app_add_end(panel, papp); + } + + DBG("%s() papp offset at %i\n", __func__, papp->offset ); + + panel_app_name_get(panel, papp); + + papp->cmd_str = cmd_str; + + if (panel->orientation == North || panel->orientation == South) + { + papp->h = panel->h - 4; + papp->y = (panel->h - papp->h) / 2; + papp->x = papp->offset + padding; + } + else + { + papp->w = panel->w - 4; + papp->x = (panel->w - papp->w) / 2; + papp->y = papp->offset + padding; + } + + if (!panel_app_check_for_space(panel, papp)) + return NULL; + + XResizeWindow(panel->dpy, papp->win, papp->w, papp->h); + XReparentWindow(panel->dpy, papp->win, panel->win, papp->x, papp->y); + panel_app_deliver_config_event(panel, papp); + + panel_update_client_list_prop (panel); + + return papp; +} + +void +panel_app_handle_configure_request(MBPanel *panel, XConfigureRequestEvent *ev) +{ + XWindowChanges xwc; + MBPanelApp *papp = NULL; + + papp = panel_app_get_from_window( panel, ev->window ); + + if (panel->is_hidden) return; + + if (papp != NULL) + { + DBG("%s() config req x: %i , y: %i w: %i h: %i for %s\n", + __func__, ev->x, ev->y, ev->width, ev->height, papp->name ); + + DBG("%s() panel is w: %i %i h:\n", + __func__, panel->w, panel->h ); + + if (panel->orientation == North || panel->orientation == South) + { + xwc.width = ev->width; + xwc.height = panel->h - 4; + + papp->y = (panel->h - papp->h) / 2; + + if (xwc.width != papp->w) /* Handle width changes */ + { + if (papp == panel_app_list_get_last(panel, panel->apps_end_head)) + { + panel_app_move_to(panel, papp, + papp->x - (xwc.width - papp->w)); + } + else if (papp == panel_app_list_get_last(panel, + panel->apps_start_head)) + { + panel_app_move_to(panel, papp, + papp->x + (xwc.width - papp->w)); + } + else + { + panel_apps_nudge (panel, papp->next, xwc.width - papp->w); + } + papp->w = xwc.width; + } + + xwc.x = papp->x; /* NOT allowed to move themselves */ + xwc.y = papp->y; + + } else { /* East / West orientated dock */ + + xwc.width = panel->w - 4; + xwc.height = ev->height; + + papp->x = (panel->w - papp->w) / 2; + xwc.x = papp->x; + xwc.y = papp->y; + + if (xwc.height != papp->h) /* Handle width changes */ + { + if (papp == panel_app_list_get_last(panel, panel->apps_end_head)) + { + panel_app_move_to(panel, papp, + papp->y - (xwc.height - papp->h)); + } + else if (papp == panel_app_list_get_last(panel, + panel->apps_start_head)) + { + panel_app_move_to(panel, papp, + papp->y + (xwc.height - papp->h)); + } + else + { + panel_apps_nudge (panel, papp->next, xwc.height - papp->h); + } + papp->h = xwc.height; + } + } + + xwc.border_width = 0; + xwc.sibling = None; + xwc.stack_mode = None; + + DBG("%s() setting x: %i , y: %i w: %i h: %i \n", + __func__, xwc.x, xwc.y, xwc.width, xwc.height ); + + XConfigureWindow(panel->dpy, papp->win, ev->value_mask, &xwc); + } +} + +void +panel_app_deliver_config_event(MBPanel *panel, MBPanelApp *papp) +{ + XConfigureEvent ce; + + if (panel->is_hidden) return; + + ce.type = ConfigureNotify; + ce.event = papp->win; + ce.window = papp->win; + + if (PANEL_IS_VERTICAL(panel)) + { + papp->x = (panel->w - papp->w) / 2; + ce.x = papp->x; + ce.y = papp->y; + ce.width = papp->w; + ce.height = papp->h; + } else { + papp->y = (panel->h - papp->h) / 2; + ce.x = papp->x; + ce.y = papp->y; // + panel->y; + ce.width = papp->w; + ce.height = papp->h; + } + + ce.border_width = 0; + ce.above = panel->win; + ce.override_redirect = 0; + + DBG("%s() delivering x: %i , y: %i w: %i h: %i name : %s\n", + __func__, ce.x, ce.y, ce.width, ce.height, papp->name ); + + XSendEvent(panel->dpy, papp->win, False, + StructureNotifyMask, (XEvent *)&ce); +} + +void +panel_app_move_to (MBPanel *panel, + MBPanelApp *papp, + int origin_offset) +{ + if (panel->orientation == North || panel->orientation == South) + { + papp->x = origin_offset; + papp->y = (panel->h - papp->h) / 2; + } + else + { + papp->y = origin_offset; + papp->x = (panel->w - papp->w) / 2; + } + + papp->offset = origin_offset; + + if (!panel_app_check_for_space(panel, papp)) + return; + + XMoveWindow(panel->dpy, papp->win, papp->x, papp->y); +} + +void +panel_apps_nudge (MBPanel *panel, + MBPanelApp *papp, + int amount) +{ + MBPanelApp *papp_cur = papp; + + while (papp_cur != NULL) + { + panel_app_move_to (panel, papp_cur, + panel_app_get_offset(panel, papp_cur) + amount); + papp_cur = papp_cur->next; + } +} + +void +panel_apps_rescale (MBPanel *panel, + MBPanelApp *papp) +{ + MBPanelApp *papp_cur = papp; + + while (papp_cur != NULL) + { + papp->h = panel->h - 4; + XResizeWindow(panel->dpy, papp->win, papp->w, papp->h); + panel_app_deliver_config_event(panel, papp); + papp_cur = papp_cur->next; + } +} + +void +panel_app_destroy (MBPanel *panel, + MBPanelApp *papp) +{ + MBMenuItem *tmp = NULL; + + if (!papp) return; + + /* remove popup menu entry XXX this functionaility should be in mbmenu */ + if (panel->remove_menu) + tmp = panel->remove_menu->items; + + while (tmp != NULL) + { + if ((MBPanelApp *)tmp->cb_data == papp) + { + mb_menu_item_remove(panel->mbmenu, panel->remove_menu, tmp); + break; + } + tmp = tmp->next_item; + } + + if (papp->gravity == PAPP_GRAVITY_START) + { + panel_apps_nudge(panel, papp->next, + -1 * panel_app_get_size(panel, papp)); + panel_app_list_remove(panel, papp, &panel->apps_start_head); + } + else + { + panel_apps_nudge(panel, papp->next, panel_app_get_size(panel, papp)); + panel_app_list_remove(panel, papp, &panel->apps_end_head); + } + + if (papp->name) XFree(papp->name); + + if (papp->cmd_str) free(papp->cmd_str); + + if (papp->icon) mb_pixbuf_img_free(panel->pb, papp->icon); + + free(papp); + + panel_update_client_list_prop (panel); +} + +/* Utilities */ + +int +panel_app_get_offset (MBPanel *panel, + MBPanelApp *papp) +{ + if (panel->orientation == East || panel->orientation == West) + return papp->y; + else + return papp->x; +} + +int +panel_app_get_size (MBPanel *panel, + MBPanelApp *papp) +{ + if (panel->orientation == East || panel->orientation == West) + return papp->h; + else + return papp->w; +} + +MBPanelApp* +panel_app_get_from_window (MBPanel *panel, + Window win) +{ + MBPanelApp *papp = panel->apps_start_head; + DBG("%s() called, looking for win %li\n", __func__, win); + + while( papp != NULL) + { + DBG("%s() check %s ( %li )\n", __func__, papp->name, papp->win); + if (papp->win == win) return papp; + papp = papp->next; + } + + papp = panel->apps_end_head; + + while( papp != NULL) + { + // DBG("%s() check %s ( %li )\n", __func__, papp->name, papp->win); + if (papp->win == win) return papp; + papp = papp->next; + } + + return NULL; +} + |