New import
git-svn-id: http://tint2.googlecode.com/svn/trunk@13 121b4492-b84c-0410-8b4c-0d4edfb3f3cc
This commit is contained in:
71
src/systray/Makefile
Normal file
71
src/systray/Makefile
Normal file
@@ -0,0 +1,71 @@
|
||||
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
||||
# #
|
||||
# Change these values to customize your installation and build process #
|
||||
# #
|
||||
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
||||
|
||||
# Change this PREFIX to where you want docker to be installed
|
||||
PREFIX=/usr/local
|
||||
# Change this XLIBPATH to point to your X11 development package's installation
|
||||
XLIBPATH=/usr/X11R6/lib
|
||||
|
||||
# Sets some flags for stricter compiling
|
||||
CFLAGS=-pedantic -Wall -W -O
|
||||
|
||||
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
||||
# #
|
||||
# Leave the rest of the Makefile alone if you want it to build! #
|
||||
# #
|
||||
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
|
||||
|
||||
PACKAGE=docker
|
||||
VERSION=1.5
|
||||
|
||||
target=docker
|
||||
sources=docker.c kde.c icons.c xproperty.c net.c
|
||||
headers=docker.h kde.h icons.h xproperty.h net.h version.h
|
||||
extra=README COPYING version.h.in
|
||||
|
||||
all: $(target) $(sources) $(headers)
|
||||
@echo Build Successful
|
||||
|
||||
$(target): $(sources:.c=.o)
|
||||
$(CC) $(CFLAGS) -L$(XLIBPATH) -lX11 \
|
||||
`pkg-config --libs glib-2.0` $^ -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` $<
|
||||
|
||||
version.h: version.h.in Makefile
|
||||
sed -e "s/@VERSION@/$(VERSION)/" version.h.in > $@
|
||||
|
||||
install: all
|
||||
install $(target) $(PREFIX)/bin/$(target)
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/$(target)
|
||||
|
||||
clean:
|
||||
rm -rf .dist
|
||||
rm -f core *.o .\#* *\~ $(target)
|
||||
|
||||
distclean: clean
|
||||
rm -f version.h
|
||||
rm -f $(PACKAGE)-*.tar.gz
|
||||
|
||||
dist: Makefile $(sources) $(headers) $(extra)
|
||||
mkdir -p .dist/$(PACKAGE)-$(VERSION) && \
|
||||
cp $^ .dist/$(PACKAGE)-$(VERSION) && \
|
||||
tar -c -z -C .dist -f \
|
||||
$(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION) && \
|
||||
rm -rf .dist
|
||||
|
||||
love: $(sources)
|
||||
touch $^
|
||||
|
||||
# local dependancies
|
||||
docker.o: docker.c version.h kde.h icons.h docker.h net.h
|
||||
icons.o: icons.c icons.h docker.h
|
||||
kde.o: kde.c kde.h docker.h xproperty.h
|
||||
net.o: net.c net.h docker.h icons.h
|
||||
xproperty.o: xproperty.c xproperty.h docker.h
|
||||
75
src/systray/README
Normal file
75
src/systray/README
Normal file
@@ -0,0 +1,75 @@
|
||||
Docker - Docking System Tray
|
||||
|
||||
Copyright (C) 2003 Ben Jansens
|
||||
|
||||
|
||||
What is Docker?
|
||||
|
||||
Docker is a docking application (WindowMaker dock app) which acts as a system
|
||||
tray for KDE3 and GNOME2. It can be used to replace the panel in either
|
||||
environment, allowing you to have a system tray without running the KDE/GNOME
|
||||
panel.
|
||||
|
||||
|
||||
What window managers can I use Docker with?
|
||||
|
||||
I wrote and designed Docker to work with Openbox 2, but it should work fine in
|
||||
any window manager that supports WindowMaker dock apps.
|
||||
|
||||
|
||||
Why don't my KDE3 system tray icons show up?
|
||||
|
||||
Docker requires a KDE3 compliant window manager to handle KDE3 system tray
|
||||
icons, and since it is a docking application, the window manager needs to also
|
||||
support WindowMaker Dock Apps. The only window manager that meets these
|
||||
requirements to my knowledge is:
|
||||
- Openbox 2 (http://icculus.org/openbox)
|
||||
If you know of any other window managers that support the KDE3 hints for the
|
||||
system tray and docking apps (i.e. that docker works in), please let me know so
|
||||
I can add them to this list, and test docker out in them!
|
||||
|
||||
|
||||
Why don't my GNOME2 system tray icons show up?
|
||||
|
||||
I don't know! Email me and let me know what application isn't working. (Don't
|
||||
you dare email me about a GNOME1 application! :)
|
||||
|
||||
|
||||
Who wrote Docker?
|
||||
|
||||
Me, of course. That is, Ben Jansens. I can be reached at <ben@orodu.net>. I am
|
||||
the founder and currently the project head of sorts for the Openbox project.
|
||||
|
||||
|
||||
===============================
|
||||
|| INSTALLATION INSTRUCTIONS ||
|
||||
===============================
|
||||
|
||||
To install this application, simply do the following:
|
||||
|
||||
% make
|
||||
(as root)
|
||||
# make install
|
||||
|
||||
You can change a couple of things in the Makefile if you want to:
|
||||
PREFIX defines where the program will be installed to.
|
||||
XLIBPATH defines where your libX11.so is located. If it is not on the standard
|
||||
/usr/X11R6/lib path, then you will have to change this.
|
||||
|
||||
==================
|
||||
|| LICENSE INFO ||
|
||||
==================
|
||||
|
||||
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 of the License, 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
346
src/systray/docker.c
Normal file
346
src/systray/docker.c
Normal file
@@ -0,0 +1,346 @@
|
||||
#include "version.h"
|
||||
#include "kde.h"
|
||||
#include "icons.h"
|
||||
#include "docker.h"
|
||||
#include "net.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
Window win = None, hint_win = None, root = None;
|
||||
gboolean wmaker = FALSE; /* WindowMakerMode!!! wheeee */
|
||||
Display *display = NULL;
|
||||
GSList *icons = NULL;
|
||||
int width = 0, height = 0;
|
||||
int border = 1; /* blank area around icons. must be > 0 */
|
||||
gboolean horizontal = TRUE; /* layout direction */
|
||||
int icon_size = 24; /* width and height of systray icons */
|
||||
|
||||
//static char *display_string = NULL;
|
||||
/* excluding the border. sum of all child apps */
|
||||
static gboolean exit_app = FALSE;
|
||||
|
||||
/*
|
||||
void parse_cmd_line()
|
||||
{
|
||||
int i;
|
||||
gboolean help = FALSE;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (0 == strcasecmp(argv[i], "-display")) {
|
||||
++i;
|
||||
if (i < argc) {
|
||||
display_string = argv[i];
|
||||
} else {
|
||||
g_printerr("-display requires a parameter\n");
|
||||
help = TRUE;
|
||||
}
|
||||
} else if (0 == strcasecmp(argv[i], "-wmaker")) {
|
||||
wmaker = TRUE;
|
||||
} else if (0 == strcasecmp(argv[i], "-vertical")) {
|
||||
horizontal = FALSE;
|
||||
} else if (0 == strcasecmp(argv[i], "-border")) {
|
||||
++i;
|
||||
|
||||
if (i < argc) {
|
||||
int b = atoi(argv[i]);
|
||||
if (b > 0) {
|
||||
border = b;
|
||||
} else {
|
||||
g_printerr("-border must be a value greater than 0\n");
|
||||
help = TRUE;
|
||||
}
|
||||
} else {
|
||||
g_printerr("-border requires a parameter\n");
|
||||
help = TRUE;
|
||||
}
|
||||
} else if (0 == strcasecmp(argv[i], "-iconsize")) {
|
||||
++i;
|
||||
if (i < argc) {
|
||||
int s = atoi(argv[i]);
|
||||
if (s > 0) {
|
||||
icon_size = s;
|
||||
} else {
|
||||
g_printerr("-iconsize must be a value greater than 0\n");
|
||||
help = TRUE;
|
||||
}
|
||||
} else {
|
||||
g_printerr("-iconsize requires a parameter\n");
|
||||
help = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (argv[i][0] == '-')
|
||||
help = TRUE;
|
||||
}
|
||||
|
||||
|
||||
if (help) {
|
||||
|
||||
g_print("%s - version %s\n", argv[0], VERSION);
|
||||
g_print("Copyright 2003, Ben Jansens <ben@orodu.net>\n\n");
|
||||
g_print("Usage: %s [OPTIONS]\n\n", argv[0]);
|
||||
g_print("Options:\n");
|
||||
g_print(" -help Show this help.\n");
|
||||
g_print(" -display DISLPAY The X display to connect to.\n");
|
||||
g_print(" -border The width of the border to put around the\n"
|
||||
" system tray icons. Defaults to 1.\n");
|
||||
g_print(" -vertical Line up the icons vertically. Defaults to\n"
|
||||
" horizontally.\n");
|
||||
g_print(" -wmaker WindowMaker mode. This makes docker a\n"
|
||||
" fixed size (64x64) to appear nicely in\n"
|
||||
" in WindowMaker.\n"
|
||||
" Note: In this mode, you have a fixed\n"
|
||||
" number of icons that docker can hold.\n");
|
||||
g_print(" -iconsize SIZE The size (width and height) to display\n"
|
||||
" icons as in the system tray. Defaults to\n"
|
||||
" 24.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void create_hint_win()
|
||||
{
|
||||
XWMHints hints;
|
||||
XClassHint classhints;
|
||||
|
||||
hint_win = XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0);
|
||||
assert(hint_win);
|
||||
|
||||
hints.flags = StateHint | WindowGroupHint | IconWindowHint;
|
||||
hints.initial_state = WithdrawnState;
|
||||
hints.window_group = hint_win;
|
||||
hints.icon_window = win;
|
||||
|
||||
classhints.res_name = "docker";
|
||||
classhints.res_class = "Docker";
|
||||
|
||||
XSetWMProperties(display, hint_win, NULL, NULL, argv, argc,
|
||||
NULL, &hints, &classhints);
|
||||
|
||||
XMapWindow(display, hint_win);
|
||||
}
|
||||
|
||||
|
||||
void create_main_window()
|
||||
{
|
||||
XWMHints hints;
|
||||
XTextProperty text;
|
||||
char *name = "Docker";
|
||||
|
||||
/* the border must be > 0 if not in wmaker mode */
|
||||
assert(wmaker || border > 0);
|
||||
|
||||
if (!wmaker)
|
||||
win = XCreateSimpleWindow(display, root, 0, 0,
|
||||
border * 2, border * 2, 0, 0, 0);
|
||||
else
|
||||
win = XCreateSimpleWindow(display, root, 0, 0,
|
||||
64, 64, 0, 0, 0);
|
||||
|
||||
assert(win);
|
||||
|
||||
XStringListToTextProperty(&name, 1, &text);
|
||||
XSetWMName(display, win, &text);
|
||||
|
||||
hints.flags = StateHint;
|
||||
hints.initial_state = WithdrawnState;
|
||||
XSetWMHints(display, win, &hints);
|
||||
|
||||
create_hint_win();
|
||||
|
||||
XSync(display, False);
|
||||
XSetWindowBackgroundPixmap(display, win, ParentRelative);
|
||||
XClearWindow(display, win);
|
||||
}
|
||||
|
||||
|
||||
void reposition_icons()
|
||||
{
|
||||
int x = border + ((width % icon_size) / 2),
|
||||
y = border + ((height % icon_size) / 2);
|
||||
GSList *it;
|
||||
|
||||
for (it = icons; it != NULL; it = g_slist_next(it)) {
|
||||
TrayWindow *traywin = it->data;
|
||||
traywin->x = x;
|
||||
traywin->y = y;
|
||||
XMoveWindow(display, traywin->id, x, y);
|
||||
XSync(display, False);
|
||||
if (wmaker) {
|
||||
x += icon_size;
|
||||
if (x + icon_size > width) {
|
||||
x = border;
|
||||
y += icon_size;
|
||||
}
|
||||
} else if (horizontal)
|
||||
x += icon_size;
|
||||
else
|
||||
y += icon_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fix_geometry()
|
||||
{
|
||||
GSList *it;
|
||||
|
||||
/* in wmaker mode we're a fixed size */
|
||||
if (wmaker) return;
|
||||
|
||||
/* find the proper width and height */
|
||||
width = horizontal ? 0 : icon_size;
|
||||
height = horizontal ? icon_size : 0;
|
||||
for (it = icons; it != NULL; it = g_slist_next(it)) {
|
||||
if (horizontal)
|
||||
width += icon_size;
|
||||
else
|
||||
height += icon_size;
|
||||
}
|
||||
|
||||
XResizeWindow(display, win, width + border * 2, height + border * 2);
|
||||
}
|
||||
|
||||
|
||||
void event_loop()
|
||||
{
|
||||
XEvent e;
|
||||
Window cover;
|
||||
GSList *it;
|
||||
|
||||
while (!exit_app) {
|
||||
while (XPending(display)) {
|
||||
XNextEvent(display, &e);
|
||||
|
||||
switch (e.type)
|
||||
{
|
||||
case PropertyNotify:
|
||||
/* systray window list has changed? */
|
||||
if (e.xproperty.atom == kde_systray_prop) {
|
||||
XSelectInput(display, win, NoEventMask);
|
||||
kde_update_icons();
|
||||
XSelectInput(display, win, StructureNotifyMask);
|
||||
|
||||
while (XCheckTypedEvent(display, PropertyNotify, &e));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
if (e.xany.window != win) {
|
||||
/* find the icon it pertains to and beat it into submission */
|
||||
GSList *it;
|
||||
|
||||
for (it = icons; it != NULL; it = g_slist_next(it)) {
|
||||
TrayWindow *traywin = it->data;
|
||||
if (traywin->id == e.xany.window) {
|
||||
XMoveResizeWindow(display, traywin->id, traywin->x, traywin->y,
|
||||
icon_size, icon_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* briefly cover the entire containing window, which causes it and
|
||||
all of the icons to refresh their windows. finally, they update
|
||||
themselves when the background of the main window's parent changes.
|
||||
*/
|
||||
cover = XCreateSimpleWindow(display, win, 0, 0,
|
||||
border * 2 + width, border * 2 + height,
|
||||
0, 0, 0);
|
||||
XMapWindow(display, cover);
|
||||
XDestroyWindow(display, cover);
|
||||
|
||||
break;
|
||||
|
||||
case ReparentNotify:
|
||||
if (e.xany.window == win) /* reparented to us */
|
||||
break;
|
||||
case UnmapNotify:
|
||||
case DestroyNotify:
|
||||
for (it = icons; it; it = g_slist_next(it)) {
|
||||
if (((TrayWindow*)it->data)->id == e.xany.window) {
|
||||
icon_remove(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ClientMessage:
|
||||
if (e.xclient.message_type == net_opcode_atom &&
|
||||
e.xclient.format == 32 &&
|
||||
e.xclient.window == net_sel_win)
|
||||
net_message(&e.xclient);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep(500000);
|
||||
}
|
||||
|
||||
/* remove/unparent all the icons */
|
||||
while (icons) {
|
||||
/* do the remove here explicitly, cuz the event handler isn't going to
|
||||
happen anymore. */
|
||||
icon_remove(icons);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
int main(int c, char **v)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
argc = c; argv = v;
|
||||
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
sigaction(SIGINT, &act, NULL);
|
||||
sigaction(SIGHUP, &act, NULL);
|
||||
|
||||
parse_cmd_line(argc, argv);
|
||||
|
||||
display = XOpenDisplay(display_string);
|
||||
if (!display) {
|
||||
g_printerr("Unable to open Display %s. Exiting.\n",
|
||||
DisplayString(display_string));
|
||||
}
|
||||
|
||||
root = RootWindow(display, DefaultScreen(display));
|
||||
assert(root);
|
||||
|
||||
if (wmaker)
|
||||
width = height = 64 - border * 2;
|
||||
|
||||
create_main_window();
|
||||
|
||||
// set up to find KDE systray icons, and get any that already exist
|
||||
kde_init();
|
||||
|
||||
net_init();
|
||||
|
||||
// we want to get ConfigureNotify events, and assume our parent's background
|
||||
// has changed when we do, so we need to refresh ourself to match
|
||||
XSelectInput(display, win, StructureNotifyMask);
|
||||
|
||||
event_loop();
|
||||
|
||||
XCloseDisplay(display);
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
31
src/systray/docker.h
Normal file
31
src/systray/docker.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __docker_h
|
||||
#define __docker_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
extern Display *display;
|
||||
extern Window root, win;
|
||||
extern GSList *icons;
|
||||
extern int width, height;
|
||||
extern int border;
|
||||
extern gboolean horizontal;
|
||||
extern int icon_size;
|
||||
extern gboolean wmaker;
|
||||
|
||||
typedef enum {
|
||||
KDE = 1, /* kde specific */
|
||||
NET /* follows the standard (freedesktop.org) */
|
||||
} TrayWindowType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TrayWindowType type;
|
||||
Window id;
|
||||
int x, y;
|
||||
} TrayWindow;
|
||||
|
||||
void reposition_icons();
|
||||
void fix_geometry();
|
||||
|
||||
#endif /* __docker_h */
|
||||
122
src/systray/icons.c
Normal file
122
src/systray/icons.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "icons.h"
|
||||
#include "net.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
gboolean error;
|
||||
int window_error_handler(Display *d, XErrorEvent *e)
|
||||
{
|
||||
d=d;e=e;
|
||||
if (e->error_code == BadWindow) {
|
||||
error = TRUE;
|
||||
} else {
|
||||
g_printerr("X ERROR NOT BAD WINDOW!\n");
|
||||
abort();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gboolean icon_swallow(TrayWindow *traywin)
|
||||
{
|
||||
XErrorHandler old;
|
||||
|
||||
error = FALSE;
|
||||
old = XSetErrorHandler(window_error_handler);
|
||||
XReparentWindow(display, traywin->id, win, 0, 0);
|
||||
XSync(display, False);
|
||||
XSetErrorHandler(old);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The traywin must have its id and type set.
|
||||
*/
|
||||
gboolean icon_add(Window id, TrayWindowType type)
|
||||
{
|
||||
TrayWindow *traywin;
|
||||
|
||||
assert(id);
|
||||
assert(type);
|
||||
|
||||
if (wmaker) {
|
||||
/* do we have room in our window for another icon? */
|
||||
unsigned int max = (width / icon_size) * (height / icon_size);
|
||||
if (g_slist_length(icons) >= max)
|
||||
return FALSE; /* no room, sorry! REJECTED! */
|
||||
}
|
||||
|
||||
traywin = g_new0(TrayWindow, 1);
|
||||
traywin->type = type;
|
||||
traywin->id = id;
|
||||
|
||||
if (!icon_swallow(traywin)) {
|
||||
g_free(traywin);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* find the positon for the systray app window */
|
||||
if (!wmaker) {
|
||||
traywin->x = border + (horizontal ? width : 0);
|
||||
traywin->y = border + (horizontal ? 0 : height);
|
||||
} else {
|
||||
int count = g_slist_length(icons);
|
||||
traywin->x = border + ((width % icon_size) / 2) +
|
||||
(count % (width / icon_size)) * icon_size;
|
||||
traywin->y = border + ((height % icon_size) / 2) +
|
||||
(count / (height / icon_size)) * icon_size;
|
||||
}
|
||||
|
||||
/* add the new icon to the list */
|
||||
icons = g_slist_append(icons, traywin);
|
||||
|
||||
/* watch for the icon trying to resize itself! BAD ICON! BAD! */
|
||||
XSelectInput(display, traywin->id, StructureNotifyMask);
|
||||
|
||||
/* position and size the icon window */
|
||||
XMoveResizeWindow(display, traywin->id,
|
||||
traywin->x, traywin->y, icon_size, icon_size);
|
||||
|
||||
/* resize our window so that the new window can fit in it */
|
||||
fix_geometry();
|
||||
|
||||
/* flush before clearing, otherwise the clear isn't effective. */
|
||||
XFlush(display);
|
||||
/* make sure the new child will get the right stuff in its background
|
||||
for ParentRelative. */
|
||||
XClearWindow(display, win);
|
||||
|
||||
/* show the window */
|
||||
XMapRaised(display, traywin->id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void icon_remove(GSList *node)
|
||||
{
|
||||
XErrorHandler old;
|
||||
TrayWindow *traywin = node->data;
|
||||
Window traywin_id = traywin->id;
|
||||
|
||||
if (traywin->type == NET)
|
||||
net_icon_remove(traywin);
|
||||
|
||||
XSelectInput(display, traywin->id, NoEventMask);
|
||||
|
||||
/* remove it from our list */
|
||||
g_free(node->data);
|
||||
icons = g_slist_remove_link(icons, node);
|
||||
|
||||
/* reparent it to root */
|
||||
error = FALSE;
|
||||
old = XSetErrorHandler(window_error_handler);
|
||||
XReparentWindow(display, traywin_id, root, 0, 0);
|
||||
XSync(display, False);
|
||||
XSetErrorHandler(old);
|
||||
|
||||
reposition_icons();
|
||||
fix_geometry();
|
||||
}
|
||||
13
src/systray/icons.h
Normal file
13
src/systray/icons.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __icons_h
|
||||
#define __icons_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include "docker.h"
|
||||
|
||||
extern gboolean error;
|
||||
|
||||
gboolean icon_add(Window id, TrayWindowType type);
|
||||
void icon_remove(GSList *node);
|
||||
|
||||
#endif /* __icons_h */
|
||||
76
src/systray/kde.c
Normal file
76
src/systray/kde.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "kde.h"
|
||||
#include "icons.h"
|
||||
#include "docker.h"
|
||||
#include "xproperty.h"
|
||||
#include <assert.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
Atom kde_systray_prop = None;
|
||||
|
||||
void kde_init()
|
||||
{
|
||||
kde_systray_prop = XInternAtom(display,
|
||||
"_KDE_NET_SYSTEM_TRAY_WINDOWS", False);
|
||||
assert(kde_systray_prop);
|
||||
|
||||
XSelectInput(display, root, PropertyChangeMask);
|
||||
kde_update_icons();
|
||||
}
|
||||
|
||||
void kde_update_icons()
|
||||
{
|
||||
gulong count = (unsigned) -1; /* grab as many as possible */
|
||||
Window *ids;
|
||||
unsigned int i;
|
||||
GSList *it, *next;
|
||||
gboolean removed = FALSE; /* were any removed? */
|
||||
|
||||
if (! xprop_get32(root, kde_systray_prop, XA_WINDOW, sizeof(Window)*8,
|
||||
&count, &ids))
|
||||
return;
|
||||
|
||||
/* add new windows to our list */
|
||||
for (i = 0; i < count; ++i) {
|
||||
for (it = icons; it != NULL; it = g_slist_next(it)) {
|
||||
TrayWindow *traywin = it->data;
|
||||
if (traywin->id == ids[i])
|
||||
break;
|
||||
}
|
||||
if (!it)
|
||||
icon_add(ids[i], KDE);
|
||||
}
|
||||
|
||||
/* remove windows from our list that no longer exist in the property */
|
||||
for (it = icons; it != NULL;) {
|
||||
TrayWindow *traywin = it->data;
|
||||
gboolean exists;
|
||||
|
||||
if (traywin->type != KDE) {
|
||||
/* don't go removing non-kde windows */
|
||||
exists = TRUE;
|
||||
} else {
|
||||
exists = FALSE;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (traywin->id == ids[i]) {
|
||||
exists = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next = g_slist_next(it);
|
||||
if (!exists) {
|
||||
icon_remove(it);
|
||||
removed =TRUE;
|
||||
}
|
||||
it = next;
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
/* at least one tray app was removed, so reorganize 'em all and resize*/
|
||||
reposition_icons();
|
||||
fix_geometry();
|
||||
}
|
||||
|
||||
XFree(ids);
|
||||
}
|
||||
12
src/systray/kde.h
Normal file
12
src/systray/kde.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __kde_h
|
||||
#define __kde_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
extern Atom kde_systray_prop;
|
||||
|
||||
void kde_update_icons();
|
||||
void kde_init();
|
||||
|
||||
#endif /* __kde_h */
|
||||
119
src/systray/net.c
Normal file
119
src/systray/net.c
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "net.h"
|
||||
#include "docker.h"
|
||||
#include "icons.h"
|
||||
#include <assert.h>
|
||||
|
||||
Atom net_opcode_atom;
|
||||
Window net_sel_win;
|
||||
|
||||
static Atom net_sel_atom;
|
||||
static Atom net_manager_atom;
|
||||
static Atom net_message_data_atom;
|
||||
|
||||
/* defined in the systray spec */
|
||||
#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
|
||||
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
|
||||
|
||||
static void net_create_selection_window()
|
||||
{
|
||||
net_sel_win = XCreateSimpleWindow(display, root, -1, -1, 1, 1, 0, 0, 0);
|
||||
assert(net_sel_win);
|
||||
}
|
||||
|
||||
|
||||
static void net_destroy_selection_window()
|
||||
{
|
||||
XDestroyWindow(display, net_sel_win);
|
||||
net_sel_win = None;
|
||||
}
|
||||
|
||||
|
||||
void net_init()
|
||||
{
|
||||
char *name;
|
||||
XEvent m;
|
||||
|
||||
name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", DefaultScreen(display));
|
||||
net_sel_atom = XInternAtom(display, name, False);
|
||||
assert(net_sel_atom);
|
||||
net_opcode_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False);
|
||||
assert(net_opcode_atom);
|
||||
net_manager_atom = XInternAtom(display, "MANAGER", False);
|
||||
assert(net_manager_atom);
|
||||
net_message_data_atom = XInternAtom(display, "_NET_SYSTEM_TRAY_MESSAGE_DATA",
|
||||
False);
|
||||
assert(net_message_data_atom);
|
||||
|
||||
net_create_selection_window();
|
||||
|
||||
XSetSelectionOwner(display, net_sel_atom, net_sel_win, CurrentTime);
|
||||
if (XGetSelectionOwner(display, net_sel_atom) != net_sel_win)
|
||||
return; /* we don't get the selection */
|
||||
|
||||
m.type = ClientMessage;
|
||||
m.xclient.message_type = net_manager_atom;
|
||||
m.xclient.format = 32;
|
||||
m.xclient.data.l[0] = CurrentTime;
|
||||
m.xclient.data.l[1] = net_sel_atom;
|
||||
m.xclient.data.l[2] = net_sel_win;
|
||||
m.xclient.data.l[3] = 0;
|
||||
m.xclient.data.l[4] = 0;
|
||||
XSendEvent(display, root, False, StructureNotifyMask, &m);
|
||||
}
|
||||
|
||||
|
||||
void net_destroy()
|
||||
{
|
||||
net_destroy_selection_window();
|
||||
}
|
||||
|
||||
|
||||
void net_message(XClientMessageEvent *e)
|
||||
{
|
||||
unsigned long opcode;
|
||||
Window id;
|
||||
|
||||
assert(e);
|
||||
|
||||
opcode = e->data.l[1];
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case SYSTEM_TRAY_REQUEST_DOCK: /* dock a new icon */
|
||||
id = e->data.l[2];
|
||||
if (id && icon_add(id, NET))
|
||||
XSelectInput(display, id, StructureNotifyMask);
|
||||
break;
|
||||
|
||||
case SYSTEM_TRAY_BEGIN_MESSAGE:
|
||||
g_printerr("Message From Dockapp\n");
|
||||
id = e->window;
|
||||
break;
|
||||
|
||||
case SYSTEM_TRAY_CANCEL_MESSAGE:
|
||||
g_printerr("Message Cancelled\n");
|
||||
id = e->window;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (opcode == net_message_data_atom) {
|
||||
g_printerr("Text For Message From Dockapp:\n%s\n", e->data.b);
|
||||
id = e->window;
|
||||
break;
|
||||
}
|
||||
|
||||
/* unknown message type. not in the spec. */
|
||||
g_printerr("Warning: Received unknown client message to System Tray "
|
||||
"selection window.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void net_icon_remove(TrayWindow *traywin)
|
||||
{
|
||||
assert(traywin);
|
||||
|
||||
XSelectInput(display, traywin->id, NoEventMask);
|
||||
}
|
||||
15
src/systray/net.h
Normal file
15
src/systray/net.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __net_h
|
||||
#define __net_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include "docker.h"
|
||||
|
||||
extern Window net_sel_win;
|
||||
extern Atom net_opcode_atom;
|
||||
|
||||
void net_init();
|
||||
void net_message(XClientMessageEvent *e);
|
||||
void net_icon_remove(TrayWindow *traywin);
|
||||
|
||||
#endif /* __net_h */
|
||||
21
src/systray/tint_merge.h
Normal file
21
src/systray/tint_merge.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/**************************************************************************
|
||||
* Copyright (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr)
|
||||
*
|
||||
* Merge 'docker' with 'tint2'.
|
||||
* The goal is to keep unchanged docker code, but without data duplication.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef TINT_MERGE_H
|
||||
#define TINT_MERGE_H
|
||||
|
||||
#define display server.dsp
|
||||
#define root server.root_win
|
||||
|
||||
/* delete main(), parse_cmd_line() and display_string from docker.c
|
||||
* include "tint_merge.h" in docker.h
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1
src/systray/version.h
Normal file
1
src/systray/version.h
Normal file
@@ -0,0 +1 @@
|
||||
#define VERSION "1.5"
|
||||
1
src/systray/version.h.in
Normal file
1
src/systray/version.h.in
Normal file
@@ -0,0 +1 @@
|
||||
#define VERSION "@VERSION@"
|
||||
64
src/systray/xproperty.c
Normal file
64
src/systray/xproperty.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "xproperty.h"
|
||||
#include "docker.h"
|
||||
|
||||
gboolean xprop_get8(Window window, Atom atom, Atom type, int size,
|
||||
gulong *count, guchar **value)
|
||||
{
|
||||
Atom ret_type;
|
||||
int ret_size;
|
||||
unsigned long ret_bytes;
|
||||
int result;
|
||||
unsigned long nelements = *count;
|
||||
unsigned long maxread = nelements;
|
||||
|
||||
*value = NULL;
|
||||
|
||||
/* try get the first element */
|
||||
result = XGetWindowProperty(display, window, atom, 0l, 1l, False,
|
||||
AnyPropertyType, &ret_type, &ret_size,
|
||||
&nelements, &ret_bytes, value);
|
||||
if (! (result == Success && ret_type == type &&
|
||||
ret_size == size && nelements > 0)) {
|
||||
if (*value) XFree(*value);
|
||||
*value = NULL;
|
||||
nelements = 0;
|
||||
} else {
|
||||
/* we didn't the whole property's value, more to get */
|
||||
if (! (ret_bytes == 0 || maxread <= nelements)) {
|
||||
int remain;
|
||||
|
||||
/* get the entire property since it is larger than one element long */
|
||||
XFree(*value);
|
||||
/*
|
||||
the number of longs that need to be retreived to get the property's
|
||||
entire value. The last + 1 is the first long that we retrieved above.
|
||||
*/
|
||||
remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
|
||||
/* dont get more than the max */
|
||||
if (remain > size/8 * (signed)maxread)
|
||||
remain = size/8 * (signed)maxread;
|
||||
result = XGetWindowProperty(display, window, atom, 0l, remain,
|
||||
False, type, &ret_type, &ret_size,
|
||||
&nelements, &ret_bytes, value);
|
||||
/*
|
||||
If the property has changed type/size, or has grown since our first
|
||||
read of it, then stop here and try again. If it shrank, then this will
|
||||
still work.
|
||||
*/
|
||||
if (!(result == Success && ret_type == type &&
|
||||
ret_size == size && ret_bytes == 0)) {
|
||||
if (*value) XFree(*value);
|
||||
xprop_get8(window, atom, type, size, count, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*count = nelements;
|
||||
return *value != NULL;
|
||||
}
|
||||
|
||||
gboolean xprop_get32(Window window, Atom atom, Atom type, int size,
|
||||
gulong *count, gulong **value)
|
||||
{
|
||||
return xprop_get8(window, atom, type, size, count, (guchar**)value);
|
||||
}
|
||||
13
src/systray/xproperty.h
Normal file
13
src/systray/xproperty.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __xproperty_h
|
||||
#define __xproperty_h
|
||||
|
||||
#include <glib.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/* if the func returns TRUE, the returned value must be XFree()'d */
|
||||
gboolean xprop_get8(Window window, Atom atom, Atom type, int size,
|
||||
gulong *count, guchar **value);
|
||||
gboolean xprop_get32(Window window, Atom atom, Atom type, int size,
|
||||
gulong *count, gulong **value);
|
||||
|
||||
#endif /* __xproperty_h */
|
||||
Reference in New Issue
Block a user