gtkIOStream  1.7.0
GTK+ << C++ IOStream operators for GTK+. Now with ORBing, numerical computation, audio client and more ...
Widget.H
Go to the documentation of this file.
1 /* Copyright 2000-2018 Matt Flax <flatmax@flatmax.org>
2  This file is part of GTK+ IOStream class set
3 
4  GTK+ IOStream is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  GTK+ IOStream is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You have received a copy of the GNU General Public License
15  along with GTK+ IOStream
16  */
17 #ifndef WIDGET_H_
18 #define WIDGET_H_
19 
20 #include <gtk/gtk.h>
21 #include <cairo/cairo.h>
22 #include <iostream>
23 
24 #include "DragNDrop.H"
25 #include <map>
26 
27 #define WIDGET_DRAGHIGHLIGHTSTATE_DATA "DragHighlightState"
28 
31 class Widget {
32 protected:
33  GtkWidget *widget;
34 public:
36  Widget() {
37  widget=NULL;
38  }
39 
43  Widget(GtkWidget *w) {
44  widget=w;
45  }
46 
47  virtual ~Widget() {}
48 
51  GtkWidget *ref(void) {
52  g_object_ref(widget);
53  return widget;
54  }
55 
58  void unref(void) {
59  g_object_unref(widget);
60  }
61 
65  GtkWidget* show(void) {
66  gtk_widget_show(widget);
67  return widget;
68  }
72  GtkWidget* hide(void) {
73  gtk_widget_hide(widget);
74  return widget;
75  }
76 
80  bool getVisible(void) {
81 #if GTK_MAJOR_VERSION==2
82  return GTK_WIDGET_VISIBLE(widget);
83 #else
84  return gtk_widget_get_visible(widget);
85 #endif
86  }
87 
91  GtkWidget* getWidget(void) {
92  return widget;
93  }
94 
98  bool getSensitive(void) {
99  return gtk_widget_get_sensitive(widget);
100  }
101 
105  void setSensitive(bool sens) {
106  gtk_widget_set_sensitive(widget, sens);
107  }
108 
113  void getSize(int &width, int &height) {
114 #if GTK_MAJOR_VERSION>2 // if using GTK3 or more recent, then use get_preferred_size
115  GtkRequisition requisitionMin;
116  GtkRequisition naturalRequisition;
117  gtk_widget_get_preferred_size(widget, &requisitionMin, &naturalRequisition);
118  width=requisitionMin.width;
119  height=requisitionMin.height;
120 #else
121  GtkAllocation allocation;
122  gtk_widget_get_allocation(widget, &allocation);
123  width=allocation.width;
124  height=allocation.height;
125 #endif
126  }
127 
132  virtual void setSize(int width, int height) {
133  gtk_widget_set_size_request(widget, width, height);
134  }
135 
142  void getLocationSize(int &x, int &y, int &width, int &height){
143  GtkAllocation alloc;
144  gtk_widget_get_allocation(widget, &alloc);
145  x=alloc.x;
146  y=alloc.y;
147  width=alloc.width;
148  height=alloc.height;
149  }
150 
153  void queueDraw() {
154  gtk_widget_queue_draw(widget);
155  }
156 
159  GdkWindow* getWindow() {
160  return gtk_widget_get_window(widget);
161  }
162 
163  /* Save the top most container widget to file.
164  \param fileName The target file name ending with the appropriate extension.
165  \return <0 on error.
166  */
167  /* int saveTopWindowToPNGFile(const char *fileName){
168  return saveToPNGFile(gdk_get_default_root_window(), fileName);
169  }*/
170 
171 #ifdef gdk_cairo_set_source_window
172 
176  int saveToPNGFile(const char *fileName) {
177  return saveToPNGFile(getWindow(), fileName);
178  }
179 
185  int saveToPNGFile(GdkWindow *win, const char *fileName) {
186  gint width, height;
187  getSize(width, height);
188 // gdk_drawable_get_size(win, &width, &height);
189 //#if GTK_MAJOR_VERSION>2 // if using GTK3 or more recent, then use get_preferred_size
190 // gint x_orig, y_orig;
191 // gdk_window_get_origin(win, &x_orig, &y_orig);
192 // GdkPixbuf *screenshot = gdk_pixbuf_get_from_drawable(NULL, win, NULL, x_orig, y_orig, 0, 0, width, height);
193 // cairo_surface_t *cs=gdk_cairo_surface_create_from_pixbuf(screenshot, 0, NULL);
194 //#else
195  cairo_surface_t *cs=gdk_window_create_similar_surface(win, CAIRO_CONTENT_COLOR_ALPHA, width, height);
196  cairo_t *cr=cairo_create(cs);
197  gdk_cairo_set_source_window(cr, win, 0, 0);
198  cairo_paint(cr);
199 //#endif
200  cairo_status_t res=cairo_surface_write_to_png(cs, fileName);
201 //#if GTK_MAJOR_VERSION>2 // if using GTK3 or more recent, then use get_preferred_size
202 // if (screenshot) gdk_pixbuf_unref(screenshot);
203 //#else
204  cairo_destroy(cr);
205 //#endif
206  if (cs) cairo_surface_destroy(cs); // cleanup
207  if (res!=CAIRO_STATUS_SUCCESS) {
208  if (res==CAIRO_STATUS_NO_MEMORY)
209  std::cerr<<"Widget::saveToPNGFile : memory could not be allocated for the operation"<<std::endl;
210  else if (res==CAIRO_STATUS_SURFACE_TYPE_MISMATCH)
211  std::cerr<<"Widget::saveToPNGFile : the surface does not have pixel contents"<<std::endl;
212  else if (res==CAIRO_STATUS_WRITE_ERROR)
213  std::cerr<<"Widget::saveToPNGFile : an I/O error occurs while attempting to write the file."<<std::endl;
214  return -1;
215  } else
216  return 0;
217  }
218 #endif
219 
224  void connect(const char *event, GCallback callback, gpointer data) {
225  g_signal_connect(widget, event, callback, data);
226  }
227 
233  void connectAfter(const char *event, GCallback callback, gpointer data) {
234  g_signal_connect_after(widget, event, callback, data);
235  }
236 
245  void connectExposeEventCallback(GCallback callback, void *data){
246  connectExposeEventCallback(widget, callback, data);
247  }
248 
258  void connectExposeEventCallback(GtkWidget*w, GCallback callback, void *data){
259  g_signal_connect_after(G_OBJECT(w), "expose-event", callback, data);
260  }
261 
270  void connectConfigureEventCallback(GCallback callback, void *data){
271  connectConfigureEventCallback(widget, callback, data);
272  }
273 
283  void connectConfigureEventCallback(GtkWidget* w, GCallback callback, void *data){
284  g_signal_connect_after(G_OBJECT(w), "configure-event", callback, data);
285  }
286 
287 // Drag and drop entries below
288 public:
294  gtk_drag_dest_set(getWidget(), dnd.getDestDefaults(), dnd.getTargetArray(), dnd.size(), dnd.getDragAction());
295 /* } else {
296  w=(Widget*)userData;
297  GdkDragProtocol protocol;
298  gdk_drag_get_protocol_for_display(gtk_widget_get_display(w->getWidget()), gdknamespace::gdk_x11_drawable_get_xid(w->getWindow()), &protocol);
299  gboolean useCoordinates=true;
300  gtk_drag_dest_set_proxy(w->getWidget(), w->getWindow(), protocol, useCoordinates);
301  }*/
302 
303  gpointer userData=dnd.getUserData(); // check if we are using a different widget for user data in the callbacks.
304  if (userData==NULL)
305  userData=this;
306  // Sink signals
307  connectAfter("drag-data-received", G_CALLBACK(dragDataReceivedStatic), userData);
308  connectAfter("drag-leave", G_CALLBACK(dragLeaveStatic), userData);
309  connectAfter("drag-motion", G_CALLBACK(dragMotionStatic), userData);
310  connectAfter("drag-drop", G_CALLBACK(dragDropStatic), userData);
311  return *this;
312  }
313 
319  //if (GTK_WIDGET_NO_WINDOW(widget))
320  // std::cout<<"Can't use this widget for a drag and drop source as it has no associated window."<<std::endl;
321  gtk_drag_source_set(getWidget(), dnd.getModifierType(), dnd.getTargetArray(), dnd.size(), dnd.getDragAction());
322  gpointer userData=dnd.getUserData(); // check if we are using a different widget for user data in the callbacks.
323  if (userData==NULL)
324  userData=this;
325  // Source signals
326  connectAfter("drag-data-get", G_CALLBACK(dragDataGetStatic), userData);
327  connectAfter("drag-data-delete", G_CALLBACK(dragDataDeleteStatic), userData);
328  connectAfter("drag-begin", G_CALLBACK(dragBeginStatic), userData);
329  connectAfter("drag-end", G_CALLBACK(dragEndStatic), userData);
330  return *this;
331  }
332 
333 private:
334  // below are the drag and drop sink (destination) methods
346  static void dragDataReceivedStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, GtkSelectionData *selectionData, guint info, guint time, gpointer data) {
347  //std::cout<<"Widget::dragDataReceivedStatic "<<w<<'\t'<<data<<std::endl;
348  bool success=false;
349 
350  /* To come ... answer the modtion events requests to know if the data will be accepted or not in advance of dropping
351  PrivateData *private_data = GET_PRIVATE_DATA (w);
352  if (private_data->suggested_action){ // is this a request to check validity from dragMotionStatic ?
353  private_data->suggested_action = 0;
354  success=checkDropValidity(info, gtk_selection_data_get_data(selectionData);
355  if (!success) // not ok to drop
356  gdk_drag_status(dragContext, 0, time);
357  else
358  gdk_drag_status(dragContext, gdk_drag_context_get_suggested_action(dragContext), time);
359  return;
360  }
361  */
362 
363  // not a validity check, so a physical drop ...
364  bool deleteSelectionData=false;
365  if((selectionData != NULL) && (gtk_selection_data_get_length(selectionData) >= 0)) {
366  if (gdk_drag_context_get_suggested_action(dragContext) == GDK_ACTION_ASK) {
367  // currently not implemented
368  // Ask the user to move or copy, then set the context action.
369  }
370  bool deleteSelectionData=false; // work out whether to copy or move.
371  if (gdk_drag_context_get_suggested_action(dragContext) == GDK_ACTION_COPY)
372  ;
373  else if (gdk_drag_context_get_suggested_action(dragContext) == GDK_ACTION_MOVE)
374  deleteSelectionData=true;
375  // execute the user's overloaded virtual method
376  success=static_cast<Widget*>(data)->dragDataReceived(w, gtk_drag_get_source_widget(dragContext), info, gtk_selection_data_get_data(selectionData), gtk_selection_data_get_length(selectionData));
377  }
378  gtk_drag_finish(dragContext, success, deleteSelectionData, time);
379  }
380 
388  static void dragLeaveStatic(GtkWidget *w, GdkDragContext *dragContext, guint time, gpointer data) {
389  //std::cout<<"Widget::dragLeaveStatic"<<std::endl;
390  static_cast<Widget*>(data)->dragUnhighlight(w); // execute the un highlighting
391  static_cast<Widget*>(data)->dragLeave(w, gtk_drag_get_source_widget(dragContext));
392  }
393 
397  virtual void dragUnhighlight(GtkWidget *w){
398  if (g_object_get_data(G_OBJECT(w), WIDGET_DRAGHIGHLIGHTSTATE_DATA)){ // if the widget is highlit, then un highlight
399  g_object_set_data(G_OBJECT(w), WIDGET_DRAGHIGHLIGHTSTATE_DATA, 0); // store the highlight state in the object
400  gtk_drag_unhighlight(w);
401  }
402  }
403 
413  static gboolean dragMotionStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, guint time, gpointer data) {
414  static_cast<Widget*>(data)->dragHighlight(w); // execute the highlighting
415  /* To come ... more intricate tests requesting validation from the "drag-data-received" signal (dragDataReceivedStatic)
416  GdkAtom target = gtk_drag_dest_find_target(widget, dragContext, NULL);
417  if (target == GDK_NONE)
418  gdk_drag_status (dragContext, 0, time);
419  else {
420  private_data->pending_status = dragContext->suggested_action;
421  gtk_drag_get_data(w, dragContext, target, time);
422  }
423  */
424 
425  bool success=static_cast<Widget*>(data)->dragMotion(w, gtk_drag_get_source_widget(dragContext), x, y);
426 
427  return success;
428  }
429 
433  virtual void dragHighlight(GtkWidget *w){
434  if (!g_object_get_data(G_OBJECT(w), WIDGET_DRAGHIGHLIGHTSTATE_DATA)){ // if not highlit, highlight
435  g_object_set_data (G_OBJECT(w), WIDGET_DRAGHIGHLIGHTSTATE_DATA, (gpointer)1); // store the highlight state in the object
436  gtk_drag_highlight (w);
437  }
438  }
439 
450  static bool dragDropStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, guint time, gpointer data) {
451  //std::cout<<"Widget::dragDropStatic"<<std::endl;
452  // Check to see if (x,y) is a valid drop site within widget
453  gboolean validDropSite = static_cast<Widget*>(data)->dragMotion(w, gtk_drag_get_source_widget(dragContext), x, y);
454  if (validDropSite)
455  if (gdk_drag_context_list_targets(dragContext)) { // If the source offers a target
456  // Choose the best target type
457  DragNDrop dnd(dragContext); // construct a DragNDrop class to hold all of the target types.
458  int whichTarget=static_cast<Widget*>(data)->chooseTheTargetToUse(w, gtk_drag_get_source_widget(dragContext), dnd);
459  std::cout<<"whichTarget "<<whichTarget<<std::endl;
460  if (whichTarget<0)
461  validDropSite = FALSE;
462  else {
463  GdkAtom targetType = GDK_POINTER_TO_ATOM(g_list_nth_data(gdk_drag_context_list_targets(dragContext), whichTarget));
464  // Request the data from the source. This triggers the received signal/execution
465  // the widget (w) will receive the 'drag-data-received' signal, which executes dragDataReceivedStatic
466  gtk_drag_get_data(w, dragContext, targetType, time);
467  }
468  } else // No target offered by source => error
469  validDropSite = FALSE;
470  return validDropSite;
471  }
472 
473  // below are the drag and drop source methods
474 
484  static void dragDataGetStatic(GtkWidget *w, GdkDragContext *dragContext, GtkSelectionData *selectionData, guint info, guint time, gpointer data) {
485  //std::cout<<"Widget::dragDataGetStatic"<<std::endl;
486  g_assert (selectionData != NULL);
487  static_cast<Widget*>(data)->dragDataGet(w, selectionData, info);
488  }
489 
495  static void dragDataDeleteStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data) {
496  //std::cout<<"Widget::dragDataDeleteStatic"<<std::endl;
497  static_cast<Widget*>(data)->dragDataDelete(w);
498  }
499 
506  static void dragBeginStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data) {
507  //std::cout<<"Widget::dragBeginStatic"<<std::endl;
508  static_cast<Widget*>(data)->dragBegin(w);
509  }
510 
517  static void dragEndStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data) {
518  //std::cout<<"Widget::dragEndStatic"<<std::endl;
519  static_cast<Widget*>(data)->dragEnd(w);
520  }
521 
522 protected:
523  // below are the drag and drop sink (destination) methods
530  virtual bool checkDropValidity(GtkWidget *w, GtkWidget *sourceWidget, int info, const unsigned char *selectionStoredData) {
531  //std::cout<<"Widget::checkDropValidity not overloaded"<<std::endl;
532  return false;
533  }
534 
542  virtual bool dragDataReceived(GtkWidget *w, GtkWidget *sourceWidget, int info, const unsigned char *selectionStoredData, int length) {
543  //std::cout<<"Widget::dragDataReceived not overloaded"<<std::endl;
544  return false;
545  }
546 
551  virtual void dragLeave(GtkWidget *w, GtkWidget *sourceWidget) {
552  //std::cout<<"Widget::dragLeave not overloaded"<<std::endl;
553  }
554 
562  virtual bool dragMotion(GtkWidget *w, GtkWidget *sourceWidget, int x, int y) {
563  //std::cout<<"Widget::dragMotion not overloaded, returning true to indicate ok"<<std::endl;
564  return true;
565  }
566 
582  virtual int chooseTheTargetToUse(GtkWidget *w, GtkWidget *sourceWidget, DragNDrop &dnd){
583  if (dnd.size()==0) // if there are no known targets, report error.
585  if (dnd.size()==1) // There can be only one
586  return 0;
587  std::cout<<"Widget::chooseTheTargetToUse not overloaded, handling the empty and single target case"<<std::endl;
589  }
590 
591  // below are the drag and drop source methods
592 
605  virtual void dragDataGet(GtkWidget *w, GtkSelectionData *selectionData, guint info) {
606  std::cout<<"Widget::dragDataGet not overloaded, this is where you load in the data for sending"<<std::endl;
607  }
608 
613  virtual void dragDataDelete(GtkWidget *w) {
614  //std::cout<<"Widget::dragDataDelete not overloaded"<<std::endl;
615  }
616 
621  virtual void dragBegin(GtkWidget *w) {
622  //std::cout<<"Widget::dragBegin not overloaded"<<std::endl;
623  }
624 
629  virtual void dragEnd(GtkWidget *w) {
630  //std::cout<<"Widget::dragEnd not overloaded"<<std::endl;
631  }
632 };
633 #endif // WIDGET_H_
virtual bool checkDropValidity(GtkWidget *w, GtkWidget *sourceWidget, int info, const unsigned char *selectionStoredData)
Definition: Widget.H:530
#define DND_WHICHTARGET_ERROR
Definition: DragNDrop.H:25
void setSensitive(bool sens)
Definition: Widget.H:105
void getModifierType(GdkModifierType modifierTypeIn)
Definition: DragNDrop.H:233
float * x
static gboolean dragMotionStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, guint time, gpointer data)
Definition: Widget.H:413
static void dragBeginStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data)
Definition: Widget.H:506
virtual void dragEnd(GtkWidget *w)
Definition: Widget.H:629
GtkDestDefaults getDestDefaults()
Definition: DragNDrop.H:162
Widget & operator>>(DragNDrop &dnd)
Definition: Widget.H:318
#define DND_EMPTY_ERROR
Definition: DragNDrop.H:24
virtual int evaluateError(int errorNum)
Definition: Debug.H:132
virtual bool dragMotion(GtkWidget *w, GtkWidget *sourceWidget, int x, int y)
Definition: Widget.H:562
virtual void dragDataDelete(GtkWidget *w)
Definition: Widget.H:613
static void dragDataDeleteStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data)
Definition: Widget.H:495
GdkWindow * getWindow()
Definition: Widget.H:159
bool getVisible(void)
Definition: Widget.H:80
void connectConfigureEventCallback(GCallback callback, void *data)
Definition: Widget.H:270
virtual ~Widget()
Destructor.
Definition: Widget.H:47
void connectConfigureEventCallback(GtkWidget *w, GCallback callback, void *data)
Definition: Widget.H:283
void connectExposeEventCallback(GCallback callback, void *data)
Definition: Widget.H:245
virtual void dragHighlight(GtkWidget *w)
Definition: Widget.H:433
virtual void dragLeave(GtkWidget *w, GtkWidget *sourceWidget)
Definition: Widget.H:551
static void dragDataGetStatic(GtkWidget *w, GdkDragContext *dragContext, GtkSelectionData *selectionData, guint info, guint time, gpointer data)
Definition: Widget.H:484
virtual void dragBegin(GtkWidget *w)
Definition: Widget.H:621
static bool dragDropStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, guint time, gpointer data)
Definition: Widget.H:450
void connectExposeEventCallback(GtkWidget *w, GCallback callback, void *data)
Definition: Widget.H:258
virtual void dragDataGet(GtkWidget *w, GtkSelectionData *selectionData, guint info)
Definition: Widget.H:605
void getSize(int &width, int &height)
Definition: Widget.H:113
GtkWidget * show(void)
Definition: Widget.H:65
static void dragEndStatic(GtkWidget *w, GdkDragContext *dragContext, gpointer data)
Definition: Widget.H:517
virtual bool dragDataReceived(GtkWidget *w, GtkWidget *sourceWidget, int info, const unsigned char *selectionStoredData, int length)
Definition: Widget.H:542
Widget & operator<<(DragNDrop &dnd)
Definition: Widget.H:293
gpointer getUserData()
Definition: DragNDrop.H:138
virtual void setSize(int width, int height)
Definition: Widget.H:132
GtkWidget * widget
The container based widget.
Definition: Widget.H:33
GtkWidget * getWidget(void)
Definition: Widget.H:91
float * y
GtkWidget * ref(void)
Definition: Widget.H:51
Definition: Widget.H:31
Widget(GtkWidget *w)
Definition: Widget.H:43
GtkWidget * hide(void)
Definition: Widget.H:72
static void dragDataReceivedStatic(GtkWidget *w, GdkDragContext *dragContext, gint x, gint y, GtkSelectionData *selectionData, guint info, guint time, gpointer data)
Definition: Widget.H:346
#define WIDGET_DRAGHIGHLIGHTSTATE_DATA
Definition: Widget.H:27
GdkDragAction getDragAction()
Definition: DragNDrop.H:188
static void dragLeaveStatic(GtkWidget *w, GdkDragContext *dragContext, guint time, gpointer data)
Definition: Widget.H:388
Widget()
Construcotr.
Definition: Widget.H:36
bool getSensitive(void)
Definition: Widget.H:98
GtkTargetEntry * getTargetArray()
Definition: DragNDrop.H:246
void connectAfter(const char *event, GCallback callback, gpointer data)
Definition: Widget.H:233
virtual void dragUnhighlight(GtkWidget *w)
Definition: Widget.H:397
virtual int chooseTheTargetToUse(GtkWidget *w, GtkWidget *sourceWidget, DragNDrop &dnd)
Definition: Widget.H:582
void getLocationSize(int &x, int &y, int &width, int &height)
Definition: Widget.H:142
void unref(void)
Definition: Widget.H:58
void queueDraw()
Definition: Widget.H:153
void connect(const char *event, GCallback callback, gpointer data)
Definition: Widget.H:224
gtkIOStream: /tmp/gtkiostream/include/Widget.H Source File
GTK+ IOStream  Beta