Hi all, I'm not that good at libtool-stuff, so I need some help at merging the pager into sawfish (need to adjust the path to client.so *after* compilation and before/while install). First grab the pager.jl from the sawfish-pager-0.7 package (see sourceforge.net), then grab the pager.c attached and place into sawfishs src/ directory, the last step is to apply the src_mk_patch. so we compile and install `pager' correctly, but the path to client.so needs to be adjusted to `$(shell pkg-config --variable=repcommonexecdir librep)/sawfish/client.so' or if you know a better way, you're welcome, too :) Thanks in advance, Chris
diff --git a/src/Makefile.in b/src/Makefile.in
index b7b2d91..b4edb3d 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -38,9 +38,10 @@ DL_DSTS = sawfish/wm/util/gradient.la sawfish/wm/util/flippers.la \
sawfish/wm/util/play-sample.la
DL_DIRS = sawfish/wm/util
+PAGER_LDFLAGS = $(LDFLAGS) $(srcdir)/src/.libs/client.so
override CFLAGS := $(CFLAGS) $(REP_CFLAGS) $(IMAGE_CFLAGS) $(X11_CFLAGS) $(ESD_CFLAGS) $(PANGO_CFLAGS)
-all : sawfish libclient.o $(DL_OBJS) .libexec gtk-style
+all : sawfish libclient.o $(DL_OBJS) .libexec gtk-style pager
sawfish : $(OBJS) $(LIBOBJS)
$(rep_LIBTOOL) --mode=link --tag=CC $(CC) -export-dynamic $(LDFLAGS) \
@@ -62,11 +63,15 @@ client.la : client.lo libclient_.lo
gtk-style : gtk-style.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(GTK_CFLAGS) $(LDFLAGS) -o $@ $< $(GTK_LIBS) $(LIBS)
+pager : pager.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(GTK_CFLAGS) $(PAGER_LDFLAGS) -o $@ $< $(GTK_LIBS) $(LIBS)
+
install : all installdirs
for p in sawfish; do \
$(rep_LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)${bindir}; \
done
$(rep_DL_INSTALL) gtk-style $(DESTDIR)${sawfishexecdir}
+ $(rep_DL_INSTALL) pager $(DESTDIR)${sawfishexecdir}
$(foreach x,$(DL_DSTS),\
$(rep_LIBTOOL) --mode=install $(INSTALL_PROGRAM) \
$(notdir $(x)) $(DESTDIR)$(sawfishexecdir)/$(dir $(x));)
@@ -97,7 +102,7 @@ clean :
distclean: realclean
realclean : clean
- rm -f .*.d sawfish sawfish-about.jl Makefile gtk-style
+ rm -f .*.d sawfish sawfish-about.jl Makefile gtk-style pager
rm -rf .libs
-include $(SRCS:%.c=.%.d) $(DL_SRCS:%.c=.%.d)
/* pager.c -- The display program of sawfish.wm.ext.pager
Copyright (C) 2009 Christopher Bratusek <zanghar freenet de>
Copyright (C) 2007 Janek Kozicki <janek_listy wp pl>
Copyright (C) 2002 Daniel Pfeiffer <occitan esperanto org>
Copyright (C) 2000 Satyaki Das <satyaki theforce stanford edu>
Hakon Alstadheim
This file is part of sawfish.
sawfish 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.
sawfish 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 sawfish; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "libclient.h"
enum { bg, hilit_bg, win, focus_win, win_border, vp_divider, ws_divider, vp_frame };
int hatch = 0;
int xmark = 0;
GdkColor colors[ws_divider+1];
GdkGC *gc[vp_frame+1];
GdkColormap *cmap = NULL;
GdkPixmap *background = NULL;
GdkPixmap *pixmap = NULL;
GtkWidget *drawing_area;
GtkWidget *window;
GdkRectangle update_rect;
/* can read this many chars, truncate beyond */
#define MAXSTRING 2048
char bg_filename[MAXSTRING] = "";
/* can display this many, including all instances of stickies */
#define MAXWINDOWS 1024
struct {
long id;
GdkRectangle w, c; /* window and clip area */
} windows[MAXWINDOWS], *lowest, *w, *dragged_window, *tooltip_window;
int vp_width, vp_height, ws_width, ws_height, width, height;
int offset_x, offset_y;
int show_all_ws, ws_x, ws_y, vp_x, vp_y;
long focus_id;
int mouse_x = -1;
int mouse_y = -1;
gint delete_event( GtkWidget *, GdkEvent *, gpointer );
gint destroy_event( GtkWidget *, GdkEvent *, gpointer );
gint configure_event( GtkWidget *, GdkEvent *, gpointer );
gint leave_notify_event( GtkWidget *, GdkEvent *, gpointer );
gint expose_event( GtkWidget *, GdkEventExpose *, gpointer );
gint button_press_event( GtkWidget *, GdkEventButton *, gpointer );
gint button_release_event( GtkWidget *, GdkEventButton *, gpointer );
gint motion_notify_event( GtkWidget *, GdkEventMotion *, gpointer );
void
wait_stdin( gpointer, gint, GdkInputCondition );
void make_background( void );
void draw_pager( GtkWidget * );
gint draw_tooltip( void );
void parse_stdin( void );
void send_command( char *cmd );
static void wmspec_change_state( gboolean , GdkWindow *, GdkAtom , GdkAtom );
int main( int argc, char *argv[] )
{
GtkWidget *vbox;
gtk_init( &argc, &argv );
if( client_open( NULL ) )
exit( 1 );
atexit( client_close );
window = argc == 2 ?
gtk_plug_new( strtol( argv[1], NULL, 10 )) :
gtk_window_new( GTK_WINDOW_TOPLEVEL );
vbox = gtk_vbox_new( FALSE, 0 );
gtk_container_add( GTK_CONTAINER( window ), vbox );
drawing_area = gtk_drawing_area_new();
/* Get the dimensions and colors of the pager and viewport and focus */
parse_stdin();
update_rect.x = update_rect.y = 0;
gtk_drawing_area_size( GTK_DRAWING_AREA( drawing_area ), width, height );
gtk_box_pack_start( GTK_BOX( vbox ), drawing_area, FALSE, FALSE, 0 );
/* Signals to quit */
gtk_signal_connect( GTK_OBJECT( window ), "delete_event",
GTK_SIGNAL_FUNC( delete_event ), NULL );
gtk_signal_connect( GTK_OBJECT( window ), "destroy",
GTK_SIGNAL_FUNC( destroy_event ), NULL );
/* Wait for input from standard input */
gdk_input_add( 0, GDK_INPUT_READ,
&wait_stdin,
drawing_area );
/* Change the viewport when a button is pressed */
gtk_signal_connect( GTK_OBJECT( drawing_area ), "motion_notify_event",
(GtkSignalFunc) motion_notify_event, NULL );
gtk_signal_connect( GTK_OBJECT( drawing_area ), "button_press_event",
(GtkSignalFunc) button_press_event, NULL );
gtk_signal_connect( GTK_OBJECT( drawing_area ), "button_release_event",
(GtkSignalFunc) button_release_event, NULL );
gtk_signal_connect( GTK_OBJECT( drawing_area ), "leave_notify_event",
(GtkSignalFunc) leave_notify_event, NULL );
gtk_widget_set_events( drawing_area, GDK_EXPOSURE_MASK
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK );
/* Initialize and draw the pixmap */
gtk_signal_connect( GTK_OBJECT( drawing_area ), "expose_event",
(GtkSignalFunc) expose_event, NULL );
gtk_signal_connect( GTK_OBJECT( drawing_area ), "configure_event",
(GtkSignalFunc) configure_event, NULL );
gtk_widget_show( drawing_area );
gtk_widget_show( vbox );
wmspec_change_state(TRUE, window->window,
gdk_atom_intern( "_NET_WM_STATE_SKIP_PAGER", FALSE ),
gdk_atom_intern( "_NET_WM_STATE_SKIP_TASKBAR", FALSE ));
gtk_widget_show( window );
gtk_main();
return 0;
}
inline void send_command( char *cmd )
{
int rv;
client_eval( cmd, NULL, &rv );
}
inline gint find_w( int x, int y ) {
for( w = windows; w <= lowest; w++ )
if( w->w.x <= x && w->w.x + w->w.width > x &&
w->w.y <= y && w->w.y + w->w.height > y )
return TRUE;
return FALSE;
}
inline void box( int color, gint filled,
gint x, gint y, gint width, gint height )
{
gdk_draw_rectangle( pixmap, gc[color], filled, x, y, width, height );
}
inline void clipbox( int color, gint filled,
gint x, gint y, gint width, gint height,
GdkRectangle *c )
{
if(width < 0 || height < 0)
return;
gdk_gc_set_clip_rectangle( gc[color], c );
gdk_draw_rectangle( pixmap, gc[color], filled, x, y, width, height );
}
gint expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer data )
{
gdk_draw_pixmap( widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE( widget )],
pixmap,
0, 0, 0, 0,
width, height );
return TRUE;
}
gint leave_notify_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
if( !dragged_window ) {
mouse_x = width;
mouse_y = height;
draw_tooltip();
}
return TRUE;
}
gint button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer d )
{
char cmd[64];
int x, y;
mouse_x = x = (int) event->x;
mouse_y = y = (int) event->y;
if( !(x % ws_width) || !(y % ws_height) ) /* WS border */
return TRUE;
/* Button1 changes viewport */
if( event->button == 1 ) {
sprintf( cmd, "(pager-goto %ld %d %d)", find_w( x, y ) ? w->id : 0, x, y );
send_command( cmd );
draw_tooltip();
}
/* Button2 raises/lowers current window */
else if( event->button == 2 && find_w( x, y ) ) {
sprintf( cmd, "(pager-change-depth %ld)", w->id );
send_command( cmd );
draw_tooltip();
}
/* Button3 is for dragging the selected window */
else if( event->button == 3 && find_w( x, y ) ) {
draw_tooltip();
dragged_window = w;
/* Offset of top left from cursor */
offset_x = x - w->w.x;
offset_y = y - w->w.y;
}
return TRUE;
}
gint motion_notify_event( GtkWidget *widget, GdkEventMotion *event, gpointer d )
{
GdkModifierType state;
if( event->is_hint )
gdk_window_get_pointer( event->window, &mouse_x, &mouse_y, &state );
else {
mouse_x = event->x;
mouse_y = event->y;
state = event->state;
}
if( dragged_window && state & GDK_BUTTON3_MASK ) {
char cmd[64];
sprintf( cmd, "(pager-move-window %ld %d %d %d %d %d %d)",
dragged_window->id, mouse_x-offset_x, mouse_y-offset_y,
dragged_window->w.width, dragged_window->w.height,
mouse_x, mouse_y );
send_command( cmd );
} else
draw_tooltip();
return TRUE;
}
gint button_release_event( GtkWidget *widget, GdkEventButton *event, gpointer d )
{
if( dragged_window && event->button == 3 ) {
int x = (int) event->x;
int y = (int) event->y;
char cmd[64];
sprintf( cmd, "(pager-move-window %ld %d %d %d %d %d %d)",
dragged_window->id, x-offset_x, y-offset_y,
dragged_window->w.width, dragged_window->w.height,
x, y );
send_command( cmd );
dragged_window = NULL;
}
return TRUE;
}
gint configure_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
int i;
if( pixmap ) {
gdk_pixmap_unref( pixmap );
for( i = bg; i <= vp_frame; i++ )
gdk_gc_unref( gc[i] );
}
pixmap = gdk_pixmap_new( widget->window, width, height, -1 );
for( i = bg; i <= ws_divider; i++ )
gdk_gc_set_foreground( gc[i] = gdk_gc_new( pixmap ), &colors[i] );
/* wishing for a nicer line style, like 3 on, 5 off, making this alternate for neighbouring VPs */
gdk_gc_set_line_attributes( gc[vp_divider], 1, GDK_LINE_ON_OFF_DASH,
GDK_CAP_ROUND, GDK_JOIN_ROUND );
gdk_gc_set_foreground( gc[vp_frame] = gdk_gc_new( pixmap ), &colors[vp_divider] );
gdk_gc_set_line_attributes( gc[vp_frame], 1, GDK_LINE_ON_OFF_DASH,
GDK_CAP_ROUND, GDK_JOIN_ROUND );
/* wishing for Gimp-style functions -- GDK is just too primitive */
/* gdk_gc_set_function( gc[vp_frame], GDK_XOR ); */
make_background();
draw_pager( widget );
return TRUE;
}
void make_background()
{
if( background )
gdk_pixmap_unref( background );
if( ! (*bg_filename &&
(background = gdk_pixmap_create_from_xpm( window->window, NULL, NULL, bg_filename ))) )
{
int i, j;
background = gdk_pixmap_new( window->window, ws_width, ws_height, -1 );
gdk_draw_rectangle( background, gc[bg], TRUE, 1, 1, ws_width, ws_height );
/* draw the boundaries of the different viewports */
if( vp_width < ws_width-1 || vp_height < ws_height-1 )
for( i=1; i<ws_width; i+=vp_width )
for( j=1; j<ws_height; j+=vp_height )
gdk_draw_rectangle( background, gc[vp_divider], FALSE,
i+1, j+1, vp_width-3, vp_height-3 );
/* draw the workspace-boundary (repeated by tiling) */
gdk_draw_line( background, gc[ws_divider], 0, 0, 0, ws_height );
gdk_draw_line( background, gc[ws_divider], 1, 0, ws_width, 0 );
}
gdk_gc_set_fill( gc[bg], GDK_TILED );
gdk_gc_set_tile( gc[bg], background );
}
void draw_pager( GtkWidget *widget )
{
if( show_all_ws )
box( bg, TRUE, 0, 0, width, height );
else
box( bg, TRUE, -ws_x, -ws_y, width+ws_x, height+ws_y );
/* highlight the current viewport with color hilit background */
if(xmark ==0)
box( hilit_bg, TRUE, vp_x, vp_y, vp_width, vp_height );
/* draw the windows */
if(hatch == 0)
{
for( w = lowest; w >= windows; w-- ) {
clipbox( (w->id == focus_id) ? focus_win : win, TRUE,
w->w.x+1, w->w.y+1, w->w.width-2, w->w.height-2, &w->c );
clipbox( win_border, FALSE,
w->w.x, w->w.y, w->w.width-1, w->w.height-1, &w->c );
}
} else {
for( w = lowest; w >= windows; w-- ) {
int i;
if(w->id == focus_id)
{
for(i=((w->w.width > w->w.height)?w->w.width:w->w.height)>>1; i>=1 ; i-=2)
clipbox(focus_win, FALSE, w->w.x+i, w->w.y+1, w->w.width-1-(i<<1), w->w.height-1, &w->c );
} else {
for(i=((w->w.width > w->w.height)?w->w.width:w->w.height)>>1; i>=1 ; i-=2)
clipbox(win, FALSE, w->w.x+1, w->w.y+i, w->w.width-1, w->w.height-1-(i<<1), &w->c );
}
/* for(i=((w->w.width > w->w.height)?w->w.width:w->w.height)>>1; i>=1 ; i-=2)
clipbox( (w->id == focus_id) ? focus_win : win, FALSE, w->w.x+i, w->w.y+i, w->w.width-1-(i<<1), w->w.height-1-(i<<1), &w->c );
clipbox( (w->id == focus_id) ? focus_win : win, FALSE, w->w.x+1, w->w.y+1, w->w.width-3, w->w.height-3, &w->c );
clipbox( (w->id == focus_id) ? focus_win : win, FALSE, w->w.x+2, w->w.y+2, w->w.width-5, w->w.height-5, &w->c );
clipbox( (w->id == focus_id) ? focus_win : win, FALSE, w->w.x+3, w->w.y+3, w->w.width-7, w->w.height-7, &w->c ); */
clipbox( win_border, FALSE, w->w.x, w->w.y, w->w.width-1, w->w.height-1, &w->c );
}
}
/* frame the current viewport above all else in case it's covered */
if( vp_width < ws_width-1 || vp_height < ws_height-1 )
{
if(xmark == 0)
{
box( vp_frame, FALSE, vp_x, vp_y, vp_width-1, vp_height-1 );
} else
{
/* box( vp_frame, FALSE, vp_x+1, vp_y+1, vp_width-3, vp_height-3 ); */
box( hilit_bg, FALSE, vp_x, vp_y, vp_width-1, vp_height-1 );
gdk_draw_line(pixmap,gc[hilit_bg],vp_x , vp_y + 2 , vp_width-1 + vp_x - 2, vp_height-1 + vp_y );
gdk_draw_line(pixmap,gc[hilit_bg],vp_x , vp_height-1 + vp_y - 2 , vp_width-1 + vp_x - 2, vp_y );
gdk_draw_line(pixmap,gc[hilit_bg],vp_x + 2, vp_y , vp_width-1 + vp_x , vp_height-1 + vp_y - 2);
gdk_draw_line(pixmap,gc[hilit_bg],vp_x + 2, vp_height-1 + vp_y , vp_width-1 + vp_x , vp_y + 2);
}
}
gtk_widget_draw( widget, &update_rect );
}
gint draw_tooltip()
{
if( find_w( mouse_x, mouse_y )) {
if( w != tooltip_window ) {
char cmd[64];
tooltip_window = w;
sprintf( cmd, "(pager-tooltip %ld)", w->id );
send_command( cmd );
}
return TRUE;
} else if( tooltip_window )
send_command( "(pager-tooltip)" );
tooltip_window = NULL;
return FALSE;
}
char get_char( int must )
{
static char buffer[MAXSTRING];
static char *ptr = buffer;
static int n = 0;
if( ++ptr < buffer + n )
return *ptr;
else if( must ) {
n = read( 0, buffer, MAXSTRING );
if( n < 1 )
exit( 1 );
return *(ptr = buffer);
} else {
/* input waiting? */
fd_set rfds;
struct timeval tv;
FD_ZERO( &rfds );
FD_SET( 0, &rfds );
tv.tv_sec = tv.tv_usec = 0;
if( select( 1, &rfds, NULL, NULL, &tv ) ) {
n = read( 0, buffer, MAXSTRING );
if( n < 1 )
exit( 1 );
return *(ptr = buffer);
} else
return '\0';
}
}
int last;
long get_number()
{
char buffer;
long number = 0;
int sign = 1;
while( (buffer = get_char( 1 )) ) {
if( buffer >= '0' && buffer <= '9' )
number = number * 10 + buffer - '0';
else if( (last = (buffer == '\n')) || buffer == ' ' ) {
if( sign == -1 )
number = -number;
break;
} else if( buffer == '-' )
sign = -1;
}
return number;
}
void get_string( char *buffer )
{
char *ptr = buffer;
while( (*ptr = get_char( 1 )) )
if( *ptr == '\n' )
break;
else if( ptr < buffer + MAXSTRING - 1 )
ptr++;
*ptr = '\0';
}
void get_rect( GdkRectangle *r )
{
r->x = get_number();
r->y = get_number();
r->width = get_number();
r->height = get_number();
}
/* This reads and returns the type of the data:
* W - regular info about what to display
* s - size info to resize the window
* b - background image file
* c - color change
* w - info about one window
* f - focus change
* H - hatching
* X - draw X-es
*/
void parse_stdin()
{
long i;
int repeat, more = 0;
while( 1 )
switch( get_char( ! more++ ) ) {
case 'f':
focus_id = get_number();
break;
case 'v':
ws_x = get_number();
ws_y = get_number();
vp_x = ws_x + get_number();
vp_y = ws_y + get_number();
break;
case 'W':
last = 0;
lowest = windows - 1;
while( !last ) {
if( lowest >= windows + MAXWINDOWS )
get_number(); /* flush input in excess of MAXWINDOWS */
else if( ((lowest+1)->id = get_number()) ) {
get_rect( &(++lowest)->w );
get_rect( &lowest->c );
}
}
break;
case 'w':
/* should never get here for an unknown window */
i = get_number();
for( w = lowest; w >= windows; w-- ) {
if( w->id == i ) {
get_rect( &w->w );
get_rect( &w->c );
break;
}
}
break;
case 'h':
hatch = get_number(); // this number is a 0 or 1
break;
case 'x':
xmark = get_number(); // this number is a 0 or 1
break;
case 's':
show_all_ws = get_number();
vp_width = get_number();
vp_height = get_number();
ws_width = get_number();
ws_height = get_number();
width = update_rect.width = get_number() + 1;
height = update_rect.height = get_number() + 1;
/* Initialize the picture */
gdk_window_resize( window->window, width, height );
gtk_drawing_area_size( GTK_DRAWING_AREA( drawing_area ), width, height );
break;
case 'b':
get_string( bg_filename );
if( pixmap )
make_background();
break;
case 'c':
repeat = (cmap != NULL);
cmap = gdk_colormap_get_system();
for( i = bg; i <= ws_divider; i++ ) {
if( repeat )
gdk_colormap_free_colors( cmap, &colors[i], 1 );
colors[i].red = get_number();
colors[i].green = get_number();
colors[i].blue = get_number();
gdk_color_alloc( cmap, &colors[i] );
}
break;
case '\0':
return;
}
}
void
wait_stdin( gpointer data, gint source, GdkInputCondition cond )
{
parse_stdin();
draw_pager( data );
draw_tooltip();
}
gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
return FALSE;
}
gint destroy_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
gtk_main_quit();
return FALSE;
}
/* This function is borrowed from galeon's source */
static void wmspec_change_state( gboolean add, GdkWindow *window,
GdkAtom state1, GdkAtom state2 )
{
XEvent xev;
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.display = gdk_display;
xev.xclient.window = GDK_WINDOW_XID (window);
xev.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
xev.xclient.format = 32;
xev.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
xev.xclient.data.l[1] = gdk_x11_atom_to_xatom (state1);
xev.xclient.data.l[2] = gdk_x11_atom_to_xatom (state2);
XSendEvent(gdk_display, GDK_WINDOW_XID (gdk_get_default_root_window ()),
False, SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
Attachment:
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil