aboutsummaryrefslogtreecommitdiffstats
path: root/src/panel_app.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/panel_app.c')
-rw-r--r--src/panel_app.c597
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;
+}
+