aboutsummaryrefslogtreecommitdiffstats
path: root/mbpanelmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbpanelmgr.c')
-rw-r--r--mbpanelmgr.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/mbpanelmgr.c b/mbpanelmgr.c
new file mode 100644
index 0000000..4d45665
--- /dev/null
+++ b/mbpanelmgr.c
@@ -0,0 +1,543 @@
+/*
+ * Gtk2 Based matchbox panel manager.
+ *
+ * Copyright 2003 Matthew Allum <mallum@handhelds.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+Display *dpy;
+GtkListStore *list_store;
+GtkWidget *list_view;
+Window win_panel;
+Atom atoms[4];
+GtkTreeIter IterSelected;
+
+char *atom_names[] =
+ {
+ "WM_PROTOCOLS",
+ "_NET_WM_PING",
+ "WM_DELETE_WINDOW",
+ "_NET_CLIENT_LIST",
+ "_NET_ACTIVE_WINDOW"
+ };
+
+#define WM_PROTOCOLS 0
+#define _NET_WM_PING 1
+#define WM_DELETE_WINDOW 2
+#define _NET_CLIENT_LIST 3
+#define _NET_ACTIVE_WINDOW 4
+
+#define MB_REQ_CLIENT_ORDER 0
+
+void
+items_reorder (GtkWidget *w, GtkWidget *list_view);
+
+
+Window
+util_get_panel_win (Display *dpy, int panel_num)
+{
+ char tray_atom_spec[128];
+ Atom atom_sys_tray;
+ Window result;
+
+ snprintf(tray_atom_spec, 128, "_NET_SYSTEM_TRAY_S%i", panel_num);
+
+ atom_sys_tray = XInternAtom(dpy, tray_atom_spec, False);
+
+ XGrabServer (dpy);
+ result = XGetSelectionOwner(dpy, atom_sys_tray);
+ XUngrabServer (dpy);
+
+ return result;
+}
+
+gchar *
+util_get_window_name (Display *dpy, Window w)
+{
+ Atom actual_type;
+ Atom net_wm_name_atom = XInternAtom (dpy, "_NET_WM_NAME", False);
+ Atom utf8_string_atom = XInternAtom (dpy, "UTF8_STRING", False);
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop = NULL;
+ gchar *name = NULL;
+ XTextProperty text_prop;
+ int rc;
+
+ gdk_error_trap_push ();
+
+ rc = XGetWindowProperty (dpy, w, net_wm_name_atom,
+ 0, G_MAXLONG, False, utf8_string_atom, &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop);
+
+ gdk_error_trap_pop ();
+
+ if (rc != Success)
+ return FALSE;
+
+ if (nitems)
+ {
+ name = g_strdup (prop);
+ XFree (prop);
+ }
+ else
+ {
+ if (XGetWMName(dpy, w, &text_prop))
+ {
+ name = g_strdup((char *) text_prop.value);
+ XFree((char *) text_prop.value);
+ }
+ else
+ {
+ XFetchName(dpy, w, (char **)&name);
+ }
+ }
+
+ return name;
+}
+
+gboolean
+util_get_client_window_list (Display *dpy,
+ Window win_panel,
+ Window **wins_result,
+ guint *n_wins_result)
+{
+ Atom net_client_list_atom = XInternAtom (dpy, "_NET_CLIENT_LIST", False);
+
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after = 0;
+ unsigned char *prop = NULL;
+
+ if (XGetWindowProperty (dpy, win_panel, net_client_list_atom,
+ 0, G_MAXLONG, False, XA_WINDOW,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after, &prop) != Success)
+ return FALSE;
+
+ /* FIXME: more checks */
+
+ *wins_result = (Window *)prop;
+ *n_wins_result = (guint)nitems;
+
+ return TRUE;
+}
+
+GdkPixbuf *
+util_get_window_icon (Display *dpy, Window w)
+{
+ Atom actual_type;
+ Atom net_wm_icon_atom = XInternAtom (dpy, "_NET_WM_ICON", False);
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ gulong *prop = NULL;
+ int rc;
+ GdkPixbuf *pixbuf = NULL;
+
+ gdk_error_trap_push ();
+
+ rc = XGetWindowProperty (dpy, w, net_wm_icon_atom,
+ 0, G_MAXLONG, False, XA_CARDINAL, &actual_type, &actual_format,
+ &nitems, &bytes_after, (guchar **)&prop);
+
+ if (gdk_error_trap_pop ())
+ return FALSE;
+
+ if (rc != Success)
+ return FALSE;
+
+ if (nitems)
+ {
+ guint w = prop[0], h = prop[1];
+ guint i;
+ guchar *pixels = g_malloc (w * h * 4);
+ guchar *p = pixels;
+
+ for (i = 0; i < w * h; i++)
+ {
+ gulong l = prop[2 + i];
+ *(p++) = (l & 0x00ff0000) >> 16;
+ *(p++) = (l & 0x0000ff00) >> 8;
+ *(p++) = (l & 0x000000ff);
+ *(p++) = (l & 0xff000000) >> 24;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_data (pixels,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ w, h,
+ w * 4,
+ (GdkPixbufDestroyNotify)g_free,
+ NULL);
+ }
+
+ if (prop)
+ XFree (prop);
+
+ return pixbuf;
+}
+
+gboolean
+item_move_down (GtkWidget *w, GtkWidget *list_view)
+{
+ GtkTreeSelection *sel;
+ GtkTreeIter iter, *next_iter;
+ GtkTreeModel *model;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
+
+ if (gtk_tree_selection_get_selected (sel, &model, &iter))
+ {
+ next_iter = gtk_tree_iter_copy (&iter);
+
+ if (gtk_tree_model_iter_next (model, next_iter))
+ {
+ gtk_list_store_move_after (list_store, &iter, next_iter);
+ gtk_tree_iter_free(next_iter);
+
+ items_reorder (w, list_view);
+ }
+ }
+}
+
+gboolean
+item_move_up (GtkWidget *w, GtkWidget *list_view)
+{
+ GtkTreeSelection *sel;
+ GtkTreeIter iter, prev_iter;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ gchar *str = NULL;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
+
+ if (gtk_tree_selection_get_selected (sel, &model, &iter))
+ {
+ path = gtk_tree_model_get_path (model, &iter);
+
+ gtk_tree_path_prev(path);
+
+ gtk_tree_model_get_iter (model, &prev_iter, path);
+
+ str = gtk_tree_model_get_string_from_iter (model, &prev_iter);
+
+ if (str[0] == '0')
+ gtk_list_store_move_after (list_store, &prev_iter, &iter);
+ else
+ gtk_list_store_move_before (list_store, &iter, &prev_iter);
+
+ g_free(str);
+ gtk_tree_path_free(path);
+
+ items_reorder (w, list_view);
+ }
+
+}
+
+void
+item_add_new (Display *dpy, Window w)
+{
+ GtkTreeIter iter;
+ gchar *name = util_get_window_name (dpy, w);
+ GdkPixbuf *icon = util_get_window_icon (dpy, w);
+
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter, 0, name, 1, w, -1);
+ if (icon)
+ {
+ GdkPixbuf *icons = gdk_pixbuf_scale_simple (icon, 16, 16, GDK_INTERP_BILINEAR);
+ gdk_pixbuf_unref (icon);
+ gtk_list_store_set (list_store, &iter, 2, icons, -1);
+ }
+
+ /* XXX: free up name ? */
+}
+
+void
+items_reorder (GtkWidget *w, GtkWidget *list_view)
+{
+ GtkTreeIter iter;
+ int rows = 0, i = 0;
+ Window *wins = NULL;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
+ {
+ do {
+ rows++;
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), &iter));
+
+ wins = malloc(sizeof(Window)*rows);
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter);
+
+ do {
+ gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 1, &wins[i], -1);
+ i++;
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), &iter));
+
+ XChangeProperty(dpy, win_panel,
+ atoms[MB_REQ_CLIENT_ORDER],
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *)wins, rows);
+
+ free(wins);
+ }
+}
+
+void
+gui_populate ()
+{
+ Window *list;
+ guint nr, i;
+ GtkTreeIter iter, iter_selected;
+ GtkTreeSelection *sel;
+ GtkTreeModel *model;
+ GtkTreePath *path_selected;
+ Bool have_selection = False;
+ char *p;
+
+ if (util_get_client_window_list (dpy, util_get_panel_win (dpy, 0),
+ &list, &nr) == FALSE)
+ return;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
+
+ if (gtk_tree_selection_get_selected (sel, &model, &iter_selected))
+ {
+ have_selection = True;
+ path_selected = gtk_tree_model_get_path(model, &iter_selected);
+ }
+
+ p = g_malloc0 (nr);
+
+ gtk_list_store_clear (list_store);
+
+ for (i = 0; i < nr; i++)
+ {
+ if (p[i] == 0 )
+ {
+ item_add_new(dpy, list[i]);
+ }
+ }
+
+ if (have_selection)
+ {
+ gtk_tree_selection_select_path (sel, path_selected);
+ gtk_tree_path_free(path_selected);
+ }
+
+ g_free (p);
+}
+
+
+void
+gui_setup (void)
+{
+ GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ GtkWidget *scrolled = gtk_scrolled_window_new (NULL, NULL);
+ GtkWidget *vbox, *vbox_buttons, *hbox1, *hbox2;
+ GtkWidget *apply_button, *up_button, *down_button;
+ GtkWidget *img_up, *img_down;
+ GtkWidget *notebook, *notebook_label;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ GtkWidget *combo, *enable_button;
+ GList *display_app_list = NULL;
+
+ notebook = gtk_notebook_new ();
+ gtk_notebook_set_tab_pos( GTK_NOTEBOOK (notebook), GTK_POS_TOP);
+ gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);
+
+ gtk_container_add (GTK_CONTAINER (window), notebook );
+
+ /* reorder tab */
+
+ /* list */
+
+ list_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT,G_TYPE_OBJECT);
+ list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list_view), FALSE);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Icon", renderer,
+ "pixbuf", 2, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
+ "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (scrolled), list_view);
+ gtk_container_set_border_width (GTK_CONTAINER (scrolled), 6);
+
+
+ vbox = gtk_vbox_new (FALSE, 2); /* main vbox */
+
+ notebook_label = gtk_label_new ("Order");
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, notebook_label);
+
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+ hbox1 = gtk_hbox_new (FALSE, 2); /* list + up/down buttons container */
+ gtk_box_pack_start (GTK_BOX (vbox), hbox1, TRUE, TRUE, 0);
+
+ /* for apply button */
+ gtk_box_pack_start (GTK_BOX (hbox1), scrolled, TRUE, TRUE, 0);
+
+ /* Up / Down buttons */
+
+ vbox_buttons = gtk_vbox_new (FALSE, 2); /* Up/Down button box */
+ gtk_container_set_border_width (GTK_CONTAINER (vbox_buttons), 6);
+ up_button = gtk_button_new ();
+ down_button = gtk_button_new ();
+
+ img_up = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add (GTK_CONTAINER (up_button), img_up);
+
+ img_down = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add (GTK_CONTAINER (down_button), img_down);
+
+ gtk_box_pack_start (GTK_BOX (vbox_buttons), up_button, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox_buttons), down_button, FALSE, TRUE, 0);
+
+ gtk_box_pack_end (GTK_BOX (hbox1), vbox_buttons, FALSE, TRUE, 0);
+
+ /*
+
+ hbox2 = gtk_hbox_new (FALSE, 1);
+ gtk_box_pack_end (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0);
+
+ apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
+
+ gtk_box_pack_end (GTK_BOX (hbox2), apply_button, FALSE, FALSE, 0);
+
+ g_signal_connect (G_OBJECT (apply_button), "clicked",
+ G_CALLBACK (items_reorder), list_view);
+
+ */
+
+ g_signal_connect (G_OBJECT (up_button), "clicked",
+ G_CALLBACK (item_move_up), list_view);
+
+ g_signal_connect (G_OBJECT (down_button), "clicked",
+ G_CALLBACK (item_move_down), list_view);
+
+
+ g_signal_connect (G_OBJECT (window), "delete_event",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+
+#if 0
+
+ /* enable tab */
+
+ vbox = gtk_vbox_new (FALSE, 2);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+ /* FIXME: should be a menu not combo? */
+ combo = gtk_combo_new();
+
+ display_app_list = g_list_append (display_app_list, "String 2");
+ display_app_list = g_list_append (display_app_list, "String 2");
+ display_app_list = g_list_append (display_app_list, "String 2");
+
+ gtk_combo_set_popdown_strings (GTK_COMBO (combo), display_app_list);
+
+ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
+
+ enable_button = gtk_check_button_new_with_label ( "Enable" );
+
+ gtk_box_pack_start (GTK_BOX (vbox), enable_button, FALSE, TRUE, 0);
+
+ notebook_label = gtk_label_new ("Display");
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, notebook_label);
+
+ /* Position tab */
+
+ vbox = gtk_vbox_new (FALSE, 2);
+
+ notebook_label = gtk_label_new ("Position");
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, notebook_label);
+
+#endif
+
+ gtk_window_set_title (GTK_WINDOW (window), "Panel Manager");
+
+ gtk_widget_show_all (window);
+
+}
+
+GdkFilterReturn
+window_filter (GdkXEvent *xev, GdkEvent *gev, gpointer d)
+{
+ XEvent *ev = (XEvent *)xev;
+ Display *dpy = ev->xany.display;
+
+ if (ev->xany.type == PropertyNotify
+ && ev->xproperty.window == win_panel)
+ {
+ if (ev->xproperty.atom == atoms[_NET_CLIENT_LIST])
+ {
+ gui_populate (dpy);
+ }
+
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ gtk_init (&argc, &argv);
+
+ dpy = GDK_DISPLAY ();
+
+ atoms[_NET_CLIENT_LIST] = XInternAtom (dpy, "_NET_CLIENT_LIST", False);
+ atoms[MB_REQ_CLIENT_ORDER] = XInternAtom (dpy, "_MB_REQ_CLIENT_ORDER", False);
+ gui_setup ();
+
+ if ((win_panel = util_get_panel_win (dpy, 0)) == None)
+ {
+ fprintf(stderr, "mbpanelmgr: unable to find panel to manage!\n");
+ exit(1);
+ }
+
+ gui_populate ();
+
+ gdk_window_add_filter (NULL, window_filter, NULL);
+
+ XSelectInput (dpy, win_panel, PropertyChangeMask);
+
+ gtk_main ();
+
+ exit (0);
+}