From cfc7dff206b37dc699d47705d39cdc95218b9cf7 Mon Sep 17 00:00:00 2001 From: Matthew Campbell Date: Sat, 3 Aug 2013 12:29:31 -0400 Subject: [PATCH] Squashed commit of the following: commit 80a7a2b3d0b6312dda339e49bed31762437ad0d3 Author: Matthew Campbell Date: Fri Aug 2 16:29:18 2013 -0400 remove debugging g_print commit c017b06e9fb797a820b27a96291ddc91a3cf6033 Author: Matthew Campbell Date: Fri Aug 2 16:28:32 2013 -0400 fix code whitespace formatting commit 61a4ca5111370de2815be0e643d0ec13807e99e9 Author: Matthew Campbell Date: Fri Aug 2 16:25:04 2013 -0400 add support for move with focued window commit aac53677a432a958763f7b53ebac00e04be817f7 Author: Matthew Campbell Date: Wed Jul 31 12:53:35 2013 -0400 add TODO note for making a wrokspace sub-widget commit c4861372cf297b04f0a30b7b1c68701da68a7d70 Author: Matthew Campbell Date: Wed Jul 31 12:24:18 2013 -0400 use expose event driven for widget redrawing commit 37f13601fbef6a23f63a58a323005fe30726aae3 Author: Matthew Campbell Date: Wed Jul 31 12:15:36 2013 -0400 don't draw wswinwidget until exposed commit 23e109c91b1e31475323fe53465d03baeec134e1 Author: Matthew Campbell Date: Wed Jul 31 00:25:01 2013 -0400 move several properties from wswinwidget to wswin commit 35fe2072037fa64ebed27c183053560c9cc72856 Author: Matthew Campbell Date: Tue Jul 30 17:36:58 2013 -0400 move and duplicate handle workspace event calls commit 72781e2ca1f38a0c3e713396fdc3aca2f3945ccc Author: Matthew Campbell Date: Tue Jul 30 12:27:23 2013 -0400 draw only current and previous workspace for efficency commit 20c7cc61bfdf9252f4830113a98885f7d3f322ae Author: Matthew Campbell Date: Tue Jul 30 12:05:50 2013 -0400 add support for previous worspace commit 274fe930fd69b38339fc968b95f34afaac58001f Author: Matthew Campbell Date: Tue Jul 30 00:33:59 2013 -0400 improve non-compositied drawing commit 930d413c620cfab9d99e0c19cc765d78ba04d99a Author: Matthew Campbell Date: Tue Jul 30 00:19:34 2013 -0400 remove debug print statement commit 798414e26aaceda541ef42a1f5433ce297498715 Author: Matthew Campbell Date: Tue Jul 30 00:17:04 2013 -0400 handle shortcuts without modifiers in workspace switching commit 0eaee0ae6228b960269ca390cdfb8286108dc9be Author: Matthew Campbell Date: Tue Jul 30 00:16:25 2013 -0400 fix code formatting, return type on seperate line commit a055cf6a449402a887cb19e878f4e3c347364d37 Author: Matthew Campbell Date: Mon Jul 29 22:58:02 2013 -0400 beautifiy workspace drawing in wswinwidget commit 001e8dc155dd67dbaeb2b2523bb0d742e198eb37 Author: Matthew Campbell Date: Mon Jul 29 22:57:07 2013 -0400 fix rounded worspace edge drawing commit 45983541b1765c3f77d1db88d749bfbfe484affd Author: Matthew Campbell Date: Mon Jul 29 22:56:33 2013 -0400 support non-rectangular workspace layouts commit 8ff3c424c1cd645189d3ecbc6ca8db3e6c0991ce Author: Matthew Campbell Date: Mon Jul 29 22:55:58 2013 -0400 fix first draw problem in wswinwidget commit e6c5c17cbd1956a12a4f7ca545da8bbfcb2bfcd2 Author: Matthew Campbell Date: Mon Jul 29 19:52:23 2013 -0400 make widget bigger, add curved workspaces commit 1d794641d042079ea9239e1ca9bbd0ac4081d8ea Author: Matthew Campbell Date: Mon Jul 29 19:51:55 2013 -0400 workaround not drawing first time commit 211025ce5dda8700faa3bae7ea5e3682b868a6a4 Author: Matthew Campbell Date: Mon Jul 29 18:59:18 2013 -0400 rename wswin widget to tabwin for theme compatibility commit 2e0b9a3a4c62b199b2df061765189fd97232ac0b Author: Matthew Campbell Date: Mon Jul 29 18:19:51 2013 -0400 add fancy background drawing to wswinWidget commit 7bcd02a232a7dd05eb74baba039a80738e6ed038 Author: Matthew Campbell Date: Mon Jul 29 18:05:21 2013 -0400 remove debugging g_print statements from worspacewin.c commit 90f57d59f64c597b44dbf56080433ccea894589c Author: Matthew Campbell Date: Mon Jul 29 18:01:42 2013 -0400 remove unneccariy cairo call commit 43da5d368129d47633c5e6a52e2179ccb35ebd1f Author: Matthew Campbell Date: Mon Jul 29 18:01:00 2013 -0400 add wswinSetSelcted calls to workspaces.c commit 843642e46032bc024d600e41d88c73d9dff66e01 Author: Matthew Campbell Date: Mon Jul 29 17:59:52 2013 -0400 implment wswinSetSelected function commit f4651186b425df8f8f15bfa86e6c635961ced3e5 Author: Matthew Campbell Date: Mon Jul 29 17:59:03 2013 -0400 add rows, cols, count and selected to wswinWidget struct commit 8ae2f045fd4f8f270291ae8d605d8ee7378659f1 Author: Matthew Campbell Date: Mon Jul 29 17:57:58 2013 -0400 add cairo draw function for current workspace commit 0a8308f63974fe7365d9a3fe5592c9e4c55c97b6 Author: Matthew Campbell Date: Mon Jul 29 15:30:05 2013 -0400 add workspacewin widget and have it draw commit 84d19f4eed309508ec736f5cbc0d4e37a048a729 Author: Matthew Campbell Date: Mon Jul 29 00:37:16 2013 -0400 add basic workspacewin widget commit 76ed0d2ef5c152b498f408e1136136cb91ea3de0 Author: Matthew Campbell Date: Mon Jul 29 00:15:56 2013 -0400 add worspacewin source files commit 994e35c98d9fba051b719f0047af5c47e183a144 Author: Matthew Campbell Date: Sun Jul 28 23:32:53 2013 -0400 use eventfilter for workspace switching commit a63f6f2731bcd7b403fb2a02d90c8c435b2097e3 Author: Matthew Campbell Date: Sun Jul 28 23:10:24 2013 -0400 worspace up,down,left,right use workspaceSwitchInteractive commit e111d649c9da1203cacc71a7193fb60d6268ea63 Author: Matthew Campbell Date: Sun Jul 28 23:09:38 2013 -0400 add worspaceSwitchInteractive --- src/Makefile.am | 2 + src/events.c | 20 +-- src/workspaces.c | 222 ++++++++++++++++++++++++++++++ src/workspaces.h | 3 + src/workspacewin.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/workspacewin.h | 76 ++++++++++ 6 files changed, 703 insertions(+), 18 deletions(-) create mode 100644 src/workspacewin.c create mode 100644 src/workspacewin.h diff --git a/src/Makefile.am b/src/Makefile.am index ee2fff6..47d8e0f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,6 +67,8 @@ xfwm4_SOURCES = \ wireframe.h \ workspaces.c \ workspaces.h \ + workspacewin.c \ + workspacewin.h \ xsync.c \ xsync.h \ xpm-color-table.h diff --git a/src/events.c b/src/events.c index 4b49171..b31959d 100644 --- a/src/events.c +++ b/src/events.c @@ -387,17 +387,10 @@ handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev) workspaceSwitch (screen_info, screen_info->current_ws - 1, c, TRUE, ev->time); break; case KEY_MOVE_UP_WORKSPACE: - workspaceMove (screen_info, -1, 0, c, ev->time); - break; case KEY_MOVE_DOWN_WORKSPACE: - workspaceMove (screen_info, 1, 0, c, ev->time); - break; case KEY_MOVE_LEFT_WORKSPACE: - workspaceMove (screen_info, 0, -1, c, ev->time); - break; case KEY_MOVE_RIGHT_WORKSPACE: - workspaceMove (screen_info, 0, 1, c, ev->time); - break; + workspaceSwitchInteractive (ev_screen_info, c, ev); case KEY_MOVE_WORKSPACE_1: case KEY_MOVE_WORKSPACE_2: case KEY_MOVE_WORKSPACE_3: @@ -495,20 +488,11 @@ handleKeyPress (DisplayInfo *display_info, XKeyEvent * ev) workspaceSwitch (ev_screen_info, ev_screen_info->current_ws - 1, NULL, TRUE, ev->time); break; case KEY_UP_WORKSPACE: - status = EVENT_FILTER_REMOVE; - workspaceMove(ev_screen_info, -1, 0, NULL, ev->time); - break; case KEY_DOWN_WORKSPACE: - status = EVENT_FILTER_REMOVE; - workspaceMove(ev_screen_info, 1, 0, NULL, ev->time); - break; case KEY_LEFT_WORKSPACE: - status = EVENT_FILTER_REMOVE; - workspaceMove(ev_screen_info, 0, -1, NULL, ev->time); - break; case KEY_RIGHT_WORKSPACE: status = EVENT_FILTER_REMOVE; - workspaceMove(ev_screen_info, 0, 1, NULL, ev->time); + workspaceSwitchInteractive (ev_screen_info, NULL, ev); break; case KEY_ADD_WORKSPACE: status = EVENT_FILTER_REMOVE; diff --git a/src/workspaces.c b/src/workspaces.c index f57eec9..75b6f29 100644 --- a/src/workspaces.c +++ b/src/workspaces.c @@ -40,12 +40,21 @@ #include "misc.h" #include "transients.h" #include "workspaces.h" +#include "workspacewin.h" #include "settings.h" #include "client.h" #include "focus.h" #include "stacking.h" #include "hints.h" +typedef struct _WorkspaceSwitchData WorkspaceSwitchData; +struct _WorkspaceSwitchData +{ + Wswin *wswin; + ScreenInfo *screen_info; + Client *c; +}; + static void workspaceGetPosition (ScreenInfo *screen_info, int n, int * row, int * col) { @@ -177,6 +186,218 @@ modify_with_wrap (int value, int by, int limit, gboolean wrap) return value; } +static void handle_workspace_event (ScreenInfo * screen_info, Client * c, XKeyEvent * ev) +{ + int key; + + key = myScreenGetKeyPressed (screen_info, ev); + + if(c) + { + switch(key) + { + case KEY_MOVE_UP_WORKSPACE: + workspaceMove (screen_info, -1, 0, c, ev->time); + break; + case KEY_MOVE_DOWN_WORKSPACE: + workspaceMove (screen_info, 1, 0, c, ev->time); + break; + case KEY_MOVE_LEFT_WORKSPACE: + workspaceMove (screen_info, 0, -1, c, ev->time); + break; + case KEY_MOVE_RIGHT_WORKSPACE: + workspaceMove (screen_info, 0, 1, c, ev->time); + break; + } + } + + switch(key) + { + case KEY_UP_WORKSPACE: + workspaceMove (screen_info, -1, 0, NULL, ev->time); + break; + case KEY_DOWN_WORKSPACE: + workspaceMove (screen_info, 1, 0, NULL, ev->time); + break; + case KEY_LEFT_WORKSPACE: + workspaceMove (screen_info, 0, -1, NULL, ev->time); + break; + case KEY_RIGHT_WORKSPACE: + workspaceMove (screen_info, 0, 1, NULL, ev->time); + break; + } +} + +static eventFilterStatus +workspaceSwitchFilter (XEvent * xevent, gpointer data) +{ + ScreenInfo *screen_info; + DisplayInfo *display_info; + WorkspaceSwitchData *passdata; + eventFilterStatus status; + int key, modifiers; + gboolean switching; + Client *c; + + TRACE ("entering workspaceSwitchFilter"); + + passdata = (WorkspaceSwitchData *) data; + + screen_info = passdata->screen_info; + display_info = screen_info->display_info; + modifiers = (screen_info->params->keys[KEY_MOVE_UP_WORKSPACE].modifier | + screen_info->params->keys[KEY_MOVE_DOWN_WORKSPACE].modifier | + screen_info->params->keys[KEY_MOVE_LEFT_WORKSPACE].modifier | + screen_info->params->keys[KEY_MOVE_RIGHT_WORKSPACE].modifier | + screen_info->params->keys[KEY_LEFT_WORKSPACE].modifier | + screen_info->params->keys[KEY_RIGHT_WORKSPACE].modifier | + screen_info->params->keys[KEY_UP_WORKSPACE].modifier | + screen_info->params->keys[KEY_DOWN_WORKSPACE].modifier); + status = EVENT_FILTER_STOP; + + switching = TRUE; + + /* Update the display time */ + myDisplayUpdateCurrentTime (display_info, xevent); + + switch (xevent->type) + { + case KeyPress: + key = myScreenGetKeyPressed (screen_info, (XKeyEvent *) xevent); + c = clientGetFocus (); + if (c) + { + if (key == KEY_MOVE_UP_WORKSPACE | + key == KEY_MOVE_DOWN_WORKSPACE | + key == KEY_MOVE_LEFT_WORKSPACE | + key == KEY_MOVE_RIGHT_WORKSPACE) + { + handle_workspace_event (screen_info, c, (XKeyEvent *) xevent); + wswinSetSelected (passdata->wswin, screen_info->current_ws); + } + } + + if (key == KEY_UP_WORKSPACE | + key == KEY_DOWN_WORKSPACE | + key == KEY_LEFT_WORKSPACE | + key == KEY_RIGHT_WORKSPACE) + { + handle_workspace_event (screen_info, NULL, (XKeyEvent *) xevent); + wswinSetSelected (passdata->wswin, screen_info->current_ws); + } + /* If last key press event didn't have our modifiers pressed, finish workspace switching */ + if (!(xevent->xkey.state & modifiers)) + { + switching = FALSE; + } + break; + case KeyRelease: + { + int keysym = XLookupKeysym (&xevent->xkey, 0); + + if (IsModifierKey(keysym)) + { + if (!(myScreenGetModifierPressed (screen_info) & modifiers)) + { + switching = FALSE; + } + } + } + break; + case ButtonPress: + case ButtonRelease: + case EnterNotify: + case MotionNotify: + break; + default: + status = EVENT_FILTER_CONTINUE; + break; + } + + if (!switching) + { + //TRACE ("event loop now finished"); + gtk_main_quit (); + } + + return status; +} + +void +workspaceSwitchInteractive (ScreenInfo * screen_info, Client * c, XKeyEvent * ev) +{ + /* TODO: add trace statements (to all code) */ + /* TODO: add support for move with current window */ + DisplayInfo *display_info; + gboolean g1, g2; + WorkspaceSwitchData passdata; + int key, modifier; + + display_info = screen_info->display_info; + + modifier = 0; + key = myScreenGetKeyPressed (screen_info, ev); + switch (key) + { + case KEY_MOVE_UP_WORKSPACE: + case KEY_MOVE_DOWN_WORKSPACE: + case KEY_MOVE_LEFT_WORKSPACE: + case KEY_MOVE_RIGHT_WORKSPACE: + case KEY_UP_WORKSPACE: + case KEY_DOWN_WORKSPACE: + case KEY_LEFT_WORKSPACE: + case KEY_RIGHT_WORKSPACE: + modifier = screen_info->params->keys[key].modifier; + } + + if (!modifier) + { + /* + * The shortcut has no modifier so there's no point in entering + * the cycle loop, and we already servied the event above + * that's it... + */ + handle_workspace_event (screen_info, c, ev); + return; + } + + g1 = myScreenGrabKeyboard (screen_info, ev->time); + g2 = myScreenGrabPointer (screen_info, LeaveWindowMask, None, ev->time); + + if (!g1 || !g2) + { + TRACE ("grab failed in workspaceSwitchInteractive"); + + gdk_beep (); + myScreenUngrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info)); + myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info)); + + return; + } + + handle_workspace_event (screen_info, c, ev); + + passdata.c = NULL; + passdata.screen_info = screen_info; + passdata.wswin = wswinCreate(screen_info); + + TRACE ("entering worspace loop"); + + eventFilterPush (display_info->xfilter, workspaceSwitchFilter, &passdata); + gtk_main (); + eventFilterPop (display_info->xfilter); + + TRACE("leaving workspace loop"); + + updateXserverTime (display_info); + + wswinDestroy (passdata.wswin); + g_free (passdata.wswin); + + myScreenUngrabKeyboard (screen_info, myDisplayGetCurrentTime (display_info)); + myScreenUngrabPointer (screen_info, myDisplayGetCurrentTime (display_info)); +} + /* returns TRUE if the workspace was changed, FALSE otherwise */ gboolean workspaceMove (ScreenInfo *screen_info, gint rowmod, gint colmod, Client * c, guint32 timestamp) @@ -567,3 +788,4 @@ workspaceUpdateArea (ScreenInfo *screen_info) clientScreenResize(screen_info, FALSE); } } + diff --git a/src/workspaces.h b/src/workspaces.h index 0087743..8861234 100644 --- a/src/workspaces.h +++ b/src/workspaces.h @@ -37,6 +37,9 @@ #include "screen.h" #include "client.h" +void workspaceSwitchInteractive (ScreenInfo *, + Client *, + XKeyEvent *); gboolean workspaceMove (ScreenInfo *, int, int, diff --git a/src/workspacewin.c b/src/workspacewin.c new file mode 100644 index 0000000..039f462 --- /dev/null +++ b/src/workspacewin.c @@ -0,0 +1,398 @@ +/* $Id$ + + 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. + + 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., Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + + xfwm4 - (c) 2002-2011 Olivier Fourdan + + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef WIN_BORDER_WIDTH +#define WIN_BORDER_WIDTH 1 +#endif + +#ifndef WIN_ALPHA +#define WIN_ALPHA 0.85 +#endif + +#ifndef WIN_BORDER_ALPHA +#define WIN_BORDER_ALPHA 0.5 +#endif + +#ifndef WIN_BORDER_RADIUS +#define WIN_BORDER_RADIUS 10 +#endif + +#include +#include +#include +#include "focus.h" +#include "workspacewin.h" + +static void wswin_widget_class_init (WswinWidgetClass *klass); + +static GType +wswin_widget_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + static const GTypeInfo info = + { + sizeof (WswinWidgetClass), + NULL, + NULL, + (GClassInitFunc) wswin_widget_class_init, + NULL, + NULL, + sizeof (WswinWidget), + 0, + NULL, + NULL, + }; + + type = g_type_register_static (GTK_TYPE_WINDOW, "Xfwm4WswinWidget", &info, 0); + } + + return type; +} + +static gboolean +wswinConfigure (WswinWidget *wsw, GdkEventConfigure *event) +{ + GtkWindow *window; + GdkRectangle monitor; + GdkScreen *screen; + gint x, y; + + g_return_val_if_fail(wsw != NULL, FALSE); + TRACE ("entering wswinConfigure"); + + if ((wsw->width == event->width) && (wsw->height == event->height)) + { + return FALSE; + } + + window = GTK_WINDOW(wsw); + screen = gtk_window_get_screen(window); + gdk_screen_get_monitor_geometry (screen, wsw->monitor_num, &monitor); + x = monitor.x + (monitor.width - event->width) / 2; + y = monitor.y + (monitor.height - event->height) / 2; + gtk_window_move (window, x, y); + + wsw->width = event->width; + wsw->height = event->height; + + return FALSE; +} + +static void +wswin_widget_class_init (WswinWidgetClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); +} + +static GdkColor * +get_color (GtkWidget *win, GtkStateType state_type) +{ + GtkStyle *style; + + g_return_val_if_fail (win != NULL, NULL); + g_return_val_if_fail (GTK_IS_WIDGET (win), NULL); + g_return_val_if_fail (GTK_WIDGET_REALIZED (win), NULL); + + style = gtk_rc_get_style (win); + if (!style) + { + style = gtk_widget_get_style (win); + } + if (!style) + { + style = gtk_widget_get_default_style (); + } + + return (&style->bg[state_type]); +} + +static void +wswinDraw (WswinWidget *wsw) +{ + GdkScreen *screen; + cairo_t *cr; + Wswin *wswin = wsw->wswin; + GdkColor *bg_normal = get_color(GTK_WIDGET (wsw), GTK_STATE_NORMAL); + GdkColor *bg_selected = get_color(GTK_WIDGET (wsw), GTK_STATE_SELECTED); + gdouble width = GTK_WIDGET(wsw)->allocation.width; + gdouble height = GTK_WIDGET(wsw)->allocation.height; + gdouble x_size = width / wswin->cols; + gdouble y_size = height / wswin->rows; + gint border_radius = WIN_BORDER_RADIUS; + gdouble border_alpha = WIN_BORDER_ALPHA; + gdouble alpha = WIN_ALPHA; + gdouble degrees = 3.14 / 180.0; + gboolean composited; + gint row, col, current; + + if (!(wsw->exposed)) + return; + + cr = gdk_cairo_create (GTK_WIDGET(wsw)->window); + if (G_UNLIKELY (cr == NULL)) + return; + + screen = gtk_widget_get_screen(GTK_WIDGET(wsw)); + composited = gdk_screen_is_composited(screen); + + cairo_set_line_width (cr, 1); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + /* TODO: use workspaces.c style workspaceGetPosition so that we respect freedestop.org's layout stuff */ + /* TODO: creawte a workspace widget for each individual workspace so that they can be redrawn individually (more efficent and modular) */ + for(row = 0; row < wswin->rows; row++) + { + for(col = 0; col < wswin->cols; col++) + { + current = (row * wswin->cols) + col; + if(current >= wswin->count) + continue; + + /* only draw if we are the current or previous work space */ + /* draw no matter what if we are not yet drawn */ + //if((wsw->undrawn == FALSE) && (current != wswin->selected) && (current != wswin->previous)) + // continue; + + /* Draw a filled rounded rectangle with an outline */ + gint top, bot, left, right; + top = row*y_size+5; + bot = (row+1)*y_size-5; + left = col*x_size+5; + right = (col+1)*x_size-5; + + cairo_arc (cr, right - border_radius - 0.5, top + border_radius + 0.5, border_radius, -90 * degrees, 0 * degrees); + cairo_arc (cr, right - border_radius - 0.5, bot - border_radius - 0.5, border_radius, 0 * degrees, 90 * degrees); + cairo_arc (cr, left + border_radius + 0.5, bot - border_radius - 0.5, border_radius, 90 * degrees, 180 * degrees); + cairo_arc (cr, left + border_radius + 0.5, top + border_radius + 0.5, border_radius, 180 * degrees, 270 * degrees); + cairo_close_path(cr); + + if(composited) + cairo_set_source_rgba (cr, bg_selected->red/65535.0, bg_selected->green/65535.0, bg_selected->blue/65535.0, border_alpha); + else + gdk_cairo_set_source_color(cr, bg_normal); + + if(current == wswin->selected) + gdk_cairo_set_source_color(cr, bg_selected); + cairo_fill_preserve (cr); + gdk_cairo_set_source_color(cr, bg_selected); + cairo_stroke (cr); + } + } + + cairo_destroy (cr); + + wsw->undrawn = FALSE; +} + +static gboolean +wswin_expose (GtkWidget *wsw, GdkEventExpose *event, gpointer data) +{ + WswinWidget *wswin; + GdkScreen *screen; + cairo_t *cr; + GdkColor *bg_normal = get_color(wsw, GTK_STATE_NORMAL); + GdkColor *bg_selected = get_color(wsw, GTK_STATE_SELECTED); + gdouble width = wsw->allocation.width; + gdouble height = wsw->allocation.height; + gdouble border_alpha = WIN_BORDER_ALPHA; + gdouble alpha = WIN_ALPHA; + gint border_radius = WIN_BORDER_RADIUS; + gdouble degrees = 3.14 / 180.0; + + screen = gtk_widget_get_screen(GTK_WIDGET(wsw)); + cr = gdk_cairo_create (wsw->window); + if (G_UNLIKELY (cr == NULL)) + return FALSE; + + wswin = (WswinWidget *) data; + + cairo_set_line_width (cr, 1); + + if (gdk_screen_is_composited(screen)) { + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + gdk_cairo_region(cr, event->region); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.0); + cairo_fill_preserve(cr); + cairo_clip(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + + /* Draw a filled rounded rectangle with an outline */ + cairo_arc (cr, width - border_radius - 0.5, border_radius + 0.5, border_radius, -90 * degrees, 0 * degrees); + cairo_arc (cr, width - border_radius - 0.5, height - border_radius - 0.5, border_radius, 0 * degrees, 90 * degrees); + cairo_arc (cr, border_radius + 0.5, height - border_radius - 0.5, border_radius, 90 * degrees, 180 * degrees); + cairo_arc (cr, border_radius + 0.5, border_radius + 0.5, border_radius, 180 * degrees, 270 * degrees); + cairo_close_path(cr); + gdk_cairo_set_source_color(cr, bg_normal); + //cairo_set_source_rgba (cr, bg_normal->red/65535.0, bg_normal->green/65535.0, bg_normal->blue/65535.0, alpha); + cairo_fill_preserve (cr); + gdk_cairo_set_source_color(cr, bg_selected); + //cairo_set_source_rgba (cr, bg_selected->red/65535.0, bg_selected->green/65535.0, bg_selected->blue/65535.0, border_alpha); + cairo_stroke (cr); + } + else{ + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_rectangle(cr, 0, 0, width, height); + gdk_cairo_set_source_color(cr, bg_normal); + cairo_fill_preserve (cr); + gdk_cairo_set_source_color(cr, bg_selected); + cairo_stroke (cr); + } + + cairo_destroy (cr); + + wswin->exposed = TRUE; + + wswinDraw(wswin); + + return FALSE; +} + +static WswinWidget * +wswinCreateWidget (Wswin *wswin, ScreenInfo *screen_info, gint monitor_num) +{ + WswinWidget *wsw; + GdkScreen *screen; + GdkRectangle monitor; + + wsw = g_object_new(wswin_widget_get_type(), "type", GTK_WINDOW_POPUP, NULL); + + wsw->width = -1; + wsw->height = -1; + wsw->monitor_num = monitor_num; + wsw->wswin = wswin; + wsw->undrawn = TRUE; + wsw->exposed = FALSE; + + gtk_window_set_screen (GTK_WINDOW (wsw), screen_info->gscr); + /* TODO: give this its own name like "xfwm4-wswin" */ + /* for now we leave it the same for compatibility with themes */ + gtk_widget_set_name (GTK_WIDGET (wsw), "xfwm4-tabwin"); + + /* Check for compositing and set colormap for it */ + screen = gtk_widget_get_screen(GTK_WIDGET(wsw)); + if(gdk_screen_is_composited(screen)) { + GdkColormap *cmap = gdk_screen_get_rgba_colormap(screen); + if(cmap) + gtk_widget_set_colormap(GTK_WIDGET(wsw), cmap); + } + + gtk_widget_realize (GTK_WIDGET (wsw)); + gtk_container_set_border_width (GTK_CONTAINER (wsw), 4); + gtk_widget_set_app_paintable(GTK_WIDGET(wsw), TRUE); + gtk_window_set_position (GTK_WINDOW (wsw), GTK_WIN_POS_NONE); + gdk_screen_get_monitor_geometry (screen_info->gscr, wsw->monitor_num, &monitor); + gtk_window_move (GTK_WINDOW(wsw), monitor.x + monitor.width / 2, + monitor.y + monitor.height / 2); + /* TODO: set the size to be a param */ + gtk_window_set_default_size(GTK_WINDOW(wsw), 64*3*(wswin->cols), 40*3*(wswin->rows)); + + g_signal_connect_swapped (wsw, "configure-event", + GTK_SIGNAL_FUNC (wswinConfigure), (gpointer) wsw); + g_signal_connect (wsw, "expose-event", GTK_SIGNAL_FUNC (wswin_expose), (gpointer) wsw); + + gtk_widget_show_all(GTK_WIDGET(wsw)); + + return wsw; +} + +void +wswinSetSelected (Wswin *wswin, gint new_ws) +{ + GList *wswin_list; + WswinWidget *wsw; + + g_return_if_fail ( wswin != NULL ); + + /* Param checking */ + if ( (wswin->selected != new_ws) && (new_ws < (wswin->count)) ) + { + wswin->previous = wswin->selected; + wswin->selected = new_ws; + } + else + return; + + for(wswin_list = wswin->wswin_list; wswin_list; wswin_list = g_list_next (wswin_list)) + { + wsw = (WswinWidget *) wswin_list->data; + if(new_ws < (wswin->count)) + { + //wswinDraw(wsw); + gtk_widget_queue_draw (GTK_WIDGET(wsw)); + } + } + +} + +Wswin * +wswinCreate (ScreenInfo *screen_info) +{ + Wswin *wswin; + int num_monitors, i; + + g_return_val_if_fail (screen_info, NULL); + + TRACE ("entering wswinCreate"); + wswin = g_new0(Wswin, 1); + wswin->wswin_list = NULL; + wswin->rows = screen_info->desktop_layout.rows; + wswin->cols = screen_info->desktop_layout.cols; + wswin->count = screen_info->workspace_count; + wswin->selected = screen_info->current_ws; + wswin->previous = wswin->selected; + num_monitors = myScreenGetNumMonitors (screen_info); + for (i = 0; i < num_monitors; i++) + { + gint monitor_index; + + monitor_index = myScreenGetMonitorIndex(screen_info, i); + wswin->wswin_list = g_list_append(wswin->wswin_list, wswinCreateWidget(wswin, screen_info, monitor_index)); + } + + return wswin; +} + +void +wswinDestroy (Wswin *w) +{ + GList *wswin_list; + WswinWidget *wsw; + + g_return_if_fail (w != NULL); + TRACE ("entering wswinDestroy"); + + g_return_if_fail (w != NULL); + for (wswin_list = w->wswin_list; wswin_list; wswin_list = g_list_next (wswin_list)) + { + wsw = (WswinWidget *) wswin_list->data; + g_list_free (wsw->widgets); + gtk_widget_destroy (GTK_WIDGET (wsw)); + } + g_list_free (w->wswin_list); +} + diff --git a/src/workspacewin.h b/src/workspacewin.h new file mode 100644 index 0000000..d4aa199 --- /dev/null +++ b/src/workspacewin.h @@ -0,0 +1,76 @@ +/* $Id$ + + 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. + + 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., Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + + xfwm4 - (c) 2002-2011 Olivier Fourdan + + */ + +#ifndef INC_WORKSPACEWIN_H +#define INC_WORKSPACEWIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "focus.h" + +typedef struct _Wswin Wswin; +typedef struct _WswinWidget WswinWidget; +typedef struct _WswinWidgetClass WswinWidgetClass; + +struct _Wswin +{ + GList *wswin_list; + gint cols; + gint rows; + gint count; + gint selected; + gint previous; +}; + +struct _WswinWidget +{ + GtkWindow __parent__; + /* The below must be freed when destroying */ + GList *widgets; + + /* these don't have to be */ + Wswin *wswin; + GtkWidget *class; + GtkWidget *label; + GtkWidget *container; + + gint width, height; + gboolean undrawn; + gboolean exposed; + gint monitor_num; +}; + +struct _WswinWidgetClass +{ + GtkWindowClass __parent__; +}; + +Wswin *wswinCreate (ScreenInfo *); +void wswinDestroy (Wswin *); +void wswinSetSelected (Wswin *, gint); + +#endif /* INC_WORKSPACEWIN_H */ -- 1.8.1.2