/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** program: ** input_shape_test ** ** created: ** 19.2.2006 ** ** last change: ** 20.2.2006 ** ** author: ** Mirco "MacSlow" Mueller ** ** license: ** GPL ** ** notes: ** - this is a test I did to figure out how to use input-shapes (XShape 1.1) ** - opens a decoration-less and transparent gtk+-window and draws a red ** cross with a circle around it ** - only the parts drawn will be "draggable" ** - window can be dragged around with LMB-drag ** - window can be resized with MMB-drag (the input-shape also resizes!) ** - window can be exited with ESC or q ** - needs a compositing manager to run in order to look as intended ** - tested with xcompmgr and compiz ** - tested with gtk+-2.8.11 and gtk+-2.9.0 (CVS-head) ** ** bugs: ** - there are no size-checks done for the input-shape, so I don't know what ** will happen, if you make the window super large ** ** todo: ** - nothing ** ** compile with: ** gcc `pkg-config --cflags --libs gtk+-2.0` input_shape_test.c -o input_shape_test ** *******************************************************************************/ #include #include #include #if !GTK_CHECK_VERSION(2,9,0) #include #include #include #endif #define WIN_WIDTH 300 #define WIN_HEIGHT 300 gint g_iCurrentWidth = WIN_WIDTH; gint g_iCurrentHeight = WIN_HEIGHT; void update_input_shape (GtkWidget* pWindow, int iWidth, int iHeight); void on_alpha_screen_changed (GtkWidget* pWidget, GdkScreen* pOldScreen, GtkWidget* pLabel); void render (cairo_t* pCairoContext, gint iWidth, gint iHeight); gboolean on_expose (GtkWidget* pWidget, GdkEventExpose* pExpose); gboolean on_key_press (GtkWidget* pWidget, GdkEventKey* pKey, gpointer userData); gboolean on_button_press (GtkWidget* pWidget, GdkEventButton* pButton, GdkWindowEdge edge); gboolean on_configure (GtkWidget* pWidget, GdkEventConfigure* pEvent, gpointer data); #if !GTK_CHECK_VERSION(2,9,0) void do_shape_combine_mask (GdkWindow* window, GdkBitmap* mask, gint x, gint y); #endif void update_input_shape (GtkWidget* pWindow, int iWidth, int iHeight); void on_alpha_screen_changed (GtkWidget* pWidget, GdkScreen* pOldScreen, GtkWidget* pLabel) { GdkScreen* pScreen = gtk_widget_get_screen (pWidget); GdkColormap* pColormap = gdk_screen_get_rgba_colormap (pScreen); if (!pColormap) pColormap = gdk_screen_get_rgb_colormap (pScreen); gtk_widget_set_colormap (pWidget, pColormap); } void render (cairo_t* pCairoContext, gint iWidth, gint iHeight) { cairo_scale (pCairoContext, (double) iWidth, (double) iHeight); cairo_set_source_rgba (pCairoContext, 1.0f, 1.0f, 1.0f, 0.0f); cairo_set_operator (pCairoContext, CAIRO_OPERATOR_SOURCE); cairo_paint (pCairoContext); cairo_set_source_rgba (pCairoContext, 1.0f, 0.0f, 0.0f, 0.75f); cairo_set_line_width (pCairoContext, 0.1f); cairo_move_to (pCairoContext, 0.15f, 0.15f); cairo_line_to (pCairoContext, 0.85f, 0.85f); cairo_move_to (pCairoContext, 0.85f, 0.15f); cairo_line_to (pCairoContext, 0.15f, 0.85f); cairo_stroke (pCairoContext); cairo_arc (pCairoContext, 0.5f, 0.5f, 0.45f, 0.0f, M_PI/180.0f * 360.0f); cairo_stroke (pCairoContext); } gboolean on_expose (GtkWidget* pWidget, GdkEventExpose* pExpose) { gint iWidth; gint iHeight; cairo_t* pCairoContext = NULL; pCairoContext = gdk_cairo_create (pWidget->window); if (!pCairoContext) return FALSE; gtk_window_get_size (GTK_WINDOW (pWidget), &iWidth, &iHeight); render (pCairoContext, iWidth, iHeight); cairo_destroy (pCairoContext); return FALSE; } gboolean on_configure (GtkWidget* pWidget, GdkEventConfigure* pEvent, gpointer userData) { gint iNewWidth = pEvent->width; gint iNewHeight = pEvent->height; if (iNewWidth != g_iCurrentWidth || iNewHeight != g_iCurrentHeight) { update_input_shape (pWidget, iNewWidth, iNewHeight); g_iCurrentWidth = iNewWidth; g_iCurrentHeight = iNewHeight; } return FALSE; } gboolean on_key_press (GtkWidget* pWidget, GdkEventKey* pKey, gpointer userData) { gint iWidth; gint iHeight; if (pKey->type == GDK_KEY_PRESS) { switch (pKey->keyval) { case GDK_Escape : case GDK_q : gtk_main_quit (); break; } } return FALSE; } gboolean on_button_press (GtkWidget* pWidget, GdkEventButton* pButton, GdkWindowEdge edge) { if (pButton->type == GDK_BUTTON_PRESS) { if (pButton->button == 1) gtk_window_begin_move_drag (GTK_WINDOW (gtk_widget_get_toplevel (pWidget)), pButton->button, pButton->x_root, pButton->y_root, pButton->time); if (pButton->button == 2) gtk_window_begin_resize_drag (GTK_WINDOW (gtk_widget_get_toplevel (pWidget)), edge, pButton->button, pButton->x_root, pButton->y_root, pButton->time); } return FALSE; } #if !GTK_CHECK_VERSION(2,9,0) /* this is piece by piece taken from gtk+ 2.9.0 (CVS-head with a patch applied regarding XShape's input-masks) so people without gtk+ >= 2.9.0 can compile and run input_shape_test.c */ void do_shape_combine_mask (GdkWindow* window, GdkBitmap* mask, gint x, gint y) { Pixmap pixmap; int ignore; int maj; int min; if (!XShapeQueryExtension (GDK_WINDOW_XDISPLAY (window), &ignore, &ignore)) return; if (!XShapeQueryVersion (GDK_WINDOW_XDISPLAY (window), &maj, &min)) return; /* for shaped input we need at least XShape 1.1 */ if (maj != 1 && min < 1) return; if (mask) pixmap = GDK_DRAWABLE_XID (mask); else { x = 0; y = 0; pixmap = None; } XShapeCombineMask (GDK_WINDOW_XDISPLAY (window), GDK_DRAWABLE_XID (window), ShapeInput, x, y, pixmap, ShapeSet); } #endif void update_input_shape (GtkWidget* pWindow, int iWidth, int iHeight) { static GdkBitmap* pShapeBitmap = NULL; static cairo_t* pCairoContext = NULL; pShapeBitmap = (GdkBitmap*) gdk_pixmap_new (NULL, iWidth, iHeight, 1); if (pShapeBitmap) { pCairoContext = gdk_cairo_create (pShapeBitmap); if (cairo_status (pCairoContext) == CAIRO_STATUS_SUCCESS) { render (pCairoContext, iWidth, iHeight); cairo_destroy (pCairoContext); #if !GTK_CHECK_VERSION(2,9,0) do_shape_combine_mask (pWindow->window, NULL, 0, 0); do_shape_combine_mask (pWindow->window, pShapeBitmap, 0, 0); #else gtk_widget_input_shape_combine_mask (pWindow, NULL, 0, 0); gtk_widget_input_shape_combine_mask (pWindow, pShapeBitmap, 0, 0); #endif } g_object_unref ((gpointer) pShapeBitmap); } } int main (int argc, char** argv) { GtkWidget* pWindow = NULL; GdkBitmap* pShapeMaskBitmap = NULL; gtk_init (&argc, &argv); pWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); on_alpha_screen_changed (pWindow, NULL, NULL); gtk_widget_set_app_paintable (pWindow, TRUE); gtk_window_set_decorated (GTK_WINDOW (pWindow), FALSE); gtk_window_set_resizable (GTK_WINDOW (pWindow), TRUE); gtk_window_set_title (GTK_WINDOW (pWindow), "gtk+/XShape 1.1 test"); gtk_widget_set_size_request (pWindow, g_iCurrentWidth, g_iCurrentHeight); gtk_widget_add_events (pWindow, GDK_BUTTON_PRESS_MASK); gtk_widget_show (pWindow); g_signal_connect (G_OBJECT (pWindow), "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (G_OBJECT (pWindow), "expose-event", G_CALLBACK (on_expose), NULL); g_signal_connect (G_OBJECT (pWindow), "configure-event", G_CALLBACK (on_configure), NULL); g_signal_connect (G_OBJECT (pWindow), "key-press-event", G_CALLBACK (on_key_press), NULL); g_signal_connect (G_OBJECT (pWindow), "button-press-event", G_CALLBACK (on_button_press), NULL); update_input_shape (pWindow, g_iCurrentWidth, g_iCurrentHeight); gtk_main (); return 0; }