📄 gtkselection.c
字号:
{ next = tmp_list->next; if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget) { current_retrievals = g_list_remove_link (current_retrievals, tmp_list); /* structure will be freed in timeout */ g_list_free (tmp_list); } tmp_list = next; } /* Disclaim ownership of any selections */ tmp_list = current_selections; while (tmp_list) { next = tmp_list->next; selection_info = (GtkSelectionInfo *)tmp_list->data; if (selection_info->widget == widget) { gdk_selection_owner_set (NULL, selection_info->selection, GDK_CURRENT_TIME, FALSE); current_selections = g_list_remove_link (current_selections, tmp_list); g_list_free (tmp_list); g_free (selection_info); } tmp_list = next; } /* Remove all selection lists */ gtk_selection_target_list_remove (widget);}/************************************************************* * gtk_selection_convert: * Request the contents of a selection. When received, * a "selection_received" signal will be generated. * * arguments: * widget: The widget which acts as requestor * selection: Which selection to get * target: Form of information desired (e.g., STRING) * time: Time of request (usually of triggering event) * In emergency, you could use GDK_CURRENT_TIME * * results: * TRUE if requested succeeded. FALSE if we could not process * request. (e.g., there was already a request in process for * this widget). *************************************************************/gintgtk_selection_convert (GtkWidget *widget, GdkAtom selection, GdkAtom target, guint32 time){ GtkRetrievalInfo *info; GList *tmp_list; GdkWindow *owner_window; g_return_val_if_fail (widget != NULL, FALSE); if (initialize) gtk_selection_init (); if (!GTK_WIDGET_REALIZED (widget)) gtk_widget_realize (widget); /* Check to see if there are already any retrievals in progress for this widget. If we changed GDK to use the selection for the window property in which to store the retrieved information, then we could support multiple retrievals for different selections. This might be useful for DND. */ tmp_list = current_retrievals; while (tmp_list) { info = (GtkRetrievalInfo *)tmp_list->data; if (info->widget == widget) return FALSE; tmp_list = tmp_list->next; } info = g_new (GtkRetrievalInfo, 1); info->widget = widget; info->selection = selection; info->target = target; info->buffer = NULL; info->offset = -1; /* Check if this process has current owner. If so, call handler procedure directly to avoid deadlocks with INCR. */ owner_window = gdk_selection_owner_get (selection); if (owner_window != NULL) { GtkWidget *owner_widget; GtkSelectionData selection_data; selection_data.selection = selection; selection_data.target = target; selection_data.data = NULL; selection_data.length = -1; gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget); if (owner_widget != NULL) { gtk_selection_invoke_handler (owner_widget, &selection_data, time); gtk_selection_retrieval_report (info, selection_data.type, selection_data.format, selection_data.data, selection_data.length, time); g_free (selection_data.data); g_free (info); return TRUE; } } /* Otherwise, we need to go through X */ current_retrievals = g_list_append (current_retrievals, info); gdk_selection_convert (widget->window, selection, target, time); gtk_timeout_add (1000, (GtkFunction) gtk_selection_retrieval_timeout, info); return TRUE;}/************************************************************* * gtk_selection_data_set: * Store new data into a GtkSelectionData object. Should * _only_ by called from a selection handler callback. * Null terminates the stored data. * arguments: * type: the type of selection data * format: format (number of bits in a unit) * data: pointer to the data (will be copied) * length: length of the data * results: *************************************************************/void gtk_selection_data_set (GtkSelectionData *selection_data, GdkAtom type, gint format, const guchar *data, gint length){ if (selection_data->data) g_free (selection_data->data); selection_data->type = type; selection_data->format = format; if (data) { selection_data->data = g_new (guchar, length+1); memcpy (selection_data->data, data, length); selection_data->data[length] = 0; } else { g_return_if_fail (length <= 0); if (length < 0) selection_data->data = NULL; else selection_data->data = g_strdup(""); } selection_data->length = length;}/************************************************************* * gtk_selection_init: * Initialize local variables * arguments: * * results: *************************************************************/static voidgtk_selection_init (void){ gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE); gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE); gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE); gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE);}/************************************************************* * gtk_selection_clear: * Handler for "selection_clear_event" * arguments: * widget: * event: * results: *************************************************************/gintgtk_selection_clear (GtkWidget *widget, GdkEventSelection *event){ /* FIXME: there can be a problem if we change the selection via gtk_selection_owner_set after another client claims the selection, but before we get the notification event. Tk filters based on serial #'s, which aren't retained by GTK. Filtering based on time's will be inherently somewhat unreliable. */ GList *tmp_list; GtkSelectionInfo *selection_info = NULL; tmp_list = current_selections; while (tmp_list) { selection_info = (GtkSelectionInfo *)tmp_list->data; if ((selection_info->selection == event->selection) && (selection_info->widget == widget)) break; tmp_list = tmp_list->next; } if (tmp_list) { if (selection_info->time > event->time) return FALSE; /* return FALSE to indicate that * the selection was out of date, * and this clear should be ignored */ else { current_selections = g_list_remove_link (current_selections, tmp_list); g_list_free (tmp_list); g_free (selection_info); } } return TRUE;}/************************************************************* * gtk_selection_request: * Handler for "selection_request_event" * arguments: * widget: * event: * results: *************************************************************/gintgtk_selection_request (GtkWidget *widget, GdkEventSelection *event){ GtkIncrInfo *info; GList *tmp_list; guchar *mult_atoms; int i; if (initialize) gtk_selection_init (); /* Check if we own selection */ tmp_list = current_selections; while (tmp_list) { GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data; if ((selection_info->selection == event->selection) && (selection_info->widget == widget)) break; tmp_list = tmp_list->next; } if (tmp_list == NULL) return FALSE; info = g_new(GtkIncrInfo, 1); info->widget = widget; info->selection = event->selection; info->num_incrs = 0; /* Create GdkWindow structure for the requestor */ info->requestor = gdk_window_lookup (event->requestor); if (!info->requestor) info->requestor = gdk_window_foreign_new (event->requestor); /* Determine conversions we need to perform */ if (event->target == gtk_selection_atoms[MULTIPLE]) { GdkAtom type; gint format; gint length; mult_atoms = NULL; gdk_error_trap_push(); if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */ 0, GTK_SELECTION_MAX_SIZE, FALSE, &type, &format, &length, &mult_atoms)) { gdk_selection_send_notify (event->requestor, event->selection, event->target, GDK_NONE, event->time); g_free (mult_atoms); g_free (info); return TRUE; } gdk_error_trap_pop(); info->num_conversions = length / (2*sizeof (GdkAtom)); info->conversions = g_new (GtkIncrConversion, info->num_conversions); for (i=0; i<info->num_conversions; i++) { info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i]; info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1]; } } else /* only a single conversion */ { info->conversions = g_new (GtkIncrConversion, 1); info->num_conversions = 1; info->conversions[0].target = event->target; info->conversions[0].property = event->property; mult_atoms = (guchar *)info->conversions; } /* Loop through conversions and determine which of these are big enough to require doing them via INCR */ for (i=0; i<info->num_conversions; i++) { GtkSelectionData data; gint items; data.selection = event->selection; data.target = info->conversions[i].target; data.data = NULL; data.length = -1; #ifdef DEBUG_SELECTION g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)", event->selection, info->conversions[i].target, gdk_atom_name(info->conversions[i].target), event->requestor, event->property);#endif gtk_selection_invoke_handler (widget, &data, event->time); if (data.length < 0) { ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE; info->conversions[i].property = GDK_NONE; continue; } g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE); items = (data.length + data.format/8 - 1) / (data.format/8); if (data.length > GTK_SELECTION_MAX_SIZE) { /* Sending via INCR */ info->conversions[i].offset = 0; info->conversions[i].data = data; info->num_incrs++; gdk_property_change (info->requestor, info->conversions[i].property, gtk_selection_atoms[INCR], 8*sizeof (GdkAtom), GDK_PROP_MODE_REPLACE, (guchar *)&items, 1); } else { info->conversions[i].offset = -1; gdk_property_change (info->requestor, info->conversions[i].property, data.type, data.format, GDK_PROP_MODE_REPLACE, data.data, items); g_free (data.data); } } /* If we have some INCR's, we need to send the rest of the data in a callback */ if (info->num_incrs > 0) { /* FIXME: this could be dangerous if window doesn't still exist */ #ifdef DEBUG_SELECTION g_message ("Starting INCR...");#endif gdk_window_set_events (info->requestor, gdk_window_get_events (info->requestor) | GDK_PROPERTY_CHANGE_MASK); current_incrs = g_list_append (current_incrs, info); gtk_timeout_add (1000, (GtkFunction)gtk_selection_incr_timeout, info); } /* If it was a MULTIPLE request, set the property to indicate which conversions succeeded */ if (event->target == gtk_selection_atoms[MULTIPLE]) { gdk_property_change (info->requestor, event->property, GDK_SELECTION_TYPE_ATOM, 8*sizeof(GdkAtom), GDK_PROP_MODE_REPLACE, mult_atoms, 2*info->num_conversions); g_free (mult_atoms); } if (info->num_conversions == 1 && info->conversions[0].property == GDK_NONE) { /* Reject the entire conversion */ gdk_selection_send_notify (event->requestor, event->selection, event->target, GDK_NONE, event->time); } else { gdk_selection_send_notify (event->requestor, event->selection, event->target, event->property, event->time); } if (info->num_incrs == 0) { g_free (info->conversions); g_free (info); } return TRUE;}/************************************************************* * gtk_selection_incr_event: * Called whenever an PropertyNotify event occurs for an * GdkWindow with user_data == NULL. These will be notifications * that a window we are sending the selection to via the * INCR protocol has deleted a property and is ready for * more data. * * arguments: * window: the requestor window * event: the property event structure * * results: *************************************************************/gintgtk_selection_incr_event (GdkWindow *window, GdkEventProperty *event){ GList *tmp_list; GtkIncrInfo *info = NULL; gint num_bytes; guchar *buffer; int i; if (event->state != GDK_PROPERTY_DELETE) return FALSE; #ifdef DEBUG_SELECTION g_message ("PropertyDelete, property %ld", event->atom);#endif /* Now find the appropriate ongoing INCR */ tmp_list = current_incrs; while (tmp_list) { info = (GtkIncrInfo *)tmp_list->data; if (info->requestor == event->window) break; tmp_list = tmp_list->next; } if (tmp_list == NULL) return FALSE; /* Find out which target this is for */ for (i=0; i<info->num_conversions; i++) { if (info->conversions[i].property == event->atom && info->conversions[i].offset != -1) { info->idle_time = 0; if (info->conversions[i].offset == -2) /* only the last 0-length piece*/ { num_bytes = 0; buffer = NULL; } else { num_bytes = info->conversions[i].data.length -
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -