GTK/DFB中的WaitCursor

本文介绍如何在GTK+/DFB中实现WaitCursor机制,包括通过定时器更新Cursor状态、加载Cursor图片等步骤,确保在等待过程中用户体验良好。
GTK/DFB中的WaitCursor

转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>

虽然我们实现了单实例应用程序,即在应用程序第二次运行时自动激活第一个实例,并将参数传递给第一个运行实例。但如果在桌面连续点击应用程序的起动图标,会让应用程序起动过过程变得更慢,为了避免这种情况出现,有必要实现类似WaitCursor机制。GTK+-2.6/DFB中没有实现WaitCursor,新版本中好像也没有,只好自己动手了:

  • 在gdkwindow.h文件中增加两个函数:
gint gdk_window_begin_wait_cursor(GdkWindow *window); gint gdk_window_end_wait_cursor(GdkWindow *window);
  • 在_GdkWindowObject结构中增加waitcursor的信息。
struct { gint ref; gint elapsed; gint timeout_id; }wait_cursor;
  • 在gdkwindow-directfb.c中实现这两个函数,很简单,就是实现一个定时器,每隔一段时间更新一下Cursor。
gint gdk_window_begin_wait_cursor(GdkWindow *window) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); g_return_val_if_fail(private != NULL, 0); private->wait_cursor.ref++; if(private->wait_cursor.ref == 1 && update_wait_cursor(window)) { private->wait_cursor.elapsed = 0; private->wait_cursor.timeout_id = g_timeout_add(250, update_wait_cursor, window); #ifndef LINUX_I386 gdk_directfb_display->layer->EnableCursor(gdk_directfb_display->layer, 1); #endif } return private->wait_cursor.ref; } gint gdk_window_end_wait_cursor(GdkWindow *window) { GdkWindowObject *private = GDK_WINDOW_OBJECT (window); if(private == NULL || private->wait_cursor.ref <=0) { return 0; } private->wait_cursor.ref--; #ifndef LINUX_I386 gdk_directfb_display->layer->EnableCursor(gdk_directfb_display->layer, private->wait_cursor.ref != 0); #endif return private->wait_cursor.ref; } static gboolean update_wait_cursor(gpointer user_data) { GdkWindow *window = user_data; GdkWindowObject *private = GDK_WINDOW_OBJECT (window); g_return_val_if_fail(private != NULL, FALSE); int cursor_type = GDK_WAIT_BEGIN + (private->wait_cursor.elapsed)%(GDK_WAIT_END - GDK_WAIT_BEGIN + 1); GdkCursor* cursor = gdk_cursor_new_for_display (gdk_display_get_default(), cursor_type); gdk_window_set_cursor(window, cursor); gdk_cursor_unref(cursor); private->wait_cursor.elapsed++; if(private->wait_cursor.ref <= 0) { private->wait_cursor.elapsed = 0; private->wait_cursor.timeout_id = 0; gdk_window_set_cursor(window, NULL); } return private->wait_cursor.ref > 0; }
在gdkcursor-directfb.c中加载Cursor图片,Cursor图片与主题关联:
static GdkCursor * gdk_cursor_load_wait_cursor(GdkDisplay *display, GdkCursorType cursor_type) { GdkCursor* cursor = NULL; if(cursor_type >= GDK_WAIT_BEGIN && cursor_type <= GDK_WAIT_END) { int index = 0; GValue value = {0}; char* theme = NULL; char filename[260] = {0}; GObject* setting = g_object_get_data (G_OBJECT (gdk_screen_get_default()), "gtk-settings"); g_return_val_if_fail(setting != NULL, NULL); g_value_init(&value, G_TYPE_STRING); g_object_get_property (setting, "gtk-icon-theme-name", &value); theme = g_value_get_string(&value); index = cursor_type-GDK_WAIT_BEGIN + 1; snprintf(filename, sizeof(filename), WAITCURSOR, theme, index); if((cursor = gdk_cursor_new_from_name(display, filename)) == NULL) { snprintf(filename, sizeof(filename), WAITCURSOR, "hicolor", index); cursor = gdk_cursor_new_from_name(display, filename); g_debug("load %p %s", cursor, filename); } g_value_reset(&value); } return cursor; }
  • 要注意的是gdk_cursor_new_from_pixbuf有点问题,pixbuf中的格式居然是GBRA而不是代码中要求的ARGB,要修改一下这个函数,否则无法实现透明效果。

  • 为了避免enable/disable时闪现一下传统的cursor,修改gdk_cursor_new_for_display,让alpha=0,让传统cursor全透明。
  • 出现WaitCursor时,丢弃按键和笔点事件,修改gdk_event_translate:
if(private->wait_cursor.ref > 0) { switch (dfbevent->type) { case DWET_BUTTONDOWN: case DWET_BUTTONUP: case DWET_MOTION: case DWET_KEYDOWN: case DWET_KEYUP: return NULL; default:break; } }
在手机上和PC上有点不问,手机上平时不能显示cursor,而且waitcursor的位置要居中,所以还要修改DirectFB:

  • 在dfb_layer_context_create_window中禁止cursor,把以前的dfb_windowstack_cursor_enable(core, stack, true )改为dfb_windowstack_cursor_enable( core, stack, false )
  • 在wm_update_cursor里让位置居中:

#ifndef LINUX_I386 if(context->stack->cursor.enabled && (flags & CCUF_POSITION)) { stack->cursor.hot.x = stack->cursor.x - (context->width/2 - stack->cursor.size.w); stack->cursor.hot.y = stack->cursor.y - (context->height/2 - stack->cursor.size.h); } #endif
测试了一下,基本功能正常。

~~end~~













TJA1044GTK/3Z 是恩智浦(NXP)公司推出的一款用于控制器局域网(CAN)的高速收发器。 ### 产品介绍 TJA1044GTK/3Z 是一款 CAN 收发器,为 CAN 协议控制器和物理总线之间提供了接口。它主要用于汽车和工业等领域的 CAN 网络通信,能在恶劣的电气环境中可靠地工作,支持高速 CAN 通信速率,可满足汽车电子系统中诸如发动机控制、车身电子等对实时性和可靠性要求较高的应用场景。 ### 使用方法 通常,TJA1044GTK/3Z 需要与 CAN 协议控制器(如微控制器中的 CAN 模块)配合使用。CAN 协议控制器负责处理 CAN 通信的协议层功能,而 TJA1044GTK/3Z 则负责将控制器输出的数字信号转换为适合在 CAN 总线上传输的差分信号,以及将总线上的差分信号转换为数字信号供控制器处理。在实际应用中,需要将 TJA1044GTK/3Z 的相应引脚与 CAN 协议控制器的引脚正确连接,同时要注意电源、接地等的合理布局,以保证其正常工作。 ### 技术参数 - **工作电压**:一般工作在 5V 电源电压下。 - **通信速率**:支持高达 1Mbps 的高速 CAN 通信速率。 - **温度范围**:具有较宽的工作温度范围,可适应汽车和工业等不同应用场景的温度要求,通常能在 -40°C 到 125°C 的温度环境下正常工作。 - **电磁兼容性(EMC)**:具备良好的 EMC 性能,能有效减少电磁干扰,提高系统的可靠性和稳定性。 以下是一个简单的代码示例(基于 Arduino 和 MCP2515 CAN 控制器),展示如何使用 CAN 收发器(假设使用 TJA1044GTK/3Z 作为收发器)进行 CAN 通信: ```cpp #include <SPI.h> #include <mcp2515.h> // 定义 MCP2515 的 CS 引脚 #define CAN_CS_PIN 10 // 创建 MCP2515 对象 MCP2515 mcp2515(CAN_CS_PIN); void setup() { // 初始化串口通信 Serial.begin(9600); // 初始化 SPI 通信 SPI.begin(); // 初始化 MCP2515 mcp2515.reset(); mcp2515.setBitrate(CAN_500KBPS, MCP_16MHZ); mcp2515.setNormalMode(); } void loop() { CANMessage message; // 发送 CAN 消息 message.id = 0x123; message.length = 2; message.data[0] = 0xAA; message.data[1] = 0x55; mcp2515.sendMessage(&message); // 接收 CAN 消息 if (mcp2515.readMessage(&message) == MCP2515::ERROR_OK) { Serial.print("Received CAN message with ID: 0x"); Serial.println(message.id, HEX); Serial.print("Message length: "); Serial.println(message.length); for (int i = 0; i < message.length; i++) { Serial.print("Data byte "); Serial.print(i); Serial.print(": 0x"); Serial.println(message.data[i], HEX); } } delay(1000); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值